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: