In cpp in android, I found that casting long to float resulting a wrong value:
long m = 1553138135;
float n = m;
dmLogInfo(“gwjgwj,pi=%f”, n);
In this example, I got the following log:
What’s wrong?
BTW, what compiler used for android?
In cpp in android, I found that casting long to float resulting a wrong value:
long m = 1553138135;
float n = m;
dmLogInfo(“gwjgwj,pi=%f”, n);
In this example, I got the following log:
What’s wrong?
BTW, what compiler used for android?
Try this?
The same.
long m = 1553138135L;
float n = m;
dmLogInfo(“gwjgwj,sizeof(float)=%d,m=%ld,n=%f”, sizeof(float), m, n);
I have tried double, it is correct, but when casting double to float, it is wrong again.
I have tried in VS, the same result, so this is the limitation of float precision
We have the details documented about compilers.
This is a case of floating point precision. Both single and double precision floating point numbers have them.
When it comes to floating point precision, there are a lot of details here
A uint32_t
has 32 bits, and can store all the numbers between [0,4294967296] or 0 - 2^32
An int32_t
also has 32 bits, can store all the numbers between [-2147483648,2147483647]. The Most Significant Bit is used to store the sign.
A single precision float has 32 bits (format IEEE 754) and spans the range [1.2E-38, 3.4E+38]
Also 3.4E+38
is way larger than 2147483647
, so how does a float
manage to store that into 32 bits.
While the int32_t
can represent all numbers in its range, the float
has to also somehow store decimals.
As you can imagine, there is a tradeoff and it’s with regards to precision.
The 32 bits are divided like so:
These bits represent the power-of-two exponent, or the range of numbers represented. Or perhaps a sliding window
E.g. [0.5,1], [1,2], [2,4], [4,8], [8,16] and so on
Once you’ve found your range, e.g. [2,4], the floating point divides that by 2^23 = 8388608
(4 - 2) / 8388608 = 0.0000002384185791
This means that the precision in the range [2,4] is 0.0000002384185791. That is, the step between two consecutive floats is 0.0000002384185791.
For the range [8192,16384] the precision is
(16384 - 8192) / 8388608 = 0,0009765625
Fabien Sanglard does an excellent explanation
This is a big number.
The range for 1553138135 is [2^30,2^31] = [1073741824, 2147483648] (log2(1553138135) ~= 30.53)
You might notice that you’re having an upper limit in your range of 2^31. That’s almost the upper limit for unsigned integers!
But, as we mentioned, the upper limit of a single float precision number is 3.4E+38, so we’re good.
The precision, between consecutive valid floats, is calculated again:
(2147483648 - 1073741824) / 8388608 = 128
So, in that range the the difference between two consecutive floats is 128
.
Your number 1553138135
is not evenly divisible by 128
:
(1553138135 - 1073741824) / 128 = 3745283,6796875
Rounding that number to 3745284 and convert back:
3745284 * 128 + 1073741824 = 1553138176
Et voilà, 1553138176
is the number you got.
Whoa!! I hadn’t even imagined that floating point arthimetic happened like this.
Yeah, it’s good to know about at least.
For instance, in shaders, the lowp
, mediump
and highp
all control the number of bits for the entire floating point number. Less bits -> bigger precision steps between numbers -> more jitter.