map() returns different values on arduino vs. teensy

gatheround

Well-known member
After spending a night trying to debug an issue I was having, I narrowed it down the map() on my Teensy returning an incorrect value.

map(1,0, 1, 100, 0); // returns 51 on teensy, 0 on arduino.

I'd expect this to return 0, but the function returns 51 on my Teensy 3.2, Teensy LC and Teensy 3.0. I tested it with an Arduino Uno and this command returns 0 as expected.

Interestingly, the Teensy works correctly if I do some fudgery:

(int)map((float)1,0,1,100,0); // returns 0.

I am using arduino 1.8.13, teensyduino 1.53
 
The code in wiring.h is
Code:
long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
{
	long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max;
	// Arduino's traditional algorithm
	//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
	// st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889
	// more conversation:
	// https://forum.pjrc.com/threads/44503-map()-function-improvements
	if ((in_max - in_min) > (out_max - out_min)) {
		return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min;
	} else {
		return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
	}
}
and it looks like the test for expansion v. contraction is wrong and should be:

Code:
	if (abs(in_max - in_min) > abs(out_max - out_min)) {

BTW the variable names are poorly chosen, as they are not maximum and minimums, but definitions
of number ranges. This probably explains the error creeping in.
 
The code in wiring.h is
Code:
long map(T _x, A _in_min, B _in_max, C _out_min, D _out_max, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
{
	long x = _x, in_min = _in_min, in_max = _in_max, out_min = _out_min, out_max = _out_max;
	// Arduino's traditional algorithm
	//return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
	// st42's suggestion: https://github.com/arduino/Arduino/issues/2466#issuecomment-69873889
	// more conversation:
	// https://forum.pjrc.com/threads/44503-map()-function-improvements
	if ((in_max - in_min) > (out_max - out_min)) {
		return (x - in_min) * (out_max - out_min+1) / (in_max - in_min+1) + out_min;
	} else {
		return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
	}
}
and it looks like the test for expansion v. contraction is wrong and should be:

Code:
	if (abs(in_max - in_min) > abs(out_max - out_min)) {

BTW the variable names are poorly chosen, as they are not maximum and minimums, but definitions
of number ranges. This probably explains the error creeping in.

Hey Mark, thanks for replying.. I didn't know the code was different than the arduino map() on purpose and looking at the "more conversation" thread linked in the commented code, it looks like Paul is aware of this exact issue as of May 2020. It also seems like someone else posted the fudgery (float) correction. I will stick with that until this issue is corrected, and I appreciate knowing that others have had this same problem.
 
See post #2 here for edit to map() code to fix out of bounds return for TD 1.54 going beta.

That Beta thread not live yet ...
 
After much fiddling, I came up with this.

https://github.com/PaulStoffregen/cores/commit/92b126da26047c52023b4ae28212352c30d71744

Hopefully it's better?

Here's a little test program...

Code:
void setup() {
  while (!Serial) ;
  Serial.println("MAP Test");
  Serial.println("--------");

  Serial.println(map(0, 0, 127, 60, 30), DEC);  // 60 is correct
  Serial.println(map(127, 0, 127, 60, 30), DEC); // 30 is correct

  Serial.println(map(50, 1, 50, 50, 1), DEC); // 1 is correct
  Serial.println(map(50, 50, 1, 1, 50), DEC); // 1 is correct

  long in1=0, in2=20;
  long out1=0, out2=4;
  Serial.printf("Range %d - %d maps to %d - %d\n", in1, in2, out1, out2);
  for (int i=in1-10; i <= in2+10; i++) {
    Serial.printf("%3d    %6.2f  %3d  %3d     %6.2f  %3d  %3d\n", i,
      map((double)i, in1, in2, out1, out2),
      map(i, in1, in2, out1, out2),
      map(i, in2, in1, out2, out1),
      map((double)i, in1, in2, out2, out1),
      map(i, in1, in2, out2, out1),
      map(i, in2, in1, out1, out2)
      );
  }

  Serial.println();
  Serial.println("Range 0-5 maps to 0-1023");
  for (int i=-5; i <= 10; i++) {
    Serial.printf("%3d  %8.2f  %5d  %5d  %8.2f  %5d  %5d\n", i,
      map((double)i, 0, 5, 0, 1023),
      map(i, 0, 5, 0, 1023),
      map(i, 5, 0, 1023, 0),
      map((double)i, 0, 5, 1023, 0),
      map(i, 0, 5, 1023, 0),
      map(i, 5, 0, 0, 1023)
      );
  }
}

void loop() {
}
 
Back
Top