why this casting fails despite 1234567891011 being much smaller than ULONG_MAX (2^64) and FLT_MAX ? (but indeed, suspiciously larger than 2^32)
In your C implementation, float
represents finite numbers as a sign, a 24-bit unsigned integer, and a scaling by a power of two ranging from 104 to −149. (This also described as a 24-bit binary numeral with its radix point fixed after the first digit and a power of two ranging from 127 to −126. These are mathematically equivalent.)
1,234,567,891,011 cannot be represented in a 24-bit integer, not scaled by any power of two. The closest value representable in the float
format described above is 4,709,503•218, which equals 1,234,567,954,432. Thus, when 1,234,567,891,011 is converted to float
, the result is 1,234,567,954,432.
how can FLT_MAX reach 3.402823e+38 with only 4 bytes?
How can you reach 3.402823e+38 using only only those 12 characters? How can powers of 2 reach 299 using only two digits in the exponent? How can we represent the concept of infinity using only finitely many letters in the word “infinity”?
The number of bits in an object only limits how many different things it can represent. It does not in any way control what they represent. We can take three bits and say 000 represent zero, 001 represent five, 010 represents −1, 011 represents π, 100 represents i (the square root of −1), 101 represents apple, 110 represents Mars, and 111 represents ennui.
In the float
format, we say the first bit represents the sign (0 for +, 1 for −), the next eight bits represent a code mostly for the exponent of two, and the last 23 bits represent most of a fraction portion of the float
representation. The exponent codes use 1 to 254 for exponents from −126 to +127 and also mean the fraction portion starts with “1.”. The exponent code 0 means the exponent is −126 and the fraction portion starts with “0.” The exponent code 255 means the value represent is either infinity or a special “Not a Number” value, depending on the last 23 bits.
Since the exponent code bits can represent exponents up to 127, a float
object can represent up to 2127 times the fraction portion, which can be as high as a little less than 2 (it can be 2−2−23).
is there a clean way to handle this case, other than checking if my unsigned long is bigger than a specific threshold? (2^32 ?)
It was handled cleanly; float f = (float) ul;
converted the number as well as it could. If you want different handling, you need to describe what different results you want.