Vector2 a = new Vector2( -20.0071869f, 33.5500031f );
float b = Vector2.Dot( a, a );
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?
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.
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).
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 :-))
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.
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.
Sorry for reviving this thread but I do think this could be a serious issue.
So this:
Vector2 a = new Vector2( -20.0071869f, 33.5500031f );
float b = Vector2.Dot( a, a );
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?
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.