 SOLVED: Is there a logical reason for this strange result?

I’m converting a reading to millivolts

float mVoltsOut;
int stepTime = 500; //msec

void setup() {
Serial.begin(9600);
}

void loop() {
mVoltsOut = 116 * 2244;
Serial.print(mVoltsOut);
Serial.print(" ");
delay(stepTime);
Serial.println();
}

Now by my calculations 116 * 2244 = 260304

So why does the Arduino think the correct answer is -1840?

because the calculation is done in int by default.

Try:

mVoltsOut = 116 * 2244.0;

or an explicit cast of at least one number to a float.

the range of values for an "int" is -32768 to 32767. 260304 is obviously out of range and the upper bits are lost

260304 0x3f8d0 0xf8d0 63696 -1840

if you want to convert an 5V 10-bit ADC value to mV, shouldn't you be multiplying the ADC value by 5000/1024. but in order to maintain precision, specify one value as a float, 5000.0/1024

If you want to keep the number as an integer, you can change mVoltsOut to a long, and explicitly tell the compiler to do the calculation using 32-bit integers by specifying that you are multiplying by a long:

mVoltsOut = 116 x 2244L;

Thanks all, silly me I've been playing with 32 bit devices, forgot the uno is 16 bit.

So float mVoltsOut = 116 * 2244;

behaves as float mVoltsOut = (float) 116 * 2244; then the value is too big for an int.

thanks @noiasca .. upper bits are lost so

260304 0x3f8d0 0xf8d0 63696 -1840

but

if you want to convert an 5V 10-bit ADC value to mV, shouldn't you be multiplying the ADC value by 5000/1024.

no - that assumes I'm using an ADC with an accurate 5V reference. which I'm not.

Actually I'm using PWM output with a filter as a DAC, and a value of 116 gives me 2244mV after the filter.

johnerrington:
Actually I'm using PWM output with a filter as a DAC, and a value of 116 gives me 2244mV after the filter.

i get the following results

0
2274

from this code (parentheses prevent overflow, but truncate result)

void setup (void)
{
Serial.begin (9600);
int mV;

mV = 5000 * (116 / 255);
Serial.println (mV);

mV = 5000.0 * 116 / 255;
Serial.println (mV);
}

void loop (void)
{
}

Try:

mV = (5000 * 116) / 255L;

countrypaul:
Try:

mV = (5000 * 116) / 255L;

No, multiplication is done first, with 16-bit integers, and overflows before the division operation.

mV = 5000L * (116 / 255);
Serial.println (mV);

This does not work because integer arithmetic only uses whole numbers, as a result 116 / 255 gives an answer of zero.

Specify that either the 5000 or 116 is long to prevent the overflow

mV = 5000L * 116 / 255;
Serial.println(mV);

mV = 5000 * 116L / 255;
Serial.println(mV);

Incidentally, the calculation will be done at compile-time since all the numbers are know by the compiler, and not at run-time on the arduino.

Tou are totaly correct, I managed to miss the L out completey so went back and did a careless quick edit will pay more attention next time.