Home All Groups Group Topic Archive Search About

Why there are two diffrent result in two almost same formula

Author
10 Jun 2009 8:00 AM
XjAcKs
Hi everyone. My source code is the following in VS2005:

--------
        static void Main(string[] args)
        {
            int num = 3600;
            Single XNT = 0.3F;
            Single SX = 1546.08594F;

            Single result = (XNT * num) / SX;
            Single result2 = System.Convert.ToSingle(XNT * num) / SX;

            System.Console.WriteLine(result);
            System.Console.WriteLine(result2);
            return;
        }
--------

The result is "0.6985382", but the result2 is "0.6985381".
Why there are two diffrent result here?

When "XNT * num", because "XNT" is the type of Single, I think the system should
automatic convert the result to Single. But when I manually add the
"System.Convert.ToSingle()", the diffrent result appeared. Any idea?

Thank you!

Author
10 Jun 2009 8:16 AM
XjAcKs
Show quote Hide quote
> Hi everyone. My source code is the following in VS2005:
>
> --------
>         static void Main(string[] args)
>         {
>             int num = 3600;
>             Single XNT = 0.3F;
>             Single SX = 1546.08594F;
>
>             Single result = (XNT * num) / SX;
>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
>             System.Console.WriteLine(result);
>             System.Console.WriteLine(result2);
>             return;
>         }
> --------
>
> The result is "0.6985382", but the result2 is "0.6985381".
> Why there are two diffrent result here?
>
> When "XNT * num", because "XNT" is the type of Single, I think the system should
> automatic convert the result to Single. But when I manually add the
> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>
> Thank you!

Additional:

I just changed the variable "num" from int to Single. But I was shocked that the
two result is also diffrent.
(XNT * num) / SX -> 0.6985382
System.Convert.ToSingle(XNT * num) / SX -> 0.6985381

How? It confuse me very much...
Are all your drivers up to date? click for free checkup

Author
10 Jun 2009 8:51 AM
Peter Duniho
On Wed, 10 Jun 2009 01:16:40 -0700, XjAcKs <xja***@gmail.com> wrote:

Show quoteHide quote
> [...]
>> When "XNT * num", because "XNT" is the type of Single, I think the 
>> system should
>> automatic convert the result to Single. But when I manually add the
>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>
>> Thank you!
>
> Additional:
>
> I just changed the variable "num" from int to Single. But I was shocked 
> that the
> two result is also diffrent.
> (XNT * num) / SX -> 0.6985382
> System.Convert.ToSingle(XNT * num) / SX -> 0.6985381
>
> How? It confuse me very much...

I haven't had a chance to verify your results.  I do agree that, assuming 
the code actually does what you say it does, there's something odd going 
on.

But, I should point out that whatever is going on, it's not a question of 
whether or not the "system should automatically convert the results to 
Single".  The type of the expression "XNT * num" _is_ definitely Single.  
The only other implicit conversion that would even be allowed is Double, 
and a) that won't happen because there's no Double in the expression, and 
b) if it did happen, you'd be unable to assign the final result to a 
variable of type Single, because the whole expression would have wound up 
as a Double and an implicit conversion from Double back to Single isn't 
allowed (i.e. you would've had to put a cast, if the expression wasn't 
being done as a Single in the first place, so it must be getting evaluated 
as Single).

The thing that's weird is that the calculation is being performed 
differently, independent of the precision (which must be the same in 
either case), depending on context.  I don't have time to look at it now, 
and maybe by the time I do, someone else will have already figured it 
out.  But, one would expect that "XNT * num" would always produce the same 
value, and that for a given value, dividing by "SX" would also always 
produce the same value.

The only explanation for what you're seeing is that somewhere in there is 
an incorrect assumption.  To me, the most obvious suspect is the 
Convert.ToSingle() method, but the documentation claims that 
Convert.ToSingle(Single) always returns exactly the value that was passed 
to it.

And given all that, the most obviously explanation I see is that there's a 
compiler bug that is either choosing the wrong overload for the ToSingle() 
method (i.e. using ToSingle(Double), which could produce a subtle 
difference in the result), or is actually generating different IL simply 
because of the presence of the method call.  There is a more remote 
possibility that the ToSingle(Single) method does not in fact do what the 
documentation says it does.

In the meantime, you can look into those theories yourself if you like.  
ILDASM.EXE can show you the IL generated in your program, where you can 
look for specific differences in the code the compiler generates (i.e. 
differences in the calculations, or using a different method overload than 
one would expect given the code).  To check to see what ToSingle(Single) 
does, you'll either need to use Red Gate's Reflector (Google it) or 
configure your IDE to download the .NET source while debugging, and then 
step into the method.

