Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
Developer Community or GitHub with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
This is similar to bug #15630 where the same tests fails using XS debugger (e.g. in the immediate pad).
This *works* when using the i386 JIT for the iOS simulator.
This *fails* when using the (default, non-LLVM) ARMv7 AOT compiler in Debug. LLVM and other options to be confirmed.
Test case committed on master be3ed2f7e8f0c8d697ffacac863aaaa4b91d7a6c
by default it won't execute on device (needs to comment that check to duplicate the issue)
ARMv7 (debug): fails
ARMv7 LLVM (release): fails
ARMv7 Thumb LLVM (release): fails
I have not looked at ARMv6 or ARMV7s.
This seems to be an ARM hardware quirk, see the 'Platform Notes' section here:
Interesting but [Single|Double].Epsilon *do* works for us. It's the negative of the values, e.g. `-Single.Epsilon`, that equals 0 (still it could be the same reason, maybe we're special casing the positive Epsilon somewhere ?).
I wonder what WinRT device reports for Epsilon and if we should match that ?!?
There's another note about:
<quote>The value of the Epsilon property is not equivalent to machine epsilon, which represents the upper bound of the relative error due to rounding in floating-point arithmetic.</quote>
so I expect WinRT has the same (.NET) constant values even if they are not really usable.
Not sure it needs/can be fixed, beside being documented on our side, but I'm still curious about the positive/negative differences.
> so I expect WinRT has the same (.NET) constant
> values even if they are not really usable.
We have the exact code working on Windows Phone 8 and Windows 8 Store apps that run on ARM devices. The only place the code did not function is on iOS.
So regardless of what the MSDN docs say, this does work on ARM devices on WinRT.
What code fails exactly ?
Console.WriteLine (Single.Epsilon == 0.0f);
Console.WriteLine (-Single.Epsilon == 0.0f);
Console.WriteLine (Single.Epsilon.Equals (0.0f));
Console.WriteLine ((-Single.Epsilon).Equals (0.0f));
and they all print false.
I enabled the tests in LinkAllTest.cs, and they pass too.
Interesting it works on my iPhone5S - but it fails on my iPod Touch 5th gen (armv7).
2013-10-30 12:52:32.762 linkall[759:60b] [FAIL] SingleEpsilon : Epsilon
Expected: not 0.0f
But was: 0.0f
2013-10-30 12:52:32.763 linkall[759:60b] at MonoTouchFixtures.LinkAllRegressionTest.SingleEpsilon () [0x00024] in /Developer/MonoTouch/Source/monotouch/tests/linkall/LinkAllTest.cs:299
2013-10-30 12:52:32.765 linkall[759:60b] at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object,System.Exception&)
2013-10-30 12:52:32.767 linkall[759:60b] at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object parameters, System.Globalization.CultureInfo culture) [0x00044] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:230
2013-10-30 12:52:32.631 linkall[759:60b] [FAIL] DoubleEpsilon : Epsilon
Expected: not 0.0f
But was: 4.9406564584124654E-324d
2013-10-30 12:52:32.633 linkall[759:60b] at MonoTouchFixtures.LinkAllRegressionTest.DoubleEpsilon () [0x00028] in /Developer/MonoTouch/Source/monotouch/tests/linkall/LinkAllTest.cs:311
2013-10-30 12:52:32.635 linkall[759:60b] at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object,System.Exception&)
2013-10-30 12:52:32.637 linkall[759:60b] at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object parameters, System.Globalization.CultureInfo culture) [0x00044] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:230
So specifically my original code was for a timer:
_time = Math.Max(_time - seconds, -Single.Epsilon);
The expected behavior was for the timer to stop when it was a little less than zero. On a Windows 8 Store game on ARM and x86 as well as Windows Phone game on ARM this code worked and _time would become less than zero. This code works regardless of what the MSDN docs say about ARM and Single.Epsilon.
It was on iOS where we noticed the timer was not working correctly and we found that _time was clamped to 0. Which was caused by -Single.Epsilon evaluating to 0 and not a small negative value.
We fix this temporarily by using our own constant of -0.0001f or something. The actual value didn't matter to us other than it was < 0.
Still it is a bug in the expected behavior for Single.Epsilon IMO.
I can repro on an ipad4, but not on an iphone5s. Will investigate.
So this is definitely a hw difference. We are executing these 4 instructions:
0x51460: 0xeeb42b43 vcmp.f64 d2, d3
0x51464: 0xeef1fa10 vmrs APSR_nzcv, fpscr
0x51468: 0x13a00000 movne r0, #0
0x5146c: 0x03a00001 moveq r0, #1
Here d2 is epsilon (0x1), and d3 is 0.0f (0x0). After this, r0 is set to 1 on an ipad4, and 0 on an iphone5s.
So different ARM CPU compare* epsilon differently with 0f ? fascinating
* compare or process ? that would explain the 2nd part of the test (which also works on the 5S).
2013-10-30 20:06:15.701 linkall[871:60b] [FAIL] SingleEpsilon : Epsilon.ToString()
Expected string length 12 but was 1. Strings differ at index 0.
But was: "0"
note: that diverge more (since it affects Epsilon, not just -Epsilon) from bug #15630 affecting the debugger (watch and immediate pads)
It turns out that Double.Epsilon.ToString() (and the negative version) works on my iPodTouch 5th gen (but Single does not). I split the test cases to make it easier to spot.
Anyway it does explain the MSDN warning - why it's there and why it's not always true (it probably was when written, e.g. .NET Compact Framework era).
I really don't know the rules to all this, but IMO the value of Single.Epsilon doesn't matter as long as it is the smallest representable value both positive and negative. This seems like a better default behavior than returning zero.
So as the MSDN documentation says, the value of Epsilon might not be distinguishable from zero. You should use some small constants like 0.00001 instead.
> So as the MSDN documentation says, the value of
> Epsilon might not be distinguishable from zero.
So basically... never use Single/Double.Epsilon as it is not a dependable mathematical epsilon as the name and documentation imply.
*** Bug 24808 has been marked as a duplicate of this bug. ***
*** Bug 39443 has been marked as a duplicate of this bug. ***