[Mono-list] Mono and .Net Floating Point Inconsistencies

ddambro ddambro at gmail.com
Sat Jan 17 21:32:58 EST 2009


Hi,

I was fairly sure the code had executed.  As I mentioned, different flags in
the C code caused errors in the program.  Just to be sure though, I threw in
some fprintf statements to stderr into setFloats() and they printed
properly, so the code was definitely executed.

Thankfully I have been able to come up with some code that shows at least
one example of the inconsistencies I've been talking about.  Here it is:

using System;

class Testing
{
    public static void Main()
    {
        float f1 = 0;
        f1 += -0.7779751f;
        Console.WriteLine(f1.ToString("R"));
        f1 += -1f * -1.42317927f;
        Console.WriteLine(f1.ToString("R"));
        f1 += -1.30905056f * 0.241778925f;
        Console.WriteLine(f1.ToString("R"));
        f1 = (2.0F / (1.0F + (float)Math.Exp(-4.9F * f1))) - 1.0F;
        Console.WriteLine(f1.ToString("R"));
    }
}

.NET gives me:
-0.7779751
0.6452042
0.328703344
0.667002261

While mono gives me:
-0.7779751
0.6452042
0.328703344
0.6670022

If I remove the roundtrip specifiers (the "R" in the toString() call) .NET
gives me:
-0.7779751
0.6452042
0.3287033
0.6670023

while mono gives:
-0.7779751
0.6452042
0.3287033
0.6670022

Also, if I take away the "- 1.0F" in the 2nd to last line, making it:
f1 = (2.0F / (1.0F + (float)Math.Exp(-4.9F * f1)));

Then both mono and .NET give me the same set of answers:
-0.7779751
0.6452042
0.328703344
1.6670022

I've run the same binary on .NET and both Windows and Linux mono (2.0.2) on
various computers and have consistently gotten these results.  The results
are the same on mono 2.2 on Linux as well.  Maybe it's some sort of
inconsistency in rounding, but in the other instances I've found (but
haven't explored to this depth) sometimes mono will round higher than .NET
and sometimes .NET will round higher.  I tried the other 3 rounding flags in
the FPU code (UP, DOWN, and ZERO) with my main code and while they each
produced different results, none of them matched the results I get with
.NET.  Any suggestions would be appreciated.

Thanks,
David