I'm curious myself, so if there's not an answer twelve hours or so from 
now (when I'll actually have time to look at it myself), I'll see what I 
can figure out.

Finally, note that if it is a bug, it's possible it's been fixed since 
..NET 2.0/VS 2005 (depending on whether it's a framework or compiler bug).  
I'm only going to be able to test the code with .NET 3.5/VS 2008 at the 
moment, so one thing you might want to do is try to test it yourself on a 
more recent compiler and/or .NET version and see if it still happens.  
That would be a very useful data point.

Pete
Author
10 Jun 2009 9:19 AM
XjAcKs
Show quote Hide quote
> On Wed, 10 Jun 2009 01:16:40 -0700, XjAcKs <xja***@gmail.com> wrote:
>
>> [...]
>>> When "XNT * num", because "XNT" is the type of Single, I think the
>>> system should
>>> automatic convert the result to Single. But when I manually add the
>>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>>
>>> Thank you!
>>
>> Additional:
>>
>> I just changed the variable "num" from int to Single. But I was
>> shocked that the
>> two result is also diffrent.
>> (XNT * num) / SX -> 0.6985382
>> System.Convert.ToSingle(XNT * num) / SX -> 0.6985381
>>
>> How? It confuse me very much...
>
> I haven't had a chance to verify your results.  I do agree that,
> assuming the code actually does what you say it does, there's something
> odd going on.
>
>...
>
> Finally, note that if it is a bug, it's possible it's been fixed since
> .NET 2.0/VS 2005 (depending on whether it's a framework or compiler
> bug).  I'm only going to be able to test the code with .NET 3.5/VS 2008
> at the moment, so one thing you might want to do is try to test it
> yourself on a more recent compiler and/or .NET version and see if it
> still happens.  That would be a very useful data point.
>
> Pete

Thanks for you reply. My english is poor, so I will have to read your reply for
a while. If I find out something later, I will send a reply.

BTW: I just try the program in .NET 3.5/VS 2008, and the result the same as .NET
2.0/VS 2005, so I think it seems not a complier bug or it haven't been fixed.
Author
10 Jun 2009 9:35 AM
XjAcKs
Show quote Hide quote
>
>> On Wed, 10 Jun 2009 01:16:40 -0700, XjAcKs <xja***@gmail.com> wrote:
>>
>>> [...]
>>>> When "XNT * num", because "XNT" is the type of Single, I think the
>>>> system should
>>>> automatic convert the result to Single. But when I manually add the
>>>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>>>
>>>> Thank you!
>>>
>>> Additional:
>>>
>>> I just changed the variable "num" from int to Single. But I was
>>> shocked that the
>>> two result is also diffrent.
>>> (XNT * num) / SX -> 0.6985382
>>> System.Convert.ToSingle(XNT * num) / SX -> 0.6985381
>>>
>>> How? It confuse me very much...
>>
>> I haven't had a chance to verify your results.  I do agree that,
>> assuming the code actually does what you say it does, there's
>> something odd going on.
>>
>> ...
>>
>> Finally, note that if it is a bug, it's possible it's been fixed since
>> .NET 2.0/VS 2005 (depending on whether it's a framework or compiler
>> bug).  I'm only going to be able to test the code with .NET 3.5/VS
>> 2008 at the moment, so one thing you might want to do is try to test
>> it yourself on a more recent compiler and/or .NET version and see if
>> it still happens.  That would be a very useful data point.
>>
>> Pete
>
> Thanks for you reply. My english is poor, so I will have to read your
> reply for a while. If I find out something later, I will send a reply.
>
> BTW: I just try the program in .NET 3.5/VS 2008, and the result the same
> as .NET 2.0/VS 2005, so I think it seems not a complier bug or it
> haven't been fixed.

I just try my code in Java language, and the expression's result is the same
value: 0.6985381. So I think the expression with ToSingle() method is right...
Author
10 Jun 2009 9:52 AM
XjAcKs
>> Thanks for you reply. My english is poor, so I will have to read your
>> reply for a while. If I find out something later, I will send a reply.
>>
>> BTW: I just try the program in .NET 3.5/VS 2008, and the result the
>> same as .NET 2.0/VS 2005, so I think it seems not a complier bug or it
>> haven't been fixed.
>
> I just try my code in Java language, and the expression's result is the
> same value: 0.6985381. So I think the expression with ToSingle() method
> is right...

I think I have figured out out.
I changed the variables definition "result" and "result2" to Double and I delete
the "SX" in expression. And it is :

int num = 3600;
Single XNT = 0.3F;
Double result = XNT * num ;
Double result2 = System.Convert.ToSingle(XNT * num);

And, the value of two result is:
result -> 1080.00004291534
result2 -> 1080

It seems that Single is more better than Double here...
Author
10 Jun 2009 10:00 AM
XjAcKs
Show quote Hide quote
>>> Thanks for you reply. My english is poor, so I will have to read your
>>> reply for a while. If I find out something later, I will send a reply.
>>>
>>> BTW: I just try the program in .NET 3.5/VS 2008, and the result the
>>> same as .NET 2.0/VS 2005, so I think it seems not a complier bug or
>>> it haven't been fixed.
>>
>> I just try my code in Java language, and the expression's result is
>> the same value: 0.6985381. So I think the expression with ToSingle()
>> method is right...
>
> I think I have figured out out.
> I changed the variables definition "result" and "result2" to Double and
> I delete the "SX" in expression. And it is :
>
> int num = 3600;
> Single XNT = 0.3F;
> Double result = XNT * num ;
> Double result2 = System.Convert.ToSingle(XNT * num);
>
> And, the value of two result is:
> result -> 1080.00004291534
> result2 -> 1080
>
> It seems that Single is more better than Double here...

Single result = (XNT * num) / SX;
Single result2 = System.Convert.ToSingle(XNT * num) / SX;

So I think in the first expression, the result of "XNT * num" is a type of Double.

But why one Single variable multiply another Single variable, the result is a
type of Double? How weird it is...
Author
10 Jun 2009 12:05 PM
David
What happens if you change

Single result2 = System.Convert.ToSingle(XNT * num) / SX;

to

Single result2 = System.Convert.ToSingle((XNT * num) / SX);


?

First one, you are modifying the left side before dividing. Second one, you
are modifying the result. I would suggest the second one would be correct.

--
Best regards,
Dave Colliver.
http://www.AshfieldFOCUS.com
~~
http://www.FOCUSPortals.com - Local franchises available


Show quoteHide quote
"XjAcKs" <xja***@gmail.com> wrote in message
news:eb4IoIb6JHA.5756@TK2MSFTNGP02.phx.gbl...
>>>> Thanks for you reply. My english is poor, so I will have to read your
>>>> reply for a while. If I find out something later, I will send a reply.
>>>>
>>>> BTW: I just try the program in .NET 3.5/VS 2008, and the result the
>>>> same as .NET 2.0/VS 2005, so I think it seems not a complier bug or it
>>>> haven't been fixed.
>>>
>>> I just try my code in Java language, and the expression's result is the
>>> same value: 0.6985381. So I think the expression with ToSingle() method
>>> is right...
>>
>> I think I have figured out out.
>> I changed the variables definition "result" and "result2" to Double and I
>> delete the "SX" in expression. And it is :
>>
>> int num = 3600;
>> Single XNT = 0.3F;
>> Double result = XNT * num ;
>> Double result2 = System.Convert.ToSingle(XNT * num);
>>
>> And, the value of two result is:
>> result -> 1080.00004291534
>> result2 -> 1080
>>
>> It seems that Single is more better than Double here...
>
> Single result = (XNT * num) / SX;
> Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
> So I think in the first expression, the result of "XNT * num" is a type of
> Double.
>
> But why one Single variable multiply another Single variable, the result
> is a type of Double? How weird it is...
Author
11 Jun 2009 12:23 AM
XjAcKs
Show quote Hide quote
> What happens if you change
>
> Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
> to
>
> Single result2 = System.Convert.ToSingle((XNT * num) / SX);
>
>
> ?
>
> First one, you are modifying the left side before dividing. Second one, you
> are modifying the result. I would suggest the second one would be correct.
>

After did the change you said, the result is "0.6985382", the same value as the
expression without ToSingle().

But if I use calculator program of WindowsXP and manually input the formula
"(0.3 * 3600) / 1546.08594", the result is "0.69853814206472895031954045193633",
so I think it is correct modifying the left side before dividing by ToSingle().
Author
10 Jun 2009 4:52 PM
Peter Duniho
On Wed, 10 Jun 2009 03:00:49 -0700, XjAcKs <xja***@gmail.com> wrote:

> Single result = (XNT * num) / SX;
> Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
> So I think in the first expression, the result of "XNT * num" is a type 
> of Double.

That depends on what you mean by "is a type of Double".

Looking at the replies from Hans, I suspect that the difference can be 
explained by the compiler using storage of precision Double to do the 
calculation.  But, the expression is most definitely _not_ literally typed 
as Double; there are very specific type conversion rules in C# that would 
preclude treating the expression that way.

> But why one Single variable multiply another Single variable, the result 
> is a type of Double? How weird it is...

As Hans says, it may be more efficient to do the calculation using a 
higher-precision storage, effectively promoting the values to Double 
temporarily during the calculation.  Because the semantic type of the 
expression remains Single though, the compiler will wind up converting the 
result back to Single when storing it.

In the code you posted, assuming this behavior (I still don't have time to 
go check everything myself), that would readily explain why you get 
different results depending on at what step you force the conversion back 
to Single.  When you call Convert.ToSingle(), that forces the conversion 
to happen immediately after the multiplication.  When you don't, then the 
conversion can be delayed until after the division.  The potential for 
that to produce different results is obvious.

Pete
Author
11 Jun 2009 12:28 AM
XjAcKs
Show quote Hide quote
> That depends on what you mean by "is a type of Double".
>
> Looking at the replies from Hans, I suspect that the difference can be
> explained by the compiler using storage of precision Double to do the
> calculation.  But, the expression is most definitely _not_ literally
> typed as Double; there are very specific type conversion rules in C#
> that would preclude treating the expression that way.
>
>> But why one Single variable multiply another Single variable, the
>> result is a type of Double? How weird it is...
>
> As Hans says, it may be more efficient to do the calculation using a
> higher-precision storage, effectively promoting the values to Double
> temporarily during the calculation.  Because the semantic type of the
> expression remains Single though, the compiler will wind up converting
> the result back to Single when storing it.
>
> In the code you posted, assuming this behavior (I still don't have time
> to go check everything myself), that would readily explain why you get
> different results depending on at what step you force the conversion
> back to Single.  When you call Convert.ToSingle(), that forces the
> conversion to happen immediately after the multiplication.  When you
> don't, then the conversion can be delayed until after the division.  The
> potential for that to produce different results is obvious.
>
> Pete

By do some experiment and read your reply, finally I understood the reason why
the problem happend.

Pete, Hans, Thank you very much! It's very helpful.

XjAcKs
Author
11 Jun 2009 6:02 AM
Li Huan
On Jun 10, 5:52 pm, XjAcKs <xja***@gmail.com> wrote:
Show quoteHide quote
> >> Thanks for you reply. My english is poor, so I will have to read your
> >> reply for a while. If I find out something later, I will send a reply.
>
> >> BTW: I just try the program in .NET 3.5/VS 2008, and the result the
> >> same as .NET 2.0/VS 2005, so I think it seems not a complier bug or it
> >> haven't been fixed.
>
> > I just try my code in Java language, and the expression's result is the
> > same value: 0.6985381. So I think the expression with ToSingle() method
> > is right...
>
> I think I have figured out out.
> I changed the variables definition "result" and "result2" to Double and I delete
> the "SX" in expression. And it is :
>
> int num = 3600;
> Single XNT = 0.3F;
> Double result = XNT * num ;
> Double result2 = System.Convert.ToSingle(XNT * num);
>
> And, the value of two result is:
> result -> 1080.00004291534
> result2 -> 1080
>
> It seems that Single is more better than Double here...

I believe this is a wrong conclusion.

int num = 3600;
Single XNT = 0.3F;
Double result = XNT * num ;

1. num is converted into an 80-bit floating point.
2. XNT is converted into an 80-bit floating point.
   Since 0.3F cannot be represented precisely by a Single, the 80-bit
floating point will similarly be imprecise.
3. (80-bit)XNT * (80-bit)num results in an imprecise answer due to the
previous step.
4. The imprecise result in step 3 is stored into a Double. Since
double shows more decimal point then Single, the imprecise part is
shown.



int num = 3600;
Single XNT = 0.3F;
Double result2 = System.Convert.ToSingle(XNT * num);

Steps 1 to 3 are the same as previous.

1. num is converted into an 80-bit floating point.
2. XNT is converted into an 80-bit floating point.
   Since 0.3F cannot be represented precisely by a Single, the 80-bit
floating point will similarly be imprecise.
3. (80-bit)XNT * (80-bit)num results in an imprecise answer due to the
previous step.
4. The imprecise result in step 3 is converted into Single, truncating
the imprecise part.
5. The truncated result from step 4 is converted into Double, and
since 1080 can be stored precisely in a Single, converting it to
Double gives a precise result.

The conclusion will be that the 1st result appears imprecise due to
the imprecise 0.3F to start with.
Author
11 Jun 2009 7:05 AM
XjAcKs
Show quote Hide quote
> I believe this is a wrong conclusion.
>
> int num = 3600;
> Single XNT = 0.3F;
> Double result = XNT * num ;
>
> 1. num is converted into an 80-bit floating point.
> 2. XNT is converted into an 80-bit floating point.
>    Since 0.3F cannot be represented precisely by a Single, the 80-bit
> floating point will similarly be imprecise.
> 3. (80-bit)XNT * (80-bit)num results in an imprecise answer due to the
> previous step.
> 4. The imprecise result in step 3 is stored into a Double. Since
> double shows more decimal point then Single, the imprecise part is
> shown.
>
>
>
> int num = 3600;
> Single XNT = 0.3F;
> Double result2 = System.Convert.ToSingle(XNT * num);
>
> Steps 1 to 3 are the same as previous.
>
> 1. num is converted into an 80-bit floating point.
> 2. XNT is converted into an 80-bit floating point.
>    Since 0.3F cannot be represented precisely by a Single, the 80-bit
> floating point will similarly be imprecise.
> 3. (80-bit)XNT * (80-bit)num results in an imprecise answer due to the
> previous step.
> 4. The imprecise result in step 3 is converted into Single, truncating
> the imprecise part.
> 5. The truncated result from step 4 is converted into Double, and
> since 1080 can be stored precisely in a Single, converting it to
> Double gives a precise result.
>
> The conclusion will be that the 1st result appears imprecise due to
> the imprecise 0.3F to start with.

I think you spoke to the point. It is very helpful for me.
Thank you!
Author
17 Jun 2009 4:36 AM
Ben Voigt [C++ MVP]
> The thing that's weird is that the calculation is being performed
> differently, independent of the precision (which must be the same in
> either case), depending on context.  I don't have time to look at it now,
> and maybe by the time I do, someone else will have already figured it
> out.  But, one would expect that "XNT * num" would always produce the same
> value, and that for a given value, dividing by "SX" would also always
> produce the same value.

Besides forcing rounding as already noted elsewhere in this thread, there is
another potential difference:
Without the call to ToSingle, the calculation involves only variables which
have verifiably constant values.  So the compiler can perform constant
propagation, performing the calculation at compile time.  If the FPU setup
registers (such as rounding mode) are set differently by the compiler, you
could get very slightly different results.

But I also don't agree with the OP when he said he got two different
results.  The values of the two expressions are as equal as floating-point
numbers can get.

Show quoteHide quote
>
> The only explanation for what you're seeing is that somewhere in there is
> an incorrect assumption.  To me, the most obvious suspect is the
> Convert.ToSingle() method, but the documentation claims that
> Convert.ToSingle(Single) always returns exactly the value that was passed
> to it.
>
> And given all that, the most obviously explanation I see is that there's a
> compiler bug that is either choosing the wrong overload for the ToSingle()
> method (i.e. using ToSingle(Double), which could produce a subtle
> difference in the result), or is actually generating different IL simply
> because of the presence of the method call.  There is a more remote
> possibility that the ToSingle(Single) method does not in fact do what the
> documentation says it does.
>
> In the meantime, you can look into those theories yourself if you like.
> ILDASM.EXE can show you the IL generated in your program, where you can
> look for specific differences in the code the compiler generates (i.e.
> differences in the calculations, or using a different method overload than
> one would expect given the code).  To check to see what ToSingle(Single)
> does, you'll either need to use Red Gate's Reflector (Google it) or
> configure your IDE to download the .NET source while debugging, and then
> step into the method.
>
> I'm curious myself, so if there's not an answer twelve hours or so from
> now (when I'll actually have time to look at it myself), I'll see what I
> can figure out.
>
> Finally, note that if it is a bug, it's possible it's been fixed since
> .NET 2.0/VS 2005 (depending on whether it's a framework or compiler bug).
> I'm only going to be able to test the code with .NET 3.5/VS 2008 at the
> moment, so one thing you might want to do is try to test it yourself on a
> more recent compiler and/or .NET version and see if it still happens.
> That would be a very useful data point.
>
> Pete



__________ Information from ESET NOD32 Antivirus, version of virus signature database 4160 (20090616) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
Author
10 Jun 2009 8:33 AM
Hans Kesting
It happens that XjAcKs formulated :
Show quoteHide quote
> Hi everyone. My source code is the following in VS2005:
>
> --------
>         static void Main(string[] args)
>         {
>             int num = 3600;
>             Single XNT = 0.3F;
>             Single SX = 1546.08594F;
>
>             Single result = (XNT * num) / SX;
>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
>             System.Console.WriteLine(result);
>             System.Console.WriteLine(result2);
>             return;
>         }
> --------
>
> The result is "0.6985382", but the result2 is "0.6985381".
> Why there are two diffrent result here?
>
> When "XNT * num", because "XNT" is the type of Single, I think the system
> should automatic convert the result to Single. But when I manually add the
> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>
> Thank you!

Want even more scary things? Try this:

public class MyClass
{
    static float f;

    static float Sum (float f1, float f2)
    {
        return f1+f2;
    }

    public static void Main()
    {
        f = Sum (0.1f, 0.2f);
        float g = Sum (0.1f, 0.2f);
        Console.WriteLine (f==g);
        // uncomment the next line and run again:
        //Console.WriteLine (f==g);
        // or use only this writeline:
        //Console.WriteLine (f==(float)g);
        Console.ReadKey();
    }
}

Apparently the compiler can decide to keep float variables as regular
stack variables or as register variables. Those latter ones exist only
in the CPU and are stored in a different precision (80 bits as opposed
to 64 if I remember correctly). And the 80 bit representation of some
number will be different from the 64 bits version ...

Hans Kesting
Author
10 Jun 2009 9:00 AM
XjAcKs
Show quote Hide quote
> It happens that XjAcKs formulated :
>> Hi everyone. My source code is the following in VS2005:
>>
>> --------
>>         static void Main(string[] args)
>>         {
>>             int num = 3600;
>>             Single XNT = 0.3F;
>>             Single SX = 1546.08594F;
>>
>>             Single result = (XNT * num) / SX;
>>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>>
>>             System.Console.WriteLine(result);
>>             System.Console.WriteLine(result2);
>>             return;
>>         }
>> --------
>>
>> The result is "0.6985382", but the result2 is "0.6985381".
>> Why there are two diffrent result here?
>>
>> When "XNT * num", because "XNT" is the type of Single, I think the
>> system should automatic convert the result to Single. But when I
>> manually add the
>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>
>> Thank you!
>
> Want even more scary things? Try this:
>
> public class MyClass
> {
>     static float f;
>
>    static float Sum (float f1, float f2)
>    {
>        return f1+f2;
>    }
>
>     public static void Main()
>     {
>        f = Sum (0.1f, 0.2f);
>        float g = Sum (0.1f, 0.2f);
>        Console.WriteLine (f==g);
>         // uncomment the next line and run again:
>        //Console.WriteLine (f==g);
>         // or use only this writeline:
>        //Console.WriteLine (f==(float)g);
>         Console.ReadKey();
>     }
> }
>
> Apparently the compiler can decide to keep float variables as regular
> stack variables or as register variables. Those latter ones exist only
> in the CPU and are stored in a different precision (80 bits as opposed
> to 64 if I remember correctly). And the 80 bit representation of some
> number will be different from the 64 bits version ...
>
> Hans Kesting
>
>

Thanks for you reply. I read your reply and understand your meaning. But, I
haven't know how it happend in my program yet. I think the variables in my
program are all kept as regular stack variables because there are no "static"
defined...

XjAcKs
Author
10 Jun 2009 2:09 PM
Hans Kesting
XjAcKs wrote :
Show quoteHide quote
>> It happens that XjAcKs formulated :
>>> Hi everyone. My source code is the following in VS2005:
>>>
>>> --------
>>>         static void Main(string[] args)
>>>         {
>>>             int num = 3600;
>>>             Single XNT = 0.3F;
>>>             Single SX = 1546.08594F;
>>>
>>>             Single result = (XNT * num) / SX;
>>>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>>>
>>>             System.Console.WriteLine(result);
>>>             System.Console.WriteLine(result2);
>>>             return;
>>>         }
>>> --------
>>>
>>> The result is "0.6985382", but the result2 is "0.6985381".
>>> Why there are two diffrent result here?
>>>
>>> When "XNT * num", because "XNT" is the type of Single, I think the system
>>> should automatic convert the result to Single. But when I manually add the
>>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>>
>>> Thank you!
>>
>> Want even more scary things? Try this:
>>
>> public class MyClass
>> {
>>     static float f;
>>
>>    static float Sum (float f1, float f2)
>>    {
>>        return f1+f2;
>>    }
>>
>>     public static void Main()
>>     {
>>        f = Sum (0.1f, 0.2f);
>>        float g = Sum (0.1f, 0.2f);
>>        Console.WriteLine (f==g);
>>         // uncomment the next line and run again:
>>        //Console.WriteLine (f==g);
>>         // or use only this writeline:
>>        //Console.WriteLine (f==(float)g);
>>         Console.ReadKey();
>>     }
>> }
>>
>> Apparently the compiler can decide to keep float variables as regular stack
>> variables or as register variables. Those latter ones exist only in the CPU
>> and are stored in a different precision (80 bits as opposed to 64 if I
>> remember correctly). And the 80 bit representation of some number will be
>> different from the 64 bits version ...
>>
>> Hans Kesting
>>
>>
>
> Thanks for you reply. I read your reply and understand your meaning. But, I
> haven't know how it happend in my program yet. I think the variables in my
> program are all kept as regular stack variables because there are no "static"
> defined...
>
> XjAcKs

It doesn't have to be a static variable. It's just that the compiler
may decide to have some variables as 64 bit stack variables while
others (the short-lived ones I presume) can be 80 bit register
variables.
But I don't understand the workings of the compiler enough to make an
example without the static variable.

Hans Kesting
Author
11 Jun 2009 12:29 AM
XjAcKs
Show quote Hide quote
> XjAcKs wrote :
>>> It happens that XjAcKs formulated :
>>>> Hi everyone. My source code is the following in VS2005:
>>>>
>>>> --------
>>>>         static void Main(string[] args)
>>>>         {
>>>>             int num = 3600;
>>>>             Single XNT = 0.3F;
>>>>             Single SX = 1546.08594F;
>>>>
>>>>             Single result = (XNT * num) / SX;
>>>>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>>>>
>>>>             System.Console.WriteLine(result);
>>>>             System.Console.WriteLine(result2);
>>>>             return;
>>>>         }
>>>> --------
>>>>
>>>> The result is "0.6985382", but the result2 is "0.6985381".
>>>> Why there are two diffrent result here?
>>>>
>>>> When "XNT * num", because "XNT" is the type of Single, I think the
>>>> system should automatic convert the result to Single. But when I
>>>> manually add the
>>>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>>>
>>>> Thank you!
>>>
>>> Want even more scary things? Try this:
>>>
>>> public class MyClass
>>> {
>>>     static float f;
>>>
>>>    static float Sum (float f1, float f2)
>>>    {
>>>        return f1+f2;
>>>    }
>>>
>>>     public static void Main()
>>>     {
>>>        f = Sum (0.1f, 0.2f);
>>>        float g = Sum (0.1f, 0.2f);
>>>        Console.WriteLine (f==g);
>>>         // uncomment the next line and run again:
>>>        //Console.WriteLine (f==g);
>>>         // or use only this writeline:
>>>        //Console.WriteLine (f==(float)g);
>>>         Console.ReadKey();
>>>     }
>>> }
>>>
>>> Apparently the compiler can decide to keep float variables as regular
>>> stack variables or as register variables. Those latter ones exist
>>> only in the CPU and are stored in a different precision (80 bits as
>>> opposed to 64 if I remember correctly). And the 80 bit representation
>>> of some number will be different from the 64 bits version ...
>>>
>>> Hans Kesting
>>>
>>>
>>
>> Thanks for you reply. I read your reply and understand your meaning.
>> But, I haven't know how it happend in my program yet. I think the
>> variables in my program are all kept as regular stack variables
>> because there are no "static" defined...
>>
>> XjAcKs
>
> It doesn't have to be a static variable. It's just that the compiler may
> decide to have some variables as 64 bit stack variables while others
> (the short-lived ones I presume) can be 80 bit register variables.
> But I don't understand the workings of the compiler enough to make an
> example without the static variable.
>
> Hans Kesting
>
>

OK, I will remember it. Thank you, Hans.

XjAcKs
Author
11 Jun 2009 3:06 AM
kndg
Hi XjAcKs,

The precision for Single (float) type is 7 digits (you are using more
than that). If you change SX to 1546.086F, the program will behave
correctly.
If you need more precision, use double.

Regards.

XjAcKs wrote:
Show quoteHide quote
> Hi everyone. My source code is the following in VS2005:
>
> --------
>         static void Main(string[] args)
>         {
>             int num = 3600;
>             Single XNT = 0.3F;
>             Single SX = 1546.08594F;
>
>             Single result = (XNT * num) / SX;
>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
>             System.Console.WriteLine(result);
>             System.Console.WriteLine(result2);
>             return;
>         }
> --------
>
> The result is "0.6985382", but the result2 is "0.6985381".
> Why there are two diffrent result here?
>
> When "XNT * num", because "XNT" is the type of Single, I think the system should
> automatic convert the result to Single. But when I manually add the
> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>
> Thank you!
Author
11 Jun 2009 7:13 AM
XjAcKs
Hi kndg,

Thank you for you advise. But in my program, "1546.08594F" has some meaning and
can't change it to 1546.086F.
I think it is better to use Double instead of Snigle.


Show quoteHide quote
> Hi XjAcKs,
>
> The precision for Single (float) type is 7 digits (you are using more
> than that). If you change SX to 1546.086F, the program will behave
> correctly.
> If you need more precision, use double.
>
> Regards.
>
> XjAcKs wrote:
>> Hi everyone. My source code is the following in VS2005:
>>
>> --------
>>         static void Main(string[] args)
>>         {
>>             int num = 3600;
>>             Single XNT = 0.3F;
>>             Single SX = 1546.08594F;
>>
>>             Single result = (XNT * num) / SX;
>>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>>
>>             System.Console.WriteLine(result);
>>             System.Console.WriteLine(result2);
>>             return;
>>         }
>> --------
>>
>> The result is "0.6985382", but the result2 is "0.6985381".
>> Why there are two diffrent result here?
>>
>> When "XNT * num", because "XNT" is the type of Single, I think the system should
>> automatic convert the result to Single. But when I manually add the
>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>
>> Thank you!
Author
11 Jun 2009 5:46 AM
Li Huan
On Jun 10, 4:00 pm, XjAcKs <xja***@gmail.com> wrote:
Show quoteHide quote
> Hi everyone. My source code is the following in VS2005:
>
> --------
>         static void Main(string[] args)
>         {
>             int num = 3600;
>             Single XNT = 0.3F;
>             Single SX = 1546.08594F;
>
>             Single result = (XNT * num) / SX;
>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>
>             System.Console.WriteLine(result);
>             System.Console.WriteLine(result2);
>             return;
>         }
> --------
>
> The result is "0.6985382", but the result2 is "0.6985381".
> Why there are two diffrent result here?
>
> When "XNT * num", because "XNT" is the type of Single, I think the system should
> automatic convert the result to Single. But when I manually add the
> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>
> Thank you!

On Intel processors, Single is first converted into an 80-bit
precision floating-point before calculation.

The statement
Single result = (XNT * num) / SX;
would be doing an 80-bit XNT * 80-bit num / 80-bit SX, then converting
it back to 32-bit Single.

The statement
Single result2 = System.Convert.ToSingle(XNT * num) / SX;
would instead be
80-bit XNT * 80-bit num, then convert to Single
Pass the 32-bit Single into System.Convert.ToSingle
Then convert the result into 80-bit and divide by 80-bit SX, then
converting back to Single.

The 2nd case would have introduced more errors.

BTW, you might consider using Double since Intel processors calculate
Double directly (no conversion into 80-bit floating point), and so
should run faster.
Author
11 Jun 2009 6:27 AM
kndg
Hi Li Huan,

Using SAME Intel machine, the expression

(XNT * num) / SX

will return
0.6985382 on .NET
0.6985381 on JAVA

Can you explain this behaviour?
Maybe someone who have Mono and/or Java on Linux machine can post their
result here...

Li Huan wrote:
Show quoteHide quote
> On Jun 10, 4:00 pm, XjAcKs <xja***@gmail.com> wrote:
>> Hi everyone. My source code is the following in VS2005:
>>
>> --------
>>         static void Main(string[] args)
>>         {
>>             int num = 3600;
>>             Single XNT = 0.3F;
>>             Single SX = 1546.08594F;
>>
>>             Single result = (XNT * num) / SX;
>>             Single result2 = System.Convert.ToSingle(XNT * num) / SX;
>>
>>             System.Console.WriteLine(result);
>>             System.Console.WriteLine(result2);
>>             return;
>>         }
>> --------
>>
>> The result is "0.6985382", but the result2 is "0.6985381".
>> Why there are two diffrent result here?
>>
>> When "XNT * num", because "XNT" is the type of Single, I think the system should
>> automatic convert the result to Single. But when I manually add the
>> "System.Convert.ToSingle()", the diffrent result appeared. Any idea?
>>
>> Thank you!
>
> On Intel processors, Single is first converted into an 80-bit
> precision floating-point before calculation.
>
> The statement
> Single result = (XNT * num) / SX;
> would be doing an 80-bit XNT * 80-bit num / 80-bit SX, then converting
> it back to 32-bit Single.
>
> The statement
> Single result2 = System.Convert.ToSingle(XNT * num) / SX;
> would instead be
> 80-bit XNT * 80-bit num, then convert to Single
> Pass the 32-bit Single into System.Convert.ToSingle
> Then convert the result into 80-bit and divide by 80-bit SX, then
> converting back to Single.
>
> The 2nd case would have introduced more errors.
>
> BTW, you might consider using Double since Intel processors calculate
> Double directly (no conversion into 80-bit floating point), and so
> should run faster.
Author
11 Jun 2009 5:26 PM
Peter Duniho
On Wed, 10 Jun 2009 23:27:52 -0700, kndg <reply@this.newsgroup> wrote:

> Hi Li Huan,
>
> Using SAME Intel machine, the expression
>
> (XNT * num) / SX
>
> will return
> 0.6985382 on .NET
> 0.6985381 on JAVA
>
> Can you explain this behaviour?

Note that the Java result is identical to the result you get if at each 
step of the calculation, the precision is 32-bit float (i.e. "Single" or 
"float").  Note also that Java, unlike .NET/C#, may sometimes execute code 
as interpreted.  .NET will always JIT-compile your IL code to native 
before executing it.  Since .NET is always executing the code as native, 
it has the luxury of being able to do things like promote the data type 
without introducing inconsistent results within the same execution 
session.  If Java's JIT compiler were to promote the type, then the code 
could produce different results during the interpreted execution of the 
code than during the compiled execution of the code.

Java _could_ address that by specifying the interpreter to do the same 
promotion, but then the promotion would have to happen on ALL platforms, 
and it's not necessarily the case that promoting to 64-bit float produces 
the same performance boost on all platforms.  Such a requirement on the 
interpreter could interfere with the compiler's ability to general optimal 
code.

The above is all speculation.  It's entirely possible that the only reason 
there's a difference in Java is a completely arbitrary decision on the 
part of those who implemented .NET and those who implemented Java.

Finally, you should keep in mind that this entire message thread is purely 
academic curiosity.  If you have some program requirement that 
calculations produce exact results, then neither Single/float nor 
Double/double are appropriate.  That's just not something those floating 
point types provide.

Pete
Author
12 Jun 2009 12:36 AM
XjAcKs
> Finally, you should keep in mind that this entire message thread is
> purely academic curiosity.  If you have some program requirement that
> calculations produce exact results, then neither Single/float nor
> Double/double are appropriate.  That's just not something those floating
> point types provide.
>
> Pete

I am curious to know if I have a program requirement that calculations produce
exact results, which should I use?
Author
12 Jun 2009 1:46 AM
Peter Duniho
On Thu, 11 Jun 2009 17:36:52 -0700, XjAcKs <xja***@gmail.com> wrote:

>> Finally, you should keep in mind that this entire message thread is 
>> purely academic curiosity.  If you have some program requirement that 
>> calculations produce exact results, then neither Single/float nor 
>> Double/double are appropriate.  That's just not something those 
>> floating point types provide.
>>  Pete
>
> I am curious to know if I have a program requirement that calculations 
> produce exact results, which should I use?

It depends on the nature of those exact results.

If you need floating point results that can always be represented as 
decimal, then the Decimal type will work.  Note that even with Decimal, 
there are values that can't be represented exactly (e.g. 1/3).  But for a 
lot of applications, it's fine.

If you need to represent arbitrary fractions, then you'll have to create 
your own fractional type (or find an implementation someone else has 
already made).  There's nothing built into .NET that does that.

Note that one possibility is that you only _think_ you need exact results, 
and that in fact you really don't.  You should consider that seriously 
before you complicate your life.  :)

Pete
Author
13 Jun 2009 6:07 AM
Tim Roberts
XjAcKs <xja***@gmail.com> wrote:

>> Finally, you should keep in mind that this entire message thread is
>> purely academic curiosity.  If you have some program requirement that
>> calculations produce exact results, then neither Single/float nor
>> Double/double are appropriate.  That's just not something those floating
>> point types provide.
>
>I am curious to know if I have a program requirement that calculations produce
>exact results, which should I use?

None of the above.  Floating point arithmetic NEVER produces exact results.
That's just the nature of floating point arithmetic.  It's an
approximation.

You've already seen this.  You wrote the number 1546.08594, but that number
**CANNOT** be represented exactly as a floating point value.  In binary,
that number is an infinitely repeating fraction.  It doesn't matter how
many bits you use, the floating point representation will ALWAYS be an
approximation.  It's exactly the same as if I asked you to write down the
EXACT decimal representation of 1/3.  It can't be done.

However, that's OK, because the number 1546.08594 is itself obviously an
approximation.  The KEY QUESTION you need to ask is, "how many digits/bits
of precision do I have to begin with?"  If that number was really measured
to 9 digits of accuracy (which is highly doubtful), then you might need to
consider doubles.  They maintain about 15 digits.

Further, every computation you do reduces the accuracy more and more. There
are plenty of books and web sites that describe numerical analysis with
floating point numbers.  You just need to be aware.
--
Tim Roberts, t***@probo.com
Providenza & Boekelheide, Inc.

Bookmark and Share