Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

7.55 - 0.01 = 7.5399999???

Discussion in 'Scripting' started by cgeopapa, Apr 14, 2015.

  1. cgeopapa

    cgeopapa

    Joined:
    Sep 23, 2014
    Posts:
    23
    I came across this problem a couple of times and I managed to find a pretty good solution, witch can come in handy if you also have a simillar problem!

    What's the problem?
    For some reason when you you subtract a float with an other very small float you dont get the number you would expect.
    Say: 34.67 - 0.01 = 34.65999999... (witch is not correct)

    And how do I fix this?
    Well, you cant fix it by changing some code, but you can tell unity how to change that number to the right one!
    So say you want to to do this: 12.84 - 0.01 witch is equal to 12.83 but unity will say it is equal to 12.8299999. You can do the following:


    Code (JavaScript):
    1. Mathf.Round((12.84 - 0.01)*10000)/10000;

    Let's see this code step by step:

    • First you do the subtraction: 12.84-0.01= 12.82999999
    • Then you multiply the result by 10000. So you have this number: 128299.9999
    • Then you round this number. So you have 128300.0
    • And finally you divide it by 10000. So you have 12.83 witch is the correct number!

    I hope this help you out! Cheers!!! ;) :)
     
    Wavinator and Deleted User like this.
  2. RiokuTheSlayer

    RiokuTheSlayer

    Joined:
    Aug 22, 2013
    Posts:
    356
    Floats are funny. I was just watching Far Lands Or Bust, and he crossed over a floating-point the other day.

    That's off-topic, sorry. Thanks for this! I'm sure it'll help some people around.
     
  3. Deleted User

    Deleted User

    Guest

    Thanks for sharing although sounds like a lot of work for such a small variation. :p
     
  4. dvirus1023

    dvirus1023

    Joined:
    Mar 4, 2013
    Posts:
    51
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    With rare exceptions, you should never rely on a floating-point number being exactly equal to anything. Even after using your call to "Round", the number is probably not really what you think it is, because floats only have so much precision and there are some numbers that they just can't represent perfectly.

    That's why Unity provides Mathf.Approximately.
     
    CodeMonke234 likes this.
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    In general, if the sort of logic you're using relies on A - B being exactly C, then float may well be the wrong data type, even if it seems natural.

    It's commonly used for dollars and cents, for example, dollars and cents ought to really be represented by an int (the number of cents) - when you display this to the user, you use a particular ToString variation to make it look like $1.23 instead of 123.

    When you System.DateTime functions, it doesn't store anything as floats, but rather as long ints - the number of ticks (IIRC 1/100,000th of a second) since a certain point in time. It handles time this way instead of with floating points because math with long ints is faster and more reliable (in a precision sense) than math with floats. 130000000 + 10 - 10 will always equal 130000000, and that is not necessarily the case with 13.0 + 0.0000010 - 0.0000010.

    Floats are best used for numbers that really are fluid in nature - where the functional difference between 12.999999 and 13.0 is essentially nonexistent. That's why they're used for situations like position, time, rotation, joystick axes, etc in Unity.

    Why doesn't system.DateTime use floats for time, then? Because the OS's clock will get in serious trouble if small errors creep in over time - this is generally not the case in games, and even when it is, Unity's Time.time is (I presume) derived from the systemwide, precisely reliable time anyway, so small errors don't get a chance to accumulate before the clock is synched back to the reliable master clock.
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    We always used the 'Decimal' type for money (https://msdn.microsoft.com/en-us/library/system.decimal(v=vs.110).aspx). Or created our own version of 'Decimal' if it doesn't exist. Where the fractional values are stored in base 10 instead of base 2.


    As for OP. Floats have error, check out this OLD article of mine from when years ago that goes into the Flash double float (note, .Net double uses the same double float that Flash uses. And the single float we use is just the 32-bit version of the same standard).

    Part 1 - http://www.lordofduct.com/blog/?p=90

    Part 2 - http://www.lordofduct.com/blog/?p=101
     
    Last edited: Apr 14, 2015
    StarManta likes this.
  8. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    Floating point values only have 32 bits of accuracy. Not every decimal value has an exact binary representation, which is what causes this loss of precision. Doubles are 64 bit and there are binary coded decimal libraries out there than can help maintain accuracy. 99.999998% (lol) of the time you're not going to experience any issues with this inaccuracy. Wait to deal with rounding until just before you display a value to the user. I wouldn't constantly round values within an equation unless you're going to be checking constantly that your value is less than 0.000001 off... but that's more costly than it's worth. Just accept the inaccuracies and only deal with it when it actually prevents a real issue, which it generally won't.

    Again, alternatives are
    double (but don't mix with floats -- I've been told this can cause super issues)
    Binary coded decimals.
    Deal with it. :)
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    mixing double with float won't cause 'super issues'.

    You'll have to cast a lot.

    And if you have a very large double (VERY large) and you cast it to float, you'll get an infinity.

    But other than that, not a big deal. Unity actually does this frequently. The .Net/Mono framework prefers doubles, so a lot of utility classes work with doubles. System.Math for instance. This is why UnityEngine.Mathf exists, it's really just a wrapper around System.Math that does the casting for you.

    If you decompile it you can see:

    Code (csharp):
    1.  
    2. using System;
    3. using System.Runtime.CompilerServices;
    4. using UnityEngine.Internal;
    5.  
    6. namespace UnityEngine
    7. {
    8.   public struct Mathf
    9.   {
    10.     public const float PI = 3.141593f;
    11.     public const float Infinity = float.PositiveInfinity;
    12.     public const float NegativeInfinity = float.NegativeInfinity;
    13.     public const float Deg2Rad = 0.01745329f;
    14.     public const float Rad2Deg = 57.29578f;
    15.     public const float Epsilon = 1.401298E-45f;
    16.  
    17.     public static float Sin(float f)
    18.     {
    19.       return (float) Math.Sin((double) f);
    20.     }
    21.  
    22.     public static float Cos(float f)
    23.     {
    24.       return (float) Math.Cos((double) f);
    25.     }
    26.  
    27.     public static float Tan(float f)
    28.     {
    29.       return (float) Math.Tan((double) f);
    30.     }
    31.  
    32.     public static float Asin(float f)
    33.     {
    34.       return (float) Math.Asin((double) f);
    35.     }
    36.  
    37.     public static float Acos(float f)
    38.     {
    39.       return (float) Math.Acos((double) f);
    40.     }
    41.  
    42.     public static float Atan(float f)
    43.     {
    44.       return (float) Math.Atan((double) f);
    45.     }
    46.  
    47. //... so on, so forth
    48.  
     
    jtsmith1287 likes this.
  10. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    I just wrote a program to calculate how accurate this is, and it said it was perfectly accurate. >.>
     
  11. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
     
    StarManta likes this.
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Or you ignore it. Floats are inaccurate. If you need accuracy use an int instead.