1

Here is my code, throttle comes out to -18 when I run the program, and when I do the math I get 77.941... which is what I'm looking for. I know this is an EDQ "Extremely Dumb Question", and I am most likely to experience a FIF, "Fist In Forehead" moment any minute but I am stuck on it for now. FYI, programming it on an Atmega 328P using Arduino IDE on Windows 10.

Following example prints -18 and according to my calcualtions it should be 77.941...

  int throttle = (((800 - 270) * 100) / 680);
  Serial.println(throttle);

This is the visualized code...

  throttle = (((throttleSensor - oldMinValue) * (newMax - newMin)) / (oldMax - oldMin));

I am trying to do this, Convert a number range to another range, maintaining ratio

Also, I should add, it works fine when the result is below 47, above that it flips to a negative number.

user207421
  • 298,294
  • 41
  • 291
  • 462
edgar_wideman
  • 154
  • 12

3 Answers3

3

The short answer is, (800 - 270) * 100 = 53000. which is too large a number for the space that was allocated for the calculation results, integer overflow.

so changing the code from this...

 int throttle = (((800 - 270) * 100) / 680);

to this...

long largeValue = 100;
int throttle = (((800 - 270) * largeValue) / 680);

fixes the problem. The number 100 or value of (newMax - newMin) has to be a "long" or the processor will miscalculate. Someone, please correct me on this if need be or post a better answer if you got one. Also if someone has a better suggestion for the title so it can be easier found for future people with the same problem, go ahead and commend it below.

Thanks to the StackOverflow community for helping me solve this issue!

edgar_wideman
  • 154
  • 12
  • 1
    Integer division truncates in C++, so `77.941` will come out as `77` using the above. To round to the nearest integer, instead, add half the denominator before dividing `((800 - 270) * largeValue + 340) / 680`. – dxiv Nov 05 '20 at 06:46
  • 2
    just add the `L` suffix like in my comment is enough. `L` makes a `long` and `LL` makes a `long long`. No need for a separate variable – phuclv Nov 05 '20 at 07:11
  • You could also have changed 100 and 680 by 10 and 68 (or 5 and 34) to achieve the same result. – Michaël Roy Nov 05 '20 at 09:20
  • @phuclv thanks, in this case where I am using it, needs to be a variable. But thanks for letting me know I didn't know that. – edgar_wideman Nov 05 '20 at 13:41
1

as @edgar_wideman answer suggest your sub result (53000) does not fit into 16bit integer <-32768,+32767>. You can avoid long use by bitshifting (dividing by power of 2) like this:

int sh=1; // shift stuff so it fits 16 bit
int throttle = (((800 - 270) * (100>>sh)) / (680>>sh));
Spektre
  • 45,598
  • 10
  • 100
  • 347
  • Another great idea, yes I am Edgar, I kinda answered my own question in the end then. Thanks for your help anyway! – edgar_wideman Nov 06 '20 at 13:57
  • 1
    @edgar_wideman heh :) miss that its your question ... just beware that shifting right works reliably only for non negative numbers ... otherwise you need to use division instead .. or copy MSB after shift like `a = (a>>1)|(a&0x8000);` instead of `a = a>>1;` as on ARDUINO framework only god know's what `-10 >> 1` is ...as the compiler is not standard C/C++ ... so it might be `-5` but can be also something different like `0x7FFD` and even that does not mean that differen compiler version does it the same way – Spektre Nov 06 '20 at 14:24
0

This might not be exactly what you are looking for, but there is a function for changing values from one range to an other.

int y = map(value, minOld, maxOld, minNew, maxNew);

for example:

int y = map(10, 0, 50, 0, 100); // y would be 20
Michael
  • 109
  • 4