Bug 20793 - different floating point result on x64 vs armeabi-v7a
Summary: different floating point result on x64 vs armeabi-v7a
Status: RESOLVED INVALID
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler ()
Version: 4.12.4
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Jonathan Pryor
URL:
Depends on:
Blocks:
 
Reported: 2014-06-22 03:02 UTC by Rowan
Modified: 2014-06-30 20:52 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
windows and android test apps and the common test file (66.48 KB, application/octet-stream)
2014-06-30 01:18 UTC, Rowan
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and 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 Links.

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.

Related Links:
Status:
RESOLVED INVALID

Description Rowan 2014-06-22 03:02:56 UTC
different values are returned for the same double calculation

for example

var result = 6379850.0895406241 * -0.027094270027715802;
 
this gives a result -172857.38106236051 on full windows .Net 4.5 on windows 8.1 x64 
this gives a result -172857.38106236054 on armeabi-v7a using mono

I know it doesn't seem like a big deal but it is causing errors in my application and it would be great if it was possible to fix this.
Comment 1 Tajinder Singh 2014-06-23 03:31:09 UTC
I have checked this issue and but I am unable to reproduce this issue.

Steps to reproduce.

1. Create an "Android Application" on VS 2013
2. Paste the following line of code in OnCreate() method of "MainActivity.cs" file.
    
    var result = 6379850.0895406241 * -0.027094270027715802;

3. debug the application.
4. Check the value of variable "result"

When I run the above the above expression on "console application" of VIsual Studio 2013. I am getting the same output as mentioned in the bug description i.e. (-172857.38106236051) but when I check the result of same expression on Xamarin.Android I observed that I am not getting the same value as mentioned in the bug description.

I observed that xamarin.android is doing round off of that value after the decimal of eight digits. The result of above expression is  i.e.(-172857.381062361). 

Screencast: http://www.screencast.com/t/Nr17mUPG

Environment Info:

Microsoft Visual Studio Professional 2013
Version 12.0.21005.1 REL
Microsoft .NET Framework
Version 4.5.50938

Xamarin   3.0.54.0 (d3cf238e3845e930e312b6ec9b4c6c5437c33067)
Xamarin.Android   4.12.4.20 (b5dc5ce91305e19de51d71a1122c109719c4bc34)
Comment 2 Rowan 2014-06-23 04:12:35 UTC
I saw that it was rounding off the value when trying to view the value from the debugger but I assumed that it was just rounding for display purposes.

So as the Normal .net 4.5 was giving more decimal places I just saved the value to a file and then read that file in windows

So on ARM device use

        private static void Write()
        {
            var data = new byte[8];
            BitConverter.GetBytes(6379850.0895406241 * -0.027094270027715802).CopyTo(data, 0);
            var fs = new FileStream("test", FileMode.Create);
            fs.Write(data, 0, data.Length);
            fs.Close();
        }

Then copy that test file to windows, then on a windows app use the following to get the result displayed to more decimal places. 

private static void Read()
        {
            var data = new byte[8];
            var fs = new FileStream("test", FileMode.Open);
            fs.Read(data, 0, data.Length);
            fs.Close();
            var result = BitConverter.ToDouble(data, 0);
            result = result;
        }
Comment 3 Rowan 2014-06-23 04:25:37 UTC
sorry don't try that, it is giving the same result as windows, I will find a better example
Comment 4 Rowan 2014-06-23 06:26:26 UTC
This is very very strange, it only happens in my application, I save the values to disk using bitconverter (and extract them using bitconverter to confirm that the extracted value matches then saved value which it does so their is no error with bitconverter save/load)

I save the 2 values to be multiplied, then do the multiplication, then save the result also with bitconverter.

In my app I get differences from my xarmain app to the .net app.

But if I just create a sample app and load those saved bitconverter values to do the multiplication then it calculates the same value in both windows and android.

So for some reason their must be a preceding cause of this bug, as it works as expected when just this calculation is done, but not if the calculation is done in my app after it has done other execution. But I can't send you the source code to my app to repeat this as the company I work for will not allow it. So I have no idea what to do. 

Do you have any suggestions how I could reset the floating point processor some how?
Comment 5 Zoltan Varga 2014-06-29 22:07:16 UTC
Its hard to track this down without a test case. Does this also happen when running on armv6 ?
Comment 6 Rowan 2014-06-30 01:18:00 UTC
Created attachment 7230 [details]
windows and android test apps and the common test file
Comment 7 Rowan 2014-06-30 01:23:26 UTC
I have managed to get it repeatable, There is the very basic windows and android solutions attached. Please place the file "Tst" in a folder c:\\sdcard\\ the same for android, place the file in /sdcard/

The file tst just has the start values for the calculation, and it has the result of the calculation.

The app just takes the start values does some double calculations, then compares the result with the result that was saved to the file. (the value saved in the file was from the PC version)

If you run both apps you will notice on windows the line 

 if (fileVal != retValX) says that both are the same

however on android that line says that the 2 values are different.

Also the result is then written to the file "TstRslt"

If you do a compare of the file writting on windows to the file created on android you will notice they are different.
Comment 8 Zoltan Varga 2014-06-30 15:43:33 UTC
Thanks for the testcase.

This seems to be because of the difference between Math.Cos () on windows/osx and android. 
Math.Cos (latRad) returns different results on the two platforms, even through the argument passed to it is bit identical.

The following testcase shows the difference:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
			var argbits = new byte [] { 28, 132, 228, 171, 179, 238, 218, 191 };
            var arg = BitConverter.ToDouble(argbits, 0);
            var a8 = Math.Cos (arg);
            var b = BitConverter.GetBytes(a8);
			for (int i = 0; i < b.Length; ++i) {
				Console.Write (b [i]);
				Console.Write (", ");
			}
			Console.WriteLine ();
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
On osx, it prints:
48, 68, 202, 31, 73, 53, 237, 63, 
while on android, it prints:
49, 68, 202, 31, 73, 53, 237, 63

We implement Math.Cos () using the C 'cos' function on both platforms.
Comment 9 Rowan 2014-06-30 20:10:23 UTC
so I take it this means there is no way to make mono return the same result as .net for Math functions like this.
Comment 10 Rowan 2014-06-30 20:15:02 UTC
Any chance I could get a copy of the Cos/Sin/Tan/Atan2 implementation you guys use so I can implement this on Windows so that I can get the same result between both platforms.
Comment 11 Jonathan Pryor 2014-06-30 20:52:07 UTC
> Any chance I could get a copy of the Cos/Sin/Tan/Atan2 implementation you guys use

Mono doesn't have it's own IEEE implementation; it uses the OS-provided definitions. In theory, Android should be using Bionic, and Bionic uses e.g.:

https://github.com/android/platform_bionic/blob/master/libm/upstream-freebsd/lib/msun/src/s_cos.c

See the other libm/upstream-freebsd/lib/msun/src/*.c files for additional implementations.

Possibly relevant: What Every Computer Scientist Should Know About Floating Point Math:

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html