Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# float infinite loop

The following code in C# (.Net 3.5 SP1) is an infinite loop on my machine:

for (float i = 0; i < float.MaxValue; i++) ;

It reached the number 16777216.0 and 16777216.0 + 1 is evaluates to 16777216.0. Yet at this point: i + 1 != i.

This is some craziness.

I realize there is some inaccuracy in how floating point numbers are stored. And I've read that whole numbers greater 2^24 than cannot be properly stored as a float.

Still the code above, should be valid in C# even if the number cannot be properly represented.

Why does it not work?

You can get the same to happen for double but it takes a very long time. 9007199254740992.0 is the limit for double.

like image 613
jonathanpeppers Avatar asked Feb 08 '10 20:02

jonathanpeppers


People also ask

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What do you mean by C?

" " C is a computer programming language. That means that you can use C to create lists of instructions for a computer to follow. C is one of thousands of programming languages currently in use.

Why is C named so?

Quote from wikipedia: "A successor to the programming language B, C was originally developed at Bell Labs by Dennis Ritchie between 1972 and 1973 to construct utilities running on Unix." The creators want that everyone "see" his language. So he named it "C".


2 Answers

Right, so the issue is that in order to add one to the float, it would have to become

16777217.0

It just so happens that this is at a boundary for the radix and cannot be represented exactly as a float. (The next highest value available is 16777218.0)

So, it rounds to the nearest representable float

16777216.0

Let me put it this way:

Since you have a floating amount of precision, you have to increment up by a higher-and-higher number.

EDIT:

Ok, this is a little bit difficult to explain, but try this:

float f = float.MaxValue;
f -= 1.0f;
Debug.Assert(f == float.MaxValue);

This will run just fine, because at that value, in order to represent a difference of 1.0f, you would need over 128 bits of precision. A float has only 32 bits.

EDIT2

By my calculations, at least 128 binary digits unsigned would be necessary.

log(3.40282347E+38) * log(10) / log(2) = 128

As a solution to your problem, you could loop through two 128 bit numbers. However, this will take at least a decade to complete.

like image 86
John Gietzen Avatar answered Sep 17 '22 14:09

John Gietzen


Imagine for example that a floating point number is represented by up to 2 significant decimal digits, plus an exponent: in that case, you could count from 0 to 99 exactly. The next would be 100, but because you can only have 2 significant digits that would be stored as "1.0 times 10 to the power of 2". Adding one to that would be ... what?

At best, it would be 101 as an intermediate result, which would actually be stored (via a rounding error which discards the insignificant 3rd digit) as "1.0 times 10 to the power of 2" again.

like image 39
ChrisW Avatar answered Sep 18 '22 14:09

ChrisW