0
quotient = 43156414f / 3;

I got quotient == 14385472 here (totally not as true value should be: 14385471,333...). It completely lost all fractional part!

I know about floating point calculations inacuracy (it seems, not all, that I should to know), but, as I informed, the error could appear at much farther significant digits. But the dividend here is only 8-digits number. Why so dramatic error happens?

Optional sub-question: What rules should I keep in mind to foresee such errors in future?

Just to note: Changing type of divident from float to double fixes this problem.

user1234567
  • 3,991
  • 3
  • 19
  • 25

2 Answers2

7

float has a precision of 6-9 digits. Your value is just too large to fit into a float without loss.

double has a precision of about 15-17 digits.

As an illustration, inspect the value of (int)43156414f or (double)43156414f - they are both 43156416

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
3

Well, float (Single) uses 23 bits for mantissa

https://en.wikipedia.org/wiki/Single-precision_floating-point_format

So float can represent integers up to 2**24 - 1 == 16777215 which is close to 14385471. The possibilities we have are:

 01001011 01011011 10000001 00111111 correponds to 14385471f (let's add 1 bit)
 01001011 01011011 10000001 01000000 correponds to 14385472f

So as we can see we have only 14385471f and 14385472f to choose from; no place for 14385471.33333f in case of floate. Let's have a look

 float x = 14385471.3333333333f;

 byte[] data = BitConverter.GetBytes(x);

 Console.Write(" ", string.Join(" ", data
   .Reverse()
   .Select(b => Convert.ToString(b, 2).PadLeft(8, '0'))));

We'll have

 01001011 01011011 10000001 00111111

which corresponds to 14385471f. Even more problems we have with

 quotient = 43156414f / 3;

Now, 43156414f > 2**24 - 1 (16777215) and 43156414f can't be represented as float but

 01001100 00100100 10100000 11110000 corresponds to 43156416 

So the actual value of quotient is

 43156416 / 3 == 14385472      

Finally, if you want to have 14385471.33, Single is not enough, try double:

 // 14385471.333333334
 double quotient = 43156414d / 3;
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215