Android float arithmetic wrong(SOLVED)

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:
image
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);

image

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

Maybe @Mathias_Westerdahl would have input.

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]

IEEE 754 format

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:

  • 1 sign bit
  • 8 exponent bits
  • 23 mantissa bits

Exponent (range) bits

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

Mantissa (fraction) bits

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

Your number: 1553138135

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.

6 Likes

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.

3 Likes