Kornél Pál wrote:
> 
> Hi,
> 
> DLLs are Windows specific are you sure you actually executed setFloats() 
>   on Linux?
> 
> If you are unable to solve this issue using control flags we can't 
> figure out what your problem is without providing us a test case that 
> exhibits this behavior.
> 
> Please create a source code (can be as small as your wish) that can be 
> compiled without modifications so that other people will be able to 
> reproduce the problem.
> 
> Kornél
> 
> ddambro wrote:
>> I tried the FPU flags as follows:
>> 1.Compiled the following file to a dll using gcc on a test linux system:
>> #include <fpu_control.h>
>> 
>> void setFloats()
>> {
>>         fpu_control_t desired = _FPU_MASK_DM | _FPU_MASK_UM |
>> _FPU_MASK_PM
>> |_FPU_DOUBLE | _FPU_RC_NEAREST ;
>>         _FPU_SETCW( desired);
>> }
>> 
>> 2.Added the following code to my main class in the C# code:
>> [DllImport("./floatTest.dll")]
>> public static extern void setFloats();
>> 
>> 3.Called setFloats() before any other code.
>> 
>> The end results were the exact same as all my other mono runs and thus
>> different than my .NET runs.  The C code without the masks caused my
>> program
>> to throw divided by zero exceptions from Console.Writeline() and
>> File.Exists().  Are there other flags I can try or does the fact that
>> this
>> happens on Windows mono and Linux mono point to something other than the
>> FPU
>> setup?  I'll keep looking for the exact spot where inconsistencies start
>> to
>> happen and just to try it, I'm compiling mono 2.2 on a test machine to
>> see
>> if that changes anything (everything so far has been on 2.0.2).
>> 
>> David
>> 
>> 
>> Kornél Pál wrote:
>>> Hi,
>>>
>>> Please try the FPU flags suggested John to see if that solves your 
>>> problem, modifying the control flags could be added to x86 versions of 
>>> Mono so you wouldn't have to modify them manually.
>>>
>>> Kornél
>>>
>>> ddambro wrote:
>>>> The code is compiled for x86 in Windows, and the problems I describe
>>>> persist
>>>> even using mono for Windows.  That is, on every computer I've tried so
>>>> far
>>>> regardless of OS and processor type, all of the mono runs produce the
>>>> same
>>>> results and all of the .NET runs produce the same results, but these
>>>> results
>>>> are different from each other.  This includes a 64-bit Vista machine
>>>> running
>>>> the x86 code in .NET and mono (installed as x86).  How would this
>>>> affect
>>>> your suggested fix?  Also I noticed a fairly significant speed up when
>>>> I
>>>> converted all my doubles to floats in this code a few years ago, would
>>>> your
>>>> fix undo that?  mono already runs the code MUCH slower than .NET so I'd
>>>> hate
>>>> to get another performance hit.
>>>>
>>>>
>>>> Dallman, John-2 wrote:
>>>>>> when I take the same binary and run it with the same inputs it 
>>>>>> produces different outputs if it is run on mono and .Net.
>>>>> This is with Mono on Linux, and .NET on Windows? The executable 
>>>>> is 32-bit .NET code? 
>>>>>
>>>>> I suspect that you've hit a misfeature that exists for most 
>>>>> floating-point code on 32-bit x86 Linux.
>>>>>
>>>>> The code to be run in the C function is:
>>>>>
>>>>> #include <fpu_control.h>    /* Mask the Denormal, Underflow and
>>>>> Inexact
>>>>> exceptions,
>>>>>         				leaving Invalid, Overflow and
>>>>> Zero-divide active.
>>>>> 				      Set precision to standard doubles,
>>>>> and round-to-nearest. */    
>>>>> fpu_control_t desired = _FPU_MASK_DM | _FPU_MASK_UM | _FPU_MASK_PM |
>>>>> _FPU_DOUBLE | _FPU_RC_NEAREST ;    
>>>>> _FPU_SETCW( desired);
>>>>>
>>>>> This needs to be a C function because everything in uppercase in 
>>>>> that code is a macro, from fpu_control.h. You may want to leave out 
>>>>> enabling floating point traps, in which case the code becomes:
>>>>>
>>>>> #include <fpu_control.h>    /* Set precision to standard doubles, and
>>>>> round-to-nearest. */    
>>>>> fpu_control_t desired =	_FPU_DOUBLE | _FPU_RC_NEAREST ;    
>>>>> _FPU_SETCW( desired);
>>>>>
>>>>> It would be good, really, if Mono had a standard call for setting 
>>>>> up consistent floating-point on all its platforms. 
>>>>>
>>>>> -- 
>>>>> John Dallman
>>>>> Parasolid Porting Engineer
>>>>>
>>>>> Siemens PLM Software
>>>>> 46 Regent Street, Cambridge, CB2 1DP
>>>>> United Kingdom
>>>>> Tel: +44-1223-371554
>>>>> john.dallman at siemens.com
>>>>> www.siemens.com/plm
>>>>> _______________________________________________
>>>>> Mono-list maillist  -  Mono-list at lists.ximian.com
>>>>> http://lists.ximian.com/mailman/listinfo/mono-list
>>>>>
>>>>>
>>> _______________________________________________
>>> Mono-list maillist  -  Mono-list at lists.ximian.com
>>> http://lists.ximian.com/mailman/listinfo/mono-list
>>>
>>>
>> 
> _______________________________________________
> Mono-list maillist  -  Mono-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list
> 
> 

-- 
View this message in context: http://www.nabble.com/Mono-and-.Net-Floating-Point-Inconsistencies-tp21428695p21523621.html
Sent from the Mono - General mailing list archive at Nabble.com.



More information about the Mono-list mailing list