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

Why is Mathf.RoundToInt unreliable?

Discussion in 'Scripting' started by Saucyminator, May 16, 2022.

  1. Saucyminator

    Saucyminator

    Joined:
    Nov 23, 2015
    Posts:
    61
    I'm trying to understand why my formula is off by 1, any mathwiz who can help me?

    Code (CSharp):
    1. Debug.Log(Mathf.RoundToInt(1.4f)); // = 1
    2. Debug.Log(Mathf.RoundToInt(1.5f)); // = 2
    3. Debug.Log(Mathf.RoundToInt(1.6f)); // = 2
    4.  
    5. // my formula, it should return 2 as above but returns 1
    6. Debug.Log(Mathf.RoundToInt(10 * (1f - 0.85f))); // = 1
    As per source https://docs.unity3d.com/ScriptReference/Mathf.RoundToInt.html
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Last edited: May 16, 2022
    Bunny83, apilatosba and Kurt-Dekker like this.
  3. Saucyminator

    Saucyminator

    Joined:
    Nov 23, 2015
    Posts:
    61
    Huh, TIL. What can I do to work around this problem?
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    In a vacuum? Nothing really. You'd have to explain how this is actually manifesting in your game and why it matters.
     
    Bunny83 and lordofduct like this.
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    What PraetorBlue said.

    For 95% of cases the inaccuracy of a float is not important. 4.9% of the time there's another way around it. And in that 0.1% of the time you just need perfect accuracy... you should use a different data type (for example decimal type for monetary calculations in the business world where the expectations of a base-10 system are not just expected but required by most law).

    In a video game being off by 1 pixel is seldom an issue.

    So... our question would be, why do this matter? What are you attempting to accomplish, and how is this impacting it? It's always good to include code.
     
    Bunny83 likes this.
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,525
    Right, that's the perfect analysis of the issue ^^. We have way too many questions here that try to reduce / isolate the problem which is a good idea when you are debugging and looking for the "cause" of an issue. However asking a question about general and well known behaviour usually don't get you very far. That's why it's better to focus on the actual goal when asking a question. That way we can actually address the specific usecase and either suggest alternatives or workarounds.
     
  7. Saucyminator

    Saucyminator

    Joined:
    Nov 23, 2015
    Posts:
    61
    I'm redesigning my health system so the offset is a difference between taking 1 damage or 2 damage (2 being correct value). My calculations are percent-based.

    Solved: I changed my formula to
    Mathf.RoundToInt(amount * (1f - resistancePercent + 0.01f));
    and now my tests pass.
     
    Last edited: May 17, 2022
  8. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    760
    A solution would also be the C# decimal type. However, not suitable for more complex calculations, as it is very slow.
     
  9. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530
    You have to be very careful with "solutions" like that unless you have fully analyzed the possible ranges and minimal step of all variables. As much as it helped you with one specific input, it can equally easy cause the result to be rounded wrong way with different numbers. Assuming resistance is in range 0-1 with 0.5 representing 50% , adding 0.01 could cause wrong rounding for something like 49% or 51%. Assuming amount can be larger than 100, that extra 0.01 will give you wrong result even before any rounding. But I can't know what the actual constraints for values in your code are.
     
  10. JoNax97

    JoNax97

    Joined:
    Feb 4, 2016
    Posts:
    611
    Have you thought about working with integers? Add 2 zeroes to all your numbers (equivalent as working with 2 decimals of precision) and make all your calculations using only integer math.

    That's what I usually do for my health systems and it works well.
     
    PraetorBlue, Bunny83 and DevDunk like this.