mjs513
Senior Member+
I should have mentioned, another property some people are expecting is identical result for "reverse" mapping.
In other words, ideally these should give the same result for all inputs:
map(x, 0, 5, 0, 1023);
map(x, 5, 0, 1023, 0);
And these 2 should give the same result as the 2 above, but "reversed"
map(x, 0, 5, 1023, 0);
map(x, 5, 0, 0, 1023);
Of course Arduino's map() doesn't do any of this, and I do not believe any of the proposed map() functions on their issue trackers do either, especially when considering extrapolating beyond the mapped range.
Thanks Paul - will check that next. Out of curiosity I was looking for a mathematical approach to map and found something on rosetta code for a map function: https://rosettacode.org/wiki/Map_range. I added this to the code just to see what it would give me:
Code:
#include <vector>
template<typename tVal>
tVal map_value(std::pair<tVal,tVal> a, std::pair<tVal, tVal> b, tVal inVal)
{
tVal inValNorm = inVal - a.first;
tVal aUpperNorm = a.second - a.first;
tVal normPosition = inValNorm / aUpperNorm;
tVal bUpperNorm = b.second - b.first;
tVal bValNorm = normPosition * bUpperNorm;
tVal outVal = b.first + bValNorm;
return outVal;
}
// This is the original map() function in Arduino Core
long map1(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;
}
// This is the same but with the +1 "range extrension" as suggested by st42
long mapPlus1(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min;
}
// This is another version of map with rounding done only with integer calculations
// as suggested by M.Kooijman
long mapRound(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)/2) / (in_max - in_min) + out_min;
}
void setup(void) {
Serial.begin(115200);
delay(2000);
long x;
Serial.printf("Range 0-20 to 0-4\n");
//rosetta version
//https://rosettacode.org/wiki/Map_range#C.2B.2B
Serial.printf(" x map map1 map(+1) map(round) Rosetta\n");
std::pair<float,float> a(0,20), b(0,4);
for (x=-10; x<=30; x++) {
Serial.printf("%6ld %6ld %6ld %6ld %6ld %f\n", x,
map(x, 0, 20, 0, 4),
map1(x, 0, 20, 0, 4),
mapPlus1(x, 0, 20, 0, 4),
mapRound(x, 0, 20, 0, 4),
map_value(a, b, (float)x));
}
Serial.printf("\n\n");
Serial.printf("Range 0-5 to 0-1023\n");
std::pair<float,float> c(0,5), d(0,1023);
Serial.printf(" x map map1 map(+1) map(round) Rosetta\n");
for (x=-5; x<=10; x++) {
Serial.printf("%6ld %6ld %6ld %6ld %6ld %f\n", x,
map(x, 0, 5, 0, 1023),
map1(x, 0, 5, 0, 1023),
mapPlus1(x, 0, 5, 0, 1023),
mapRound(x, 0, 5, 0, 1023),
map_value(c, d, (float)x));
}
}
void loop() {}
Output:
Code:
Range 0-20 to 0-4
x map map1 map(+1) map(round) Rosetta
-10 -2 -2 -2 -1 -2.000000
-9 -2 -1 -2 -1 -1.800000
-8 -2 -1 -1 -1 -1.600000
-7 -1 -1 -1 0 -1.400000
-6 -1 -1 -1 0 -1.200000
-5 -1 -1 -1 0 -1.000000
-4 -1 0 0 0 -0.800000
-3 -1 0 0 0 -0.600000
-2 0 0 0 0 -0.400000
-1 0 0 0 0 -0.200000
0 0 0 0 0 0.000000
1 0 0 0 0 0.200000
2 0 0 0 0 0.400000
3 1 0 0 1 0.600000
4 1 0 0 1 0.800000
5 1 1 1 1 1.000000
6 1 1 1 1 1.200000
7 1 1 1 1 1.400000
8 2 1 1 2 1.600000
9 2 1 2 2 1.800000
10 2 2 2 2 2.000000
11 2 2 2 2 2.200000
12 2 2 2 2 2.400000
13 3 2 3 3 2.600000
14 3 2 3 3 2.800000
15 3 3 3 3 3.000000
16 3 3 3 3 3.200000
17 3 3 4 3 3.400000
18 4 3 4 4 3.600000
19 4 3 4 4 3.800000
20 4 4 4 4 4.000000
21 4 4 5 4 4.200000
22 4 4 5 4 4.400000
23 5 4 5 5 4.600000
24 5 4 5 5 4.800000
25 5 5 5 5 5.000000
26 5 5 6 5 5.200000
27 5 5 6 5 5.400000
28 6 5 6 6 5.600000
29 6 5 6 6 5.800000
30 6 6 7 6 6.000000
Range 0-5 to 0-1023
x map map1 map(+1) map(round) Rosetta
-5 -1023 -1023 -853 -1022 -1023.000000
-4 -819 -818 -682 -818 -818.400024
-3 -614 -613 -512 -613 -613.800049
-2 -409 -409 -341 -408 -409.200012
-1 -205 -204 -170 -204 -204.600006
0 0 0 0 0 0.000000
1 205 204 170 205 204.600006
2 409 409 341 409 409.200012
3 614 613 512 614 613.800049
4 818 818 682 818 818.400024
5 1023 1023 853 1023 1023.000000
6 1228 1227 1024 1228 1227.600098
7 1432 1432 1194 1432 1432.199951
8 1637 1636 1365 1637 1636.800049
9 1841 1841 1536 1841 1841.399902
10 2046 2046 1706 2046 2046.000000
Next up - reverse range.