Due refuses doing math

Hi,

Im calculating some values, but somehow my DUE refuses to do the math...

uint16_t adcvalue =0;
  adcvalue= 13210;
Serial.print("ADC Val: ");
Serial.println(adcvalue/10);
long voltage = 0;
voltage = ((adcvalue/10)*(5000/4095));
Serial.print("Voltage: ");
Serial.println(voltage);

Gives me

ADC Val: 1321
Voltage: 1321

It doesnt calculate the *(5000/4095)

Why? :frowning:

tsaG:
It doesnt calculate the *(5000/4095)

Why? :frowning:

It DOES calculate the (5000/4095) and the result of that integer division is 1.

So what?

Didn't you expect that the board does an integer division if you do an integer division, or what?

jurs:
Didn't you expect that the board does an integer division if you do an integer division, or what?

uint16_t adcvalue =0;
adcvalue= 13210;
Serial.print("ADC Val: ");
Serial.println(adcvalue/10);
uint16_t voltage = 0;
float divider = (5000/4095);
voltage = ((adcvalue/10)*divider);
Serial.print("Voltage: ");
Serial.println(voltage);

Yes, this doesnt work as well (Same serial output as above).

Since on the Arduino arithmetic page it is written:

If one of the numbers (operands) are of the type float or of type double, floating point math will be used for the calculation.

I thought it would calculate in float and give out a integer value.

If I change the divider variable to "1.221" it works fine.

AWOL:
Maybe offer it a pension plan, or health insurance.

Or post your code.

Since Im from germany it already has enroled for this :smiley:
But the code is in my first post, isnt it?

tsaG:
Yes, this doesnt work as well (Same serial output as above).

Since on the Arduino arithmetic page it is written:
I thought it would calculate in float and give out a integer value.

The math rules are easy: if all numbers used in a calculation are int, then the result is int.

So "int/int" is always an int-division and the result is int. If you then assign the int result (1) to a float, the float is 1.000000.

Perhaps you wanted a division of float numbers:

float divider = (5000.0/4095.0);  // dividing float numbers

Even if one number in the division was float, the result would be float.
float/int = float
int/float = float

So perhaps in your original code you wanted a float calculation like that:

voltage = ((adcvalue/10)*(5000.0/4095));

Yes, this works! Thank you :slight_smile:

You are intersted in a specific feature of the C++ language, called type promotion.

Here's a link: Implicit conversions - cppreference.com

Look at the section on "Numeric Promotions".

jurs:
The math rules are easy: if all numbers used in a calculation are int, then the result is int.

It is more than just the result. It is all the intermediate calculations as well.

simplifying math gives always more accurate results.

voltage = ((adcvalue/10)*(5000.0/4095));
==>
voltage = adcvalue * 0.1221001;

Well if you want spurious accuracy, first change the 4095 to 4096...

robtillaart:
simplifying math gives always more accurate results.

voltage = ((adcvalue/10)*(5000.0/4095));
==>
voltage = adcvalue * 0.1221001;

Not always.... In this case, it will, because the first expression is poorly written, as it will truncate the division result, losing significance for some values of adcvalue. It is better wrtiten as:

voltage = (adcvalue*5000.0/4095)/10.0) ;

The compiler will collapse this expression to the second form at compile time, leaving the source code as documentation of where the 0.1221001 came from, rather than leaving it as a "magic number".

Regards,
Ray L.

Yes, it's extremely important to "show your working" because otherwise there's no way to know what 0.1221001 represents or how to change it to match a new system (like a 3.3v Arduino.) I would also usually include a comment to describe the units, eg milliseconds.

The complier does a surprising amount of pre-calculation for you. It can work out much more complex equations than this and just use the result, which makes your code both faster and smaller.

RayLivingston:
Not always.... In this case, it will, because the first expression is poorly written, as it will truncate the division result, losing significance for some values of adcvalue. It is better wrtiten as:

voltage = (adcvalue*5000.0/4095)/10.0) ;

The compiler will collapse this expression to the second form at compile time, leaving the source code as documentation of where the 0.1221001 came from, rather than leaving it as a "magic number".

Regards,
Ray L.

OK you have a point,

  1. I could add the original formula as comments
  2. get completely rid of the magic numbers, including familiar ones!
#define REFMILLIVOLT 5000.0
#define ADCSTEPS     4095
#define SCALING      10.0
....
voltage = adcvalue * REFMILLIVOLT/ADCSTEPS/SCALING;
voltage = adcvalue * REFMILLIVOLT/ADCSTEPS/SCALING;

Oh, that's just swell. Now you can't tell whether it's a float expression or an integer expression without searching all over other parts of the code :slight_smile: