I am writing (in C) some low level digit manipulation routines that convert int to float and vice versa for Arduino. I came across some puzzling behaviour with Arduino rounding some numbers but not others. So I located and extracted the offending code into a simple program which I compiled on desktop Linux PC with GCC and on Arduino - they give different results. Why? Here are the programs. The goal is to take the float number 1.3140 and the float number 2.3140 and split them into two integers. In the first case I expect '1' and '3140' and in the second case I expect '2' and '3140' (the terminal '0' is important for my application). The Arduino code:
void setup() {
double dnum,x,y;
uint16_t intpart,fracpart;
Serial.begin(9600);
dnum = 1.3140;
x=modf(dnum,&y);
intpart = (uint16_t)y;
fracpart = (uint16_t)(10000.0*x);
Serial.println(dnum,4);
Serial.println(intpart);
Serial.println(fracpart);
}
and the output I get is:
1.3140
1
3140
Fantastic! Success. But hold on. If I change the hard-coded number to dnum = 2.3140
I get this:
2.3140
2
3139
What? Why did it round the second part down? Am I doing something fundamentally wrong? So I wrote a little C program for my PC (compiled with gcc). Here is the code:
#include<stdint.h>
#include<stdio.h>
#include<math.h>
int main (int argc, char *argv[])
{
double dnum,x,y;
uint16_t intpart,fracpart;
dnum = 2.3140;
x=modf(dnum,&y);
intpart = (uint16_t)y;
fracpart = (uint16_t)(10000.0*x);
printf("Int_part = %u\nFrac_Part = %u\n",intpart,fracpart);
return 0;
}
When run I get this result:
Int_part = 2
Frac_Part = 3140
Now that's what I expect - and to be thorough I also did the above C program with dnum = 1.3140;
and I again got the 'correct' expected result:
Int_part = 1
Frac_Part = 3140
So why does the Arduino round the fractional part down when I convert it to an integer sometimes and not others? I tried this on a genuine Arduino Uno, a clone Arduino uno and a clone Arduino nano and all give the same results. In 'theory' it could be some difference in the compiler tolerance to some coding impropriety I have done (gcc is more tolerant) but can anyone tell me what I did wrong and how to get the Arduino to behave (the way I want it to)? Thanks.