int has a limit of around 32000 (to both sides).
because you are multipling by 100 you cross it very quickly.
you can try using unsigned int which will roll over a bit later (when I is around 640).
but I think "Map" function is more suited to your needs here
I understand the limits of ints and I realize this maybe why I get problems with the first example.
What I don't understand is why (or so it appears) does the compiler take the variable type of i in to account when calculating percent. I am not assigning the the result of i100 to i ( i = i100 ) and the value of i is always between 0 and 1023.
in your code "percent" is also an int. you have are trying to do a math in numbers that require more bits than the 16 you have allocated (short = 1 byte, int = 2 byte, long = 4 byte). so you are rolling over while doing the math.
I think that if you change percent to long (or better, unsigned long) you'll have no problem.
but if you use "map", percent can be "short" and save you 3 bytes of RAM.
The C compiler uses a set of rules for determining intermediate result types.
In particular if the arguments to an operator are int the result will be int, in general.
If one or both of the argments is long, the result becomes long. Rules also determine
if the result is signed or unsigned. Also the default size for intermediate results
is int (16 bits on the Arduino Uno etc), so that the expression "0" is actually a 16 bit
signed zero.
If you want a specific result type you may have to widen one of the argments to
force it:
100 * (long) i
Incidentally 100 and 1024 share a common factor of 4, so you can finesse the issue:
4.5 Integral promotions [conv.prom] 1 A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion
rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all
the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned
int.
here it refers to an int with any combo of modifiers ( signed/unsigned/short/long ).
So the temporaries used to store the result are big enough to store the largest version of int used in the expression. And the calculation works fine. When you use a plain int for i, it promotes nothing as 'int' can hold all the values of 'int'.
Then the value is truncated back to 16 bits into 'percent', however the value is less than INT_MAX so the data stays the same:
4.7 Integral conversions [conv.integral]
2 If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2
n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s
complement representation, this conversion is conceptual and there is no change in the bit pattern (if there
is no truncation). — end note ]
Thanks MarkT and pYro_65. I suspected it was something like this.
I played around with forcing the type while using floats and the traditional formula format ( 1/1023 * 100) but didn't get it to work without defining the variable as floats . It took me a while to realize I could swap the formula around and not have to deal with fractions.
I do mean 1023 by the way
MarkT:
Incidentally 100 and 1024 share a common factor of 4, so you can finesse the issue:
percent = (i*25) >> 8;
I do like this but when I revisit the code in a couple of month I will have no idea what it does.