-1

I'm trying to create a system where numbers like 1,000 get converted over to 1k, 1,000,000 to 1m, etc. The code works great up until I input a number like 8,850,000. Instead of spitting out 8.85B, it spits out 8.849999B. Is this a quirk with Unity and or C#, or did I do something wrong in the code?

Edit: It wasn't the Mathf.Round function, it was the limitations of the float data type. I managed to fix the problem by using the decimal data type instead.

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI; 
using UnityEngine;

public class MoneyManager : MonoBehaviour
{
    public Text txt;
    private static float totalMoney;
    public float perClick;
    private float decimalMoney;
    private float roundedMoney;
    private string[] numberletter = new string[] { "K", "B", "T" };
    private string correctletter; 
    void Start()
    {
        CookieClick.clickAmount = perClick;
    }

    void Update()
    {
        totalMoney = CookieClick.money;
        roundedMoney = Mathf.Floor(Mathf.Log10(totalMoney));
        if(roundedMoney >= 3 && roundedMoney < 6)
        {
            correctletter = numberletter[0];
            decimalMoney = Mathf.Round(totalMoney/1000f * 100.0f) * 0.01f;
            Debug.Log(decimalMoney);
            txt.text = decimalMoney.ToString() + correctletter; 
        }
        else if(roundedMoney >= 6 && roundedMoney < 9)
        {
            correctletter = numberletter[1];
            Debug.Log(totalMoney);
            decimalMoney = Mathf.Round(totalMoney/1000000f * 100.0f) * 0.01f;
            Debug.Log(decimalMoney);
            txt.text = decimalMoney.ToString() + correctletter;
        }
        else
        {
            txt.text = totalMoney.ToString(); 
        }
    }
}
Qawler
  • 1
  • 3

2 Answers2

2

It's nothing to do with the rounding, it's just that a number like 8.85 can't be exactly represented as a float.

Floating point numbers are stored in "scientific notation" in base 2. If you write 8.85 in base 2 it's

1000.11011001100110011001100..._2 (repeating forever)

so in the computer this will be stored as

1.0001101100110011001100_2 x 2^3

where the "mantissa" on the left has been chopped off at 23 bits.

Because of this truncation of the binary expansion, the number that's actually stored is equal to

8.84999847412109375

in this case, and so when the computer converts it back to decimal to print it out in a human-readable form that's what you see.

This isn't anything special to the programming language; it's just how numbers work when you can only store so many places.

As Johan Donne mentions in the comments, you can instead instruct the computer to store this number as

885 x 10^(-2)

by using the decimal type instead of float; alternately, you could have taken that number 8.84999... above and rounded it to few enough places that it would have rounded up to 8.85.

Daniel McLaury
  • 4,047
  • 1
  • 15
  • 37
1

This is not caused by Math.Round but by the data type you are using: float stores the numbers with binary fractions. So float cannot always represent a decimal value exactly. Sometimes, when you amplificate the error by multplying with a large value and showing the result or when doing many chained calculations, these errors becomes visible.

Specifically to avoid those small errors, there is the datatype decimal which stores values with decimal fractions. Whenever you want exact results using decimal numbers (e.g. in financial calculations) you should use decimal and not float or double.

So, use decimal instead of float (for the literals as well. e.g. replace 100.0fwith 100.0m).

Note: Not only does decimal store decimal values without rounding errors (even after multiple chained calculations), it also has a much higher precision: 28 digits versus 15 digits in the case of double.

On the other hand, the range for decimal is smaller than is the case for double: see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types for an overview.

Johan Donne
  • 3,104
  • 14
  • 21