0

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 am programming it on an Atmega 328P using Arduino IDE on Windows 10.

The following example prints -18 and according to my calculations 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.

halfer
  • 19,824
  • 17
  • 99
  • 186
edgar_wideman
  • 315
  • 4
  • 16
  • Please try to produce a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). Without knowing how `throttleSensor`, `oldMinValue`, `newMax`, `newMin`, `oldMax`, and `oldMin` are set, we can at best guess at what might be going wrong. – Nathan Pierson Nov 05 '20 at 04:14
  • Those actual numbers are what we're dealing with in this question. I have edited for clarity now – edgar_wideman Nov 05 '20 at 04:16
  • 5
    This is probably because `int`s are 16 bit in your system and you have an overflow on (800 - 270) * 100 = 53,000. signed 16 bit ints only go up to 32,767. – The Dark Nov 05 '20 at 04:26
  • 1
    Arduino is an 8-bit MCU so int contains only 16 bits. You need to use `long` instead: `int throttle = ((800 - 270) * 100L) / 680` – phuclv Nov 05 '20 at 04:35
  • Thanks, I just thought of this myself and am working on fixing it, I'll let ya know what I come up with. – edgar_wideman Nov 05 '20 at 04:46
  • Yip works fine, results are in my own answer below. – edgar_wideman Nov 05 '20 at 05:06

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
  • 315
  • 4
  • 16
  • 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
  • 49,595
  • 11
  • 110
  • 380
  • 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
  • 147
  • 4