web-dev-qa-db-fra.com

Mapper une plage numérique sur une autre

Les mathématiques n'ont jamais été mon fort à l'école :(

int input_start = 0; // The lowest number of the range input.
int input_end = 254; // The lowest number of the range input.
int output_start = 500; // The lowest number of the range output.
int output_end = 5500; // The largest number of the range ouput.

int input = 127; // Input value.
int output = 0;

Comment puis-je convertir la valeur d'entrée en la valeur de sortie correspondante de cette plage?

Par exemple, une valeur d'entrée de "0" équivaudrait à une valeur de sortie de "500", une valeur d'entrée de "254" serait égale à une valeur de sortie de "5500". Je ne peux pas comprendre comment calculer une valeur de sortie si une valeur d'entrée est disons 50 ou 101.

Je suis sûr que c'est simple, je ne peux pas penser en ce moment :)

Edit: j'ai juste besoin de nombres entiers, pas de fractions ou quoi que ce soit.

55
Joe

Oublions les mathématiques et essayons de résoudre cela intuitivement.

Tout d'abord, si nous voulons mapper les numéros d'entrée dans la plage [0, x] à la plage de sortie [0, y], nous avons juste besoin de l'échelle d'un montant approprié. 0 va à 0, x va à y, et un nombre t ira à (y/x)*t.

Donc, réduisons votre problème au problème plus simple ci-dessus.

Une plage d'entrée de [input_start, input_end] A input_end - input_start + 1 Nombres. C'est donc l'équivalent d'une plage de [0, r], où r = input_end - input_start.

De même, la plage de sortie est équivalente à [0, R], où R = output_end - output_start.

Une entrée de input équivaut à x = input - input_start. Cela, du premier paragraphe se traduira par y = (R/r)*x. Ensuite, nous pouvons traduire la valeur y dans la plage de sortie d'origine en ajoutant output_start: output = output_start + y.

Cela nous donne:

output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start)

Ou, d'une autre manière:

/* Note, "slope" below is a constant for given numbers, so if you are calculating
   a lot of output values, it makes sense to calculate it once.  It also makes
   understanding the code easier */
slope = (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)

Maintenant, étant C et la division en C tronquée, vous devriez essayer d'obtenir une réponse plus précise en calculant les choses en virgule flottante:

double slope = 1.0 * (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)

Si vous voulez être encore plus correct, vous feriez un arrondi au lieu de la troncature à l'étape finale. Vous pouvez le faire en écrivant une simple fonction round:

#include <math.h>
double round(double d)
{
    return floor(d + 0.5);
}

Ensuite:

output = output_start + round(slope * (input - input_start))
97
Alok Singhal

Arduino a ce intégré comme carte .

Exemple:

/* Map an analog value to 8 bits (0 to 255) */
void setup() {}

void loop()
{
  int val = analogRead(0);
  val = map(val, 0, 1023, 0, 255);
  analogWrite(9, val);
}

Il a également l'implémentation sur cette page:

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
22
Dustin

Le point crucial ici est de faire la division entière (qui inclut l'arrondi) au bon endroit. Jusqu'à présent, aucune des réponses n'a donné les bonnes parenthèses. Voici la bonne façon:

int input_range = input_end - input_start;
int output_range = output_end - output_start;

output = (input - input_start)*output_range / input_range + output_start;
11
Sven Marnach

la formule est

f (x) = (x - start_start)/(input_end - input_start) * (output_end - output_start) + output_start

Je vais brancher ce post ici: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/ car cela m'a beaucoup aidé en essayant de trouver cela intuitivement . Une fois que vous avez compris ce que dit le message, il est trivial de trouver ces formules par vous-même. Notez que j'avais aussi du mal avec de telles questions. (Je n'ai aucune affiliation - je l'ai trouvé très utile)

disons que vous avez la plage [input_start..input_end], commençons par la normaliser de telle sorte que 0 soit input_start et 1 soit input_end. il s'agit d'une technique simple pour faciliter le problème.

comment fait-on cela? nous allons devoir changer tout ce qui reste par input_start, de telle sorte que si l'entrée x se trouve être input_start, elle devrait donner zéro.

alors, disons que f(x) est la fonction qui effectue la conversion.

f(x) = x - input_start

essayons:

f(input_start) = input_start - input_start = 0

fonctionne pour input_start.

à ce stade, cela ne fonctionne pas encore pour input_end, car nous ne l'avons pas mis à l'échelle.

disons simplement la réduire de la longueur de la plage, puis nous aurons la plus grande valeur (input_end) mappée à une.

f(x) = (x - input_start) / (input_end - input_start)

ok, essayons avec input_end.

f (input_end) = (input_end - input_start) / (input_end - input_start) = 1

génial, semble fonctionner.

ok, prochaine étape, nous allons le mettre à l'échelle pour la plage de sortie. C'est aussi trivial que de simplement multiplier par la longueur réelle de la plage de sortie, en tant que telle:

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)

maintenant, en fait, nous avons presque terminé, il nous suffit de le déplacer vers la droite pour que 0 commence à partir de output_start.

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

essayons rapidement.

f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

vous voyez que la première partie de l'équation est à peu près multipliée par zéro, annulant ainsi tout, vous donnant

f(input_start) = output_start

essayons aussi input_end.

f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

qui à son tour finira par:

f(input_end) = output_end - output_start + output_start = output_end

comme vous pouvez le voir, il semble maintenant être correctement cartographié.

10
Erti-Chris Eelmaa
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start

Ce que cela fait, c'est de découvrir proportionnellement "dans quelle mesure" la plage d'entrée de l'entrée est. Il applique ensuite cette proportion à la taille de la plage de sortie pour déterminer en termes absolus dans quelle mesure la sortie doit être dans la plage de sortie. Il ajoute ensuite le début de la plage de sortie pour obtenir le numéro de sortie réel.

2
QuantumMechanic