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. Dismiss Notice

0.05f - 0.05f = 3.72529E-09; I need some help.

Discussion in 'Scripting' started by KaseyW, Oct 27, 2015.

  1. KaseyW

    KaseyW

    Joined:
    Jun 6, 2013
    Posts:
    30
    I was trying to debug and figure out why I was unable to buy things in my game when the two values matched perfectly. I even wrote them out in 7 digit long floats and they looked perfect (0.0500000). But if I debug them subtracting one another I get the title of this thread. I've had this problem hundreds of times in my past with other languages, are there are any good ways to go about fixing this in C# or Unity special ways of dealing with it? I'm able to fix it buy making a function that does this:
    Code (CSharp):
    1.  
    2.     public bool CanBuyFactory(int index)
    3.     {
    4.         return Cash - GetFactoryCost(index) >= -0.009 ? true : false;
    5.     }
    6.  
    But I'd like to know if there is a better way to go about this because this seems a silly function to have to call for every time I buy something, I'd much rather the math just work.
     
    Last edited: Oct 27, 2015
  2. generatedname

    generatedname

    Joined:
    Sep 15, 2015
    Posts:
    7
    the first step is to change your "private void CanBuyFactory" to "private bool CanBuyFactory".

    But, to help skip this method:

    what is "Cash"? and what does the GetFactoryCost(int) method do/return?
     
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    In the case of buying things, the answer is simple: never use a float to store currency. If your money system has dollars and cents, store it as an 'int' representing the number of cents. If you need subdivisions below cent, then decide ahead of time how deep you want to allow those subdivisions, and stick with it. Floating point inaccuracy is a fact of life, and if that's a problem in a particular situation, you should reconsider whether a float is the right data type for that situation.
     
  4. KaseyW

    KaseyW

    Joined:
    Jun 6, 2013
    Posts:
    30
    I've thought about this before but always imagined it would build up a lot of memory usage.
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    You could also use 'decimal' data type which is designed to be accurate in base 10:
    https://msdn.microsoft.com/en-us/library/364x0z75.aspx

    Only downside is that it doesn't serialize. But you could serialize the data with int/float, and perform everything else as decimal.
     
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    In C#, an int and a float are both 4 bytes. int has a range from 0 to 4,294,967,295 (or, if using it as cents, $42,949,672.95). I think you'll be alright...

    (If you think it's possible that your player will have more than $43 million, then floats wouldn't help you anyway - it can only go that high by losing precision on the other end.)

    Also, these are minuscule amounts of memory we're talking about here. If you have to store a million prices, you'd still only be taking about as much memory as a single 512x512 texture.
     
    BenZed likes this.
  7. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    How many accounts are we talking about here? You'd be hard pressed to run out of memory at 4 bytes a pop.

    Adding to what StarManta is saying, if 43 million isn't enough, use long.

    8 byte long will give you a maximum of $92,233,720,368,547,758.07, which, according to google, is roughly 340 times the amount of money in the whole world.

    If 92 quadrillion dollars wont cut it, then your in-game currency is over-inflated.
     
    flonch and manpower13 like this.
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,195
    ... or you're creating a cookie clicker.
     
    KaseyW and Kiwasi like this.
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    You say that as if clicking cookies doesn't over-inflate currency...
     
  10. KaseyW

    KaseyW

    Joined:
    Jun 6, 2013
    Posts:
    30
    We got a winner. I am making an Incremental game I can not have my number be restricted to int32.max_value I need something bigger, and my default has always been float. I've looked into it though, are there any issues with using double?
     
  11. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,129
  12. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    float and double
    Float and double are similar, one is just 32-bit, the other 64-bit.

    They are both capable of storing fractional values. BUT, they're stored in binary. Many normal base 10 fractions are repeating values in binary. For instance 0.1 is 0.00011001100110011 repeating. Furthermore they have a smaller sig value range than the range of the number.

    There ranges are controlled by their bit depth as well, with float going as high as 3.4*10^38, and double going as far up as 1.7 * 10^308.

    BUT, even though they have a large range. They can't store a number that is both large and small at the same time. This is the sig value range.

    506000000000 has a sig value range of 3, the 506
    506000000000.1 has a sig vlaue range of 13, the entirity of the number

    Float has a sig value range of about 7 decimal digits (it's not exact because really it's 24 binary digits, which doesn't translate directly). And a double has a sig value range of just shy of 16 decimal digits (53 binary digits).

    If you need 'precision', these guys are NOT a good choice.
    These are great for fast arithmetic with fractional values and large ranges, when precision is not necessary. In a video game, we usually don't care about precision.

    int and long
    int and long are similar, one is just 32-bit, the other 64-bit

    They store only whole numbers though. No fractions. Because of this though, there is not exponential information for the floating value. This means their sig value gets to take up the entirity of the number.

    int gives you a little over 9 sig values
    long gives you a just shy of 19 sig values

    There are no precision issues, nor is their repeating value issues. This is primarily because you can't store fractional values.

    If you need precision, but don't need fractional values, these guys are your choice.

    decimal

    This guy is a bit of both worlds.

    It's a 128-bit floating point value. BUT it's exponential value is in base 10, as opposed to base 2 (binary).

    Furthermore, they don't let the exponent range float around as much. To maintain a range that is also in the precision range.

    As a result you get 28 digits of sig value, and an upper range 7.9 *10^28.
    If you required say 2 digits of fractional sig value (for money), you only get an upper restriction drop of 2 sig values. 7.9*10^26

    This means you get a larger range than long, but fractional values, all without the binary to decimal floating error (0.1 == 0.1 in decimal).

    Honeslty, in my opinion, for very large number storage that needs both precision and fractional values for things like money... this is the best option. The decimal type was chosen by Microsoft for money, and that's why its key symbol is M. And is based on the 64-bit version of it from VB6 called the 'Currency' data type.

    Code (csharp):
    1.  
    2. decimal value = 10.05M;
    3.  
    But unfortunately 'decimal' is not serializable by unity directly.

    You could of course write a serializable version, which I have one of here, with all the operators and conversion methods defined as well. So that way you can treat it like any other number.
    https://github.com/lordofduct/space...lob/master/SpacepuppyBase/FixedPercentLong.cs
    And the PropertyDrawer:
    https://github.com/lordofduct/space.../Inspectors/FixedPercentLongPropertyDrawer.cs

    Unfortunately the propertydrawer uses the double field, so the inspector is restricted back to double ranges. A more robust inspector could be written.
     
    Last edited: Oct 28, 2015
  13. KaseyW

    KaseyW

    Joined:
    Jun 6, 2013
    Posts:
    30
    Wonderful! Thank you very much!