Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

IL2CPP floating point precision issue

Discussion in 'iOS and tvOS' started by ColinAmuzo, Aug 11, 2015.

  1. ColinAmuzo

    ColinAmuzo

    Joined:
    Mar 20, 2013
    Posts:
    46
    Hi

    I'm using Unity 4.6.7.

    Code (CSharp):
    1. Vector2  a = new Vector2( -20.0071869f, 33.5500031f );
    2. float  b = Vector2.Dot( a, a );
    3. Debug.Log( "b=" + b );
    In editor (with platform set to Android...not sure if relevant), the result is "1525.89026".
    On iOS (iPhone 6) with IL2CPP back-end and Universal architecture, the result is "1525.89014".
    The real answer (from a high-precision calculator) is "1525.89023566154122".

    We have a bug on iOS which is due to this difference.
    The bug is not present in editor, or on Android.
    The bug is present on other iOS devices (iPhone 4S).
    The bug is not present on iOS with Mono back-end.

    There have been multiple occurrences of this bug, and I have been fixing them by increasing a zero-tolerance value, but the value is getting uncomfortably high now, and the bug is still occurring.

    Is there an explanation for the apparent inaccuracy when using IL2CPP?
    Is there a fix?

    Thanks.

    Colin
     
  2. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    @Colin4T2

    This is probably a bug in IL2CPP. Could you please submit a bug report via the Unity editor? We've seen a few similar problems recently, and we have some fixes nearly ready to be released. In the other cases, we ran into problem with the generated C++ code and various optimization settings and processor combinations.

    This does look different enough though that I think it might be a separate issue. If you do submit a bug report, can you please respond here with the bug number? Thanks.
     
  3. ColinAmuzo

    ColinAmuzo

    Joined:
    Mar 20, 2013
    Posts:
    46
    Thanks Josh

    I have just submitted a bug report (719582).

    It appears to have taken the first line of description as the bug title, which I didn't expect, so the bug title is not descriptive of the bug (just a reference to this forum thread).
     
  4. JoshPeterson

    JoshPeterson

    Unity Technologies

    Joined:
    Jul 21, 2014
    Posts:
    6,938
    @Colin4T2

    Thanks, I've passed this bug on to our QA team for an initial look. We will update you on its status via the bug report.
     
  5. rb.unity3d

    rb.unity3d

    Unity Technologies

    Joined:
    May 7, 2015
    Posts:
    4
    Hi Colin,

    32-bit floats generally only have a enough precision to represent 7 decimal digits. Are you sure your expectations here are reasonable? As far as I know, we do not guarentee floating point determinism to this degree across platforms.

    (I am not investigating this bug, just a remark in passing :))

    Best,
    rb
     
  6. ColinAmuzo

    ColinAmuzo

    Joined:
    Mar 20, 2013
    Posts:
    46
    Hi rb

    The context for the dot product was a pretty standard implementation of the GJK collision algorithm.

    The dot product was one a few calculations, the results of which get multiplied and added together, so any errors are amplified.

    When the bug occurs (on iOS with IL2CPP backend), an object is determined to not be overlapping another object, when it actually is. On Android, and in the editor, and on iOS with Mono backend, the object overlap is correctly determined. The overlap(s) going undetected means that some of my game objects are not initialised which affects the game greatly.

    I think my expectations are reasonable here. Although, I admit to not considering all the translations from language to language, but should we have to?

    Since this issue arose, I *think* I have found another instance of IL2CPP floating point inaccuracy. We are using NGUI, and some of our buttons are using gradient mapping, where a colour channel floating point 0-1 value is actually translated into an integer index into a colour array. NGUI doesn't know this is how we're using the colour value, so thinks it's reasonable to do an interpolation of the colour value when going from enabled to disabled state, rather than just set the value from enabled colour to disabled colour. This is fine on all platforms but iOS IL2CPP, where the interpolation occasionally doesn't reach the destination value, and the resultant value is interpreted as a different index, and a completely different colour. This is not such an issue for us as NGUI is open source and we can fix it by avoiding the interpolation on the gradient mapped buttons.
     
  7. joncham

    joncham

    Unity Technologies

    Joined:
    Dec 1, 2011
    Posts:
    276
    Colin,

    I've responded and resolved your bug but I'll respond here as well. The specific issue highlighted initially is an issue of single precision floating point operations. The CLR guarantees that all floating point operations will be *at least* as precise as the storage types. That means for floats you'll get at least single precision accuracy. Anything beyond that is implementation defined. In this case, Mono internally always does floating pointer operations as double precision and then truncates when storing back into the single precision float. IL2CPP does floating point calculations on single precision numbers without promoting to double precision. This results in a slightly different value. If you need to ensure double precision in your calculations please use a 'double' type.

    Thanks,
    Jonathan
     
  8. joncham

    joncham

    Unity Technologies

    Joined:
    Dec 1, 2011
    Posts:
    276
    Colin,

    Also, can you please file a separate bug for the NGUI issue?

    Thanks,
    Jonathan
     
  9. ColinAmuzo

    ColinAmuzo

    Joined:
    Mar 20, 2013
    Posts:
    46
    Hi Jonathan.

    So it's not a bug at all then! Fair enough.

    Thanks for investigating.

    I won't file a bug for the NGUI issue as we have a work-around.
     
  10. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,915
    Sorry for reviving this thread but I do think this could be a serious issue.

    So this:

    Code (CSharp):
    1. Vector2  a = new Vector2( -20.0071869f, 33.5500031f );
    2. float  b = Vector2.Dot( a, a );
    3.  
    Produces different results for b (in single precision in different platforms). How can it be? I mean, in this simple case, how could it be enforced to have the same result / behaviour when using IL2CPP? Will it be enough to use a custom Dot product function that uses doubles then truncates the result to float so it mimics Mono implementation? Will that work?
     
  11. ColinAmuzo

    ColinAmuzo

    Joined:
    Mar 20, 2013
    Posts:
    46
    Hi Thrawn75, IMO it's the inconsistency that's the main issue, so maybe an option would be using IL2CPP as the backend for all platforms (which may be possible now) and also for the editor. ie ditch the Mono runtime.

    Dunno how feasible that is though.
     
  12. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,915
    That would be a solution however it can also break Lot of existing behaviours.

    I can confirm that enforcing type casting to double between operators ensures consistency across platforms (code base tested on Mac, Android and iOS).
     
  13. aaronfranke

    aaronfranke

    Joined:
    Jan 23, 2017
    Posts:
    20
    @joncham Since Mono uses double-precision types internally anyway, why doesn't Unity switch to using doubles?

    The transition period can be done in C++ by using an abstract type such as "typedef float real_t;"
     
    Menion-Leah likes this.