Wrong results when using large floats in calculations inside a Burst Job

When making calcuations with large float values in Burst i get the wrong results:

float i1 = 9_999_999_999f;
float i2 = 500;
Debug.Log(string.Format("{0}", i2 - i1 + i1));

The expected result would be 500, but the result I get when compiling with Burst is 0.
Running the job without Burst yields the correct result of 500.

Decreasing i1 to 999_999_999f yields 512 as a result, with 99_999_999 and lower the result is correct.

I tried all combinations of FloatPrecision and FloatMode for the compiler options, the result is the same in all cases.

Why does this happen? Is it a bug or just imprecision when using Burst and large numbers?

It is the expected result. :wink:

Simple console application:

float i1 = 9999999999f;
float i2 = 500;
Console.WriteLine(string.Format("{0}", i2 - i1 + i1));
Console.WriteLine(string.Format("{0}", i1));

Output:

0
1E+10

Float cannot represent numbers this large. Compare your number with int.MaxValue and you can see it is much higher than integer range:
9999999999f
2147483647

A floating point type uses the same 32-bit as an int but it has to divide this into exponent (8 bits) and significant (24 bits including sign). Meaning the integer value range for a float is much less than int.MaxValue. Ideally a float should remain a small number and optimally it remains in the 0f to 1f range because this allows you to multiply with the float to calculate any secondary values from this “percentage range”.

Let’s say you have some game value that represents currency and the player may have an account with $9,999,999,999.99 balance. You would not represent this with a float, even a double may not be enough so you need to use Decimal. Alternatively, many large values in games are simply “fake” because the last three digits are either arbitrary or always zero. So 9,999,999,000.00 may be internally represented as 9,999,999 with zero padding only in the UI.

1 Like

I don’t think the above explanation is correct - the maximum value of a float is much higher than int.maxvalue - I wonder if string.format is causing some sort of casting to ints or something like that

for example what about

  • float i1 = 9_999_999_999f;
  • float i2 = 500;
  • float i3 = i2 - i1 + i1;
  • Debug.Log(string.Format(“{0}”, i3));

or even

  • float i1 = 9_999_999_999f;
  • float i2 = 500;
  • Debug.Log(string.Format(“{0}”, (i2 - i1 + i1)));

Nope. :sunglasses:

float i1 = 9_999_999_999f;
float i2 = 500;

Console.WriteLine(string.Format("{0}", i2 - i1 + i1));
Console.WriteLine(string.Format("{0}", i1));
Console.WriteLine(int.MaxValue);

float i3 = i2 - i1 + i1;
Console.WriteLine($"string.Format(\"{{0}}\", i3) ==> {string.Format("{0}", i3)}");
Console.WriteLine($"string.Format(\"{{0}}\", i2 - i1 + i1) ==> {string.Format("{0}", i2 - i1 + i1)}");

This logs:

0
1E+10
2147483647
string.Format("{0}", i3) ==> 0
string.Format("{0}", i2 - i1 + i1) ==> 0

No matter what, it’s not about the logging, it’s the actual value being zero.
9773883--1400979--upload_2024-4-16_13-46-20.png

Interestingly when you look at i1 it’s already +1 for some reason, printing 1E+10 which equals
10,000,000,000. Also when you subtract any value from 1f to 1000000000f from float.MaxValue it still prints float.MaxValue.

1 Like

Burst is doing the “right” thing here. There are simply not enough bits in a float to represent such a large number precisely, and hence the lower digits are getting lost. Floating point numbers kinda work like scientific notation, you have the actual digits (called a mantissa) and then you got the exponent, like in 1.953e+8, where 1.953 would be the mantissa and 8 would be the exponent (here it would mean to multiply the digits by 10 to the power of 8, but floats work in base 2 instead). Because there’s only so many bits to store the digits in the mantissa the lower digits gets rounded off and lost, that’s why you get zero back out.

I can highly recommend reading more about floats and try out this interactive site that shows you exactly how a float you type in gets represented in the bits: IEEE-754 Floating Point Converter

2 Likes