map() larger then 32768

Hi!

I found a "bug" for me today. I working with a 12m long treadmill for positioning. One revolution is 150000 pulses and fits in a LONG. I use a 16-bit value for positioning 65535, 65535 also fits in a LONG.

My code:

long i = 14000;

void setup() {
Serial.begin(9600);
Serial.println("Start...");
}

void loop() {
long mapedNumber = mapidimap(i, 0, 65535, 0 , 150000);
Serial.println(String(mapedNumber));
i++;
}

long mapidimap(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;
}

When I run this code my "LONG mapedNumber" runs like an integer. It run to 32768 and jumps to -32768, but I would have this going up to 65535 instead.

"mapidimap"-calculation is the same as in Arduino-reference for map().

I found it very strange and I´am real confused...

Is there any logical explanations for this?

I found it very strange and I´am real confused...

Try:

long mapedNumber = mapidimap(i, 0UL, 65535UL, 0UL , 150000UL);

No, it dosen´t worked for me... same result and still enoying. :frowning:

Edit... I use a MEGA2560...

MacTommy:
No, it dosen´t worked for me... same result and still enoying. :frowning:

Edit... I use a MEGA2560...

Please post the revised code in code tags, not in quotes. Do not edit the original post.

Ahhh… miss the </> first in the editor toolbar… sorry.

I thought it was a litle strange that comunity didn´t have a [ code ]-block… :slight_smile:

Use some intermediate variables in the map function. See where overflow is occurring.

Just change all long to unsigned long.

unsigned long i = 14315;

void setup() {
  Serial.begin(115200);
  Serial.println(F("Start..."));
}

void loop() {
  unsigned long mapedNumber = mapidimap(i, 0, 0xFFFF, 0, 150000L);
  Serial.print(i);
  Serial.print(F(" maps to "));
  Serial.println(mapedNumber);
  i++;
  delay(500);
}

unsigned long  mapidimap(unsigned long x, unsigned long in_min, unsigned long in_max, unsigned long out_min, unsigned long out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Thanks Whandall! Works fine. :slight_smile:

I also found that if I split my calculation in two parts it works…

long  mapidimap(long x, long in_min, long in_max, long out_min, long out_max) {
  unsigned long calc1 = (x - in_min) * (out_max - out_min);
  unsigned long calc2 = calc1 / (in_max - in_min);
  return calc2;
}

mapidimap(i, 0, 65535, 0 , 150000) simplifies to i * 150000 / 65535.
i * 150000 overflows long when i = 14317 and unsigned long when i = 28634.

Solution: use long long for intermediate results.

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

oqibidipo:
mapidimap(i, 0, 65535, 0 , 150000) simplifies to i * 150000 / 65535.
i * 150000 overflows long when i = 14317 and unsigned long when i = 28634.

Solution: use long long for intermediate results.

Better solution: use arithmetic.

150000 = 15 * 10000
 65535 = 15 *  4369

Therefore, for i * 150000 / 65535, we can substitute i * 10000L / 4369, and it will not overflow unless i exceeds 214748.

Thanks guys...

But if I would speed up my code, isn´t it be better to not change the type inside the calculation and go for Whandall´s solution? "UNISGNED LONG" all he way...

MacTommy:
Thanks guys...

But if I would speed up my code, isn´t it be better to not change the type inside the calculation and go for Whandall´s solution? "UNISGNED LONG" all he way...

All that does is change when the overflow will occur.

Better solution: use arithmetic.

That's fine in that specific case. It is not a general solution.

PaulS:

odometer:
Better solution: use arithmetic.

That's fine in that specific case. It is not a general solution.

Well then, use different arithmetic.

150000 = (65535 * 2) + 18930

You see where I'm going with this.

MacTommy:
When I run this code my "LONG mapedNumber" runs like an integer. It run to 32768 and jumps to -32768, but I would have this going up to 65535 instead.

So, you want unsigned integers rather than signed integers.