why is math not accurate

so I have some code in the update function that will be used for an accelerate/decelerate function. but when I run it, the math isn’t accurate, here is my code:

if (Input.GetKeyDown(KeyCode.W))
         {
                 wDown = true;
         }
         if (Input.GetKeyUp(KeyCode.W))
         {
                 wDown = false;
         }
if(wDown == true)
         {
             if (veloFB < 5)
             {
                 veloFB += 0.2f;
             }
         } else if(wDown == false && veloFB > 0)
         {
             veloFB -= 0.2f;
         }

wDown gets turned true/false when w is pressed, and lifted, and veloFB is set to 0. when I run this, and stop pressing w, it either goes to around -2 with some random decimals, or it goes to a really high/low number, like -2e349994939234, why is this happening?

1 Like

I feel like @Kurt-Dekker is just a few minutes ahead of me today. :slight_smile:

5 Likes

Numbers have to be stored somewhere in memory.

Memory has a finite amount of space… in the case of a “float” or “single” it’s 32-bits. In the case of a “double” it’s 64-bits.

Basically it has 32/64 digits of 1 or 0 to represent the number in question.

How it does this, in the case of floats/doubles, is basically what you may be familiar with as “scientific notation”. Where you write the number as its significant value * 10 raised to some power. Just in floats it’s * 2 raised to some power (cause binary).

It ends up looking like this in memory:

This means that you only have a finite amount of sig value range. If your value does not fit in it… well you lose information.

If you do arithmetic with 2 values that in different sig value ranges, it’s going to work in the largest sig value range (meaning really large numbers + really tiny numbers appear as no addition whatsoever).

Also you end up in situations where what looks like very simple decimal values are actually infinite repeating values in binary. Just like how 1/3 is 0.333333333… in decimal, well the simple value 1/10 is 0.00011011011011011011… repeating in binary. And since you only get a limited sig range you’re going to end up with all that infinite data chopped off and you end up with a value just shy of the real value.

TLDR;

Real numbers don’t fit in finite spaces.

6 Likes

The coffee was really really really good this morning.

5 Likes

so how can I go about fixing this, or what is another way to accomplish my goal?

It’s not going to -2. It’s probably going to something like -2e-<some large number>. The e is exponential notation, so that expression expands out to -2 * 10^-<some large number>, or -0.000000...0002. It’s actually extremely close to zero, but slightly less due to floating point imprecision. There’s nothing to fix, the math is not wrong.

When working with floats you need to factor the imprecision into your logic. Decide whether you actually need that precision (you probably don’t). If you do, then don’t use floating point numbers.

1 Like

Use integers and convert it to float in the precision range when you apply it.

Or just ignore it, it’s not wrong, just ugly. :smile:

Also this } else if(wDown == false && veloFB > 0) should be this } else if(wDown == false && veloFB >= 0.2f)
Or add an if (veloFB < 0) veloFB = 0; inside after subtracting .2f
Because if you end up with .1f, the if statement will still be true and you will subtract .2f, so you will end up with -.1f

Well, don’t use floating point values. Just use an integer.

int veloFB = 0;

// [ ... ]

if(wDown == true && veloFB < 25)
{
    veloFB += 1;
}
else if(wDown == false && veloFB > 0)
{
    veloFB -= 1;
}

To get the final value as a float, you can simply multiply the value by 0.2f (or divide by 5f) whenever you use it somewhere. However if you don’t really care about the tiny errors, you could simply get rid of your range if statements and always increase / decrease the value whenever the button is pressed and just clamp the result between your desired values:

float veloFB = 0;

// [ ... ]

if(wDown)
{
    veloFB += 0.2f;
}
else
{
    veloFB -= 0.2f;
}
veloFB = Mathf.Clamp(veloFB, 0f, 5f);

btw: You haven’t really said what your actual issue was. There is no really “large” value. What you probably got was an extremely small number, very close to 0. Probably something like 2.123456789e-50. That’s not a very large number as this is a number with 50 zeros before the decimal point. So my example number would actually be
0.00000000000000000000000000000000000000000000000002123456789

If you haven’t heard of scientific notation you may want to look it up. I can also recommend this Computerphile video about floating point numbers.

2 Likes

Looking at your use case you can probably get away with float.

The main problem with float is comparing for equality: you cannot add 0.1f together ten times and expect it to equal 1.0f.

As long as you don’t compare for equality, you can probably be okay.

Just do constructs like:

veloFB -= 0.2f;
if (veloFB < 0)  // less than or greater than is fine
{
  veloFB = 0;
}

And if you want the number printed out, use fewer decimal places and it should look fine:

1 Like

well, for what I am doing sometimes the player moves backwards because of the number, instead of not visible moving

That’s because your logic depends on equality. A number like 2e-45 (which is about what you get from this kind of imprecision) is smaller than the diameter of an electron so that will literally never produce detectable movement. However, “the diameter of an electron greater than zero” is still greater than zero, so this:

else if(wDown == false && veloFB > 0)
         {
             veloFB -= 0.2f;
         }

will result in veloFB being -0.2f, which is your backwards movement. If your goal is “slow down by 0.2f until you reach 0 velocity”, use something like MoveTowards instead of plain subtraction:

veloFB = Mathf.MoveTowards(veloFB, 0f, 0.2f);
2 Likes

Great explanation, thanks a lot. Your solution helped me. In general, mathematics occupies a very large place in my life, because I have loved it since childhood. Now I am studying at the university and continue to study mathematics professionally. Sometimes I go to the site https://plainmath.net/ which helps me with my math assignments. A very useful resource, I advise.