Int to float conversion fail

Hello everyone!
I wrote a simple program, that takes a constant integer number, converts to float, then writes the result on serial output.
Theoretically, the number should remain the same. But, instead of 474780023(which was the initial number), it outputs 474780032. Why does this happen?
Here is the code:

float d;
int fc() {
  const int d2 = 474780023;
  return d2;
}
My board is an Arduino DUE.

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


void loop() {
  d = fc();
  Serial.println(d);
}

A float variable is accurate to only 6 digits, sometimes 7.

Thank you for answering!
Sorry, I should have checked the Arduino reference more carefully, before running to the forum.
The reference says: "Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point."
Meanwhile, I checked the binary representation of these 2 numbers and they are the same:
http://www.binaryconvert.com/result_float.html?decimal=052055052055056048048050051
http://www.binaryconvert.com/result_float.html?decimal=052055052055056048048051050

jremington:
A float variable is accurate to only 6 digits, sometimes 7.

That is the number of digits after the decimal point; but, the OP has the whole number of 474780023 which when mapped into float domain should theoretically be 474780023.00 and not 474780032.00. We need to investigate why there is such a change in the integer part.

GolamMostafa:
That is the number of digits after the decimal point; but, the OP has the whole number of 474780023 which when mapped into float domain should theoretically be 474780023.00 and not 474780032.00. We need to investigate why there is such a change in the integer part.

It's a 29 bit number - no investigation required.
29 into 23 doesn't go.

That is the number of digits after the decimal point

Incorrect.

Float variables are accurate to between 6 and 7 decimal digits, regardless of the position of the decimal point.

jremington:
Float variables are accurate to between 6 and 7 decimal digits, regardless of the position of the decimal point.

Right, think Significant Figures.

The OP says he/she is using an Arduino Due, for which the default int type is 32 bits, 9-10 decimal digits precision.

On a Due, a float is 32 bits, same as a Uno

jremington:
The OP says he/she is using an Arduino Due, for which the default int type is 32 bits, 9-10 decimal digits precision.

Yes, sorry, I removed that comment seconds after I posted it. You're quick.

AWOL:
It's a 29 bit number - no investigation required.
29 into 23 doesn't go.

I am interested to know the 'root cause' that is boosting the value by 9 units -- 474780032.00 instead of 474780023.00. Can we get it just from intuition without doing any rational investigation?

The OP has given the following integer number:
unsigned long x = 474780023;
==> 1C4C9177
==> 1 1100 0100 1100 1001 0001 0111 0111
==> (1.1100 0100 1100 1001 0001 0111 0111)2*228 --------[1]

Let us fit it into the following (Fig-1) binary32 template:
binary32Just.png
Figure-1: binary32 template for 32-bit float number

Sign-bit: 0
Biased exponent (8-bit) = 28 (from [1]) + 127 (fixed bias) = 155 = 9B = 10011011
Binary fraction (23-bit) = 1100 0100 1100 1001 0001 0111 0111 (from [1]) //5 bits are lost ---[2]

Putting the above 3 components in line, we get: 0 10011011 1100 0100 1100 1001 0001 011
==> (arranging in nibbles) 0100 1101 1110 0010 0110 0100 1000 1011
==> (in hex format) 4DE2648B

Let us execute the following codes in UNO (in UNO and DUE floats are same) and see what value we get for the manually calculated 32-bit (binary32) value of 4DE2648B. (Do we expect more or less?)

union
{
  float x;
  byte myData[4] = {0x8B, 0x64, 0xE2, 0x4D};
}data;

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

void loop()
{
  Serial.println(data.x, 2); //shows: 474780000.00
  delay(1000);
}

The program reports 474780000.00 instead of 474780023.00. There is a loss of information (4.86*10-6%); but, it is not a loss from practical point of view; but, it is a loss from calculation point of view. The root cause of this loss is attributed to the 5-bit that we have lost in [2].

So, how can we establish similar model to justify the gain in information (474780032.00 in place of 474780023.00)?

binary32Just.png

It is pretty straightforward to use “rational investigation” and simple math.

Here is a hint:

log10(223) ~ 6.9
log10(232) ~ 9.6

jremington:
It is pretty straightforward to use “rational investigation” and simple math.

Here is a hint:

log10(223) ~ 6.9
log10(232) ~ 9.6

These are the stuffs that we have done in secondary school as exercises; here, we are dealing with binary32 format which has come into serious discussion by virtue of Arduino Forum. There is an information gain – the co-workers seek explanation!

Every binary number has a leading 1 digit, so it would be a waste of time to store that value explicitly. Therefore the 23-bit mantissa in the IEEE-754 standard is equivalent in precision to a 24-bit integer because it assumes there’s always a 1 in front of it.

474780023 requires 29 bits to store exactly. That’s a difference of 5 (binary) orders of magnitude. 25 = 32.

So take 474780023, divide it by 32, round to the nearest integer (up in this case), then multiply by 32. What number do you think you get?

GolamMostafa:
So, how can we establish similar model to justify the gain in information (474780032.00 in place of 474780023.00)?

You rounded down. It looks like the conversion function rounds to nearest instead, which in this case is rounding up.

const int d2 = 474780023;

And all this time I thought an int was limited to 32768, even on a Due.

@Just looked it up and it is a 4 byte integer. Never mind...