473,326 Members | 1,972 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,326 software developers and data experts.

C# double value precision is 42bit?

With the test I've made on my WinXP/VS2005/C#2.0,
I get a precision of 42bit. Is this specified in C# or dependent on what?

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;
double dFraction = Math.Pow(2, -42);
if (Math.Abs(dLeft - dRight) == dFraction) {
System.Console.WriteLine("Success");
}
// Output: Success
Jun 27 '08 #1
13 3113
On Jun 10, 11:50*am, StefanG <Stef...@discussions.microsoft.com>
wrote:
With the test I've made on my WinXP/VS2005/C#2.0,
I get a precision of 42bit. Is this specified in C# or dependent on what?

* * * double dLeft = 2183.23 - 695.37;
* * * double dRight = 1487.86;
* * * double dFraction = Math.Pow(2, -42);
* * * if (Math.Abs(dLeft - dRight) == *dFraction) {
* * * * System.Console.WriteLine("Success");
* * * }
* * *// Output: Success
What are you trying to test?
Jun 27 '08 #2
"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in news:e65dbd4f-cf6c-404e-
9f***************@f63g2000hsf.googlegroups.com:
Doubles in C# have a 52 bit mantissa and an 11 bit exponent (and a
sign bit). The exact precision of that depends on normalisation.
See http://pobox.com/~skeet/csharp/floatingpoint.html for more
information.
Got me googling and I found another nice writeup here:

http://www.extremeoptimization.com/r...tConceptsAndFo
rmats.aspx
Jun 27 '08 #3
Jon Skeet [C# MVP] wrote:
On Jun 10, 4:50 pm, StefanG <Stef...@discussions.microsoft.comwrote:
>With the test I've made on my WinXP/VS2005/C#2.0,
I get a precision of 42bit. Is this specified in C# or dependent on what?

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;
double dFraction = Math.Pow(2, -42);
if (Math.Abs(dLeft - dRight) == dFraction) {
System.Console.WriteLine("Success");
}
// Output: Success

I'm actually slightly disappointed that the two
numbers aren't identical.
When you think of it, it would be more disappointing if they always
were. You want the result to be the same when the compiler does the
subtraction and when it's done at runtime:

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;

double dLeft2 = 2183.23;
dLeft2 -= 695.37;

You want dLeft and dLeft2 to be equal, rather than dLeft and dRight.

--
Göran Andersson
_____
http://www.guffa.com
Jun 27 '08 #4
Göran Andersson <gu***@guffa.comwrote:
I'm actually slightly disappointed that the two
numbers aren't identical.
When you think of it, it would be more disappointing if they always
were. You want the result to be the same when the compiler does the
subtraction and when it's done at runtime:

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;

double dLeft2 = 2183.23;
dLeft2 -= 695.37;

You want dLeft and dLeft2 to be equal, rather than dLeft and dRight.
No - the compiler has more information available. It has the exact
decimal representation in the code, rather than the approximation to
doubles.

I'm sure I've seen this make a difference in the past, where the
compiler does the maths for the constant expression in a more precise
way than at runtime. I don't have an example to hand though.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Jun 27 '08 #5
"Ignacio Machin ( .NET/ C# MVP )" wrote:
On Jun 10, 11:50 am, StefanG <Stef...@discussions.microsoft.com>
wrote:
With the test I've made on my WinXP/VS2005/C#2.0,
I get a precision of 42bit. Is this specified in C# or dependent on what?

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;
double dFraction = Math.Pow(2, -42);
if (Math.Abs(dLeft - dRight) == dFraction) {
System.Console.WriteLine("Success");
}
// Output: Success

What are you trying to test?
In my unit tests, double.Epsilon does not work to compare double values, it
is too small. So I'm worried all my code is wrong. So I came up with the
example above.

In productive code it would be Math.Abs(d1-d2) <= double.Epsilon.

I've read about the double 52bit precision and read somewhere in the MSDN:
"[...] 15-17 digits precision [...]".

Jun 27 '08 #6
On Jun 11, 7:45 am, StefanG <Stef...@discussions.microsoft.comwrote:
What are you trying to test?

In my unit tests, double.Epsilon does not work to compare double values, it
is too small. So I'm worried all my code is wrong. So I came up with the
example above.

In productive code it would be Math.Abs(d1-d2) <= double.Epsilon.
That's very, very unlikely to produce a different result than if (d1 -
d2 == 0). The result of d1-d2 will only be double.Epsilon if both d1
and d2 are incredibly small.

What are you *really* trying to find out? If you want to know whether
their difference is within a certain tolerance, use that tolerance.
double.Epsilon is almost always inappropriate.
I've read about the double 52bit precision and read somewhere in the MSDN:
"[...] 15-17 digits precision [...]".
Yes, because you get 15-17 decimal digits of precision from 52 bits of
precision.

Jon
Jun 27 '08 #7


"Jon Skeet [C# MVP]" wrote:
On Jun 10, 4:50 pm, StefanG <Stef...@discussions.microsoft.comwrote:
With the test I've made on my WinXP/VS2005/C#2.0,
I get a precision of 42bit. Is this specified in C# or dependent on what?

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;
double dFraction = Math.Pow(2, -42);
if (Math.Abs(dLeft - dRight) == dFraction) {
System.Console.WriteLine("Success");
}
// Output: Success

It's not really clear to me why you expect your test to actually tell
you the precision of floating point numbers in C# or .NET. The
compiler is performing the arithmetic, rather than it being done at
execution time. [...]
In my unit tests I'm having the problem that comparing double values with
double.Epsion fails. I came up with the example that could lead to the idea
the mantissa is 42bit, because the rounding error is exactly 2^-42.
Anyway, I was unaware that the compiler performs some arithmetic.
Jun 27 '08 #8
Jon Skeet [C# MVP] wrote:
Göran Andersson <gu***@guffa.comwrote:
>>I'm actually slightly disappointed that the two
numbers aren't identical.
When you think of it, it would be more disappointing if they always
were. You want the result to be the same when the compiler does the
subtraction and when it's done at runtime:

double dLeft = 2183.23 - 695.37;
double dRight = 1487.86;

double dLeft2 = 2183.23;
dLeft2 -= 695.37;

You want dLeft and dLeft2 to be equal, rather than dLeft and dRight.

No - the compiler has more information available. It has the exact
decimal representation in the code, rather than the approximation to
doubles.

I'm sure I've seen this make a difference in the past, where the
compiler does the maths for the constant expression in a more precise
way than at runtime. I don't have an example to hand though.
Yes, the compiler has access to more precise information, but the point
is that it should not use it. As it's optimising away code by doing the
calculation at compile time instead of at runtime, the result should be
the same as it would be at runtime.

In this example it's rather obvious that the compiler will do the
calculation at compile time, but in other situations it may not be that
obvious, for example when one of the operands is a class member that may
or may not be cosntant. You have to be able to trust that the result
will be the same regardless if the calculation is done at compile time
or runtime.

--
Göran Andersson
_____
http://www.guffa.com
Jun 27 '08 #9
On Jun 11, 3:14 pm, Göran Andersson <gu...@guffa.comwrote:
I'm sure I've seen this make a difference in the past, where the
compiler does the maths for the constant expression in a more precise
way than at runtime. I don't have an example to hand though.

Yes, the compiler has access to more precise information, but the point
is that it should not use it. As it's optimising away code by doing the
calculation at compile time instead of at runtime, the result should be
the same as it would be at runtime.
I've just checked the spec, and this is actually the specified
behaviour (7.18):

<quote>
The compile-time evaluation of constant expressions uses the same
rules as run-time evaluation of non-constant expressions, except that
where run-time evaluation would have thrown an exception, compile-time
evaluation causes a compile-time error to occur.
</quote>

I'm pretty sure I've seen this not being the case, however. Will try
to reproduce when I get the time.
In this example it's rather obvious that the compiler will do the
calculation at compile time, but in other situations it may not be that
obvious, for example when one of the operands is a class member that may
or may not be cosntant. You have to be able to trust that the result
will be the same regardless if the calculation is done at compile time
or runtime.
There are lots of places where you won't get the same results
depending on how the compilation is achieved. Even putting extra
statements *after* the calculation can affect the result of the
calculation, based on whether the JIT can just use an 80 bit register
for the result, etc. Just a caveat, really.

Jon
Jun 27 '08 #10
"Jon Skeet [C# MVP]" wrote:
On Jun 11, 7:45 am, StefanG <Stef...@discussions.microsoft.comwrote:
What are you trying to test?
In my unit tests, double.Epsilon does not work to compare double values, it
is too small. So I'm worried all my code is wrong. So I came up with the
example above.

In productive code it would be Math.Abs(d1-d2) <= double.Epsilon.

That's very, very unlikely to produce a different result than if (d1 -
d2 == 0). The result of d1-d2 will only be double.Epsilon if both d1
and d2 are incredibly small.

What are you *really* trying to find out? If you want to know whether
their difference is within a certain tolerance, use that tolerance.
double.Epsilon is almost always inappropriate.
Thank you for your answers, I've marked the question to answered and I think
this is now a new question and although I don't know the answer it is
probably answered already:
What is the tolerance of double.Parse(string)?

In my real program I've written a unit test for a function:

void Process(double armPos) {
if (armPos>100) {
// Do something
} else {
// do something else
}
}

The unit test takes another execution path than the program that takes the
value from the user interface.
I hope we agree that for floating point comparisons you must check the
tolerance and "armPos>100" is a comparison.

Maybe I was wrong to assume that double.Parse(string) has something to do
with the precision of the double type?

Jun 27 '08 #11
On Jun 11, 3:40 pm, StefanG <Stef...@discussions.microsoft.comwrote:

<snip>
The unit test takes another execution path than the program that takes the
value from the user interface.
I hope we agree that for floating point comparisons you must check the
tolerance and "armPos>100" is a comparison.
I think I'd have to know *exactly* what you mean by tolerance in this
case. While equality comparisons should usually involve a certain
tolerance, for straight greater than / less than you don't usually
need to (although you can, of course).
Maybe I was wrong to assume that double.Parse(string) has something to do
with the precision of the double type?
Well, it's certainly related to the precision of double - but it's
also related to the current culture of the thread, and the rounding
applied as part of parsing.

What are the strings in question, in both your unit test and user
interface? If this is a number someone is typing in, is it definitely
appropriate for it to be a double rather than a decimal?

Jon
Jun 27 '08 #12
"Jon Skeet [C# MVP]" wrote:
On Jun 11, 3:40 pm, StefanG <Stef...@discussions.microsoft.comwrote:

<snip>
The unit test takes another execution path than the program that takes the
value from the user interface.
I hope we agree that for floating point comparisons you must check the
tolerance and "armPos>100" is a comparison.

I think I'd have to know *exactly* what you mean by tolerance in this
case. While equality comparisons should usually involve a certain
tolerance, for straight greater than / less than you don't usually
need to (although you can, of course).
What a would be the smallest possible tolerance for my function with double
comparison in it if I expect that always the same execution path is taken,
regardless if the function is called in a unit test with “Process(100.0)” or
called from the real application using double.Parse(string)?
I guess the answer is that the tolerance is problem domain specific anyway,
I must choose a reasonable tolerance (e.g. 10^-10).
Maybe I was wrong to assume that double.Parse(string) has something to do
with the precision of the double type?

Well, it's certainly related to the precision of double - but it's
also related to the current culture of the thread, and the rounding
applied as part of parsing.

What are the strings in question, in both your unit test and user
interface? If this is a number someone is typing in, is it definitely
appropriate for it to be a double rather than a decimal?
Decimal would work, but it not an option for me.
Jun 27 '08 #13
On Jun 13, 7:52 am, StefanG <Stef...@discussions.microsoft.comwrote:
I think I'd have to know *exactly* what you mean by tolerance in this
case. While equality comparisons should usually involve a certain
tolerance, for straight greater than / less than you don't usually
need to (although you can, of course).

What a would be the smallest possible tolerance for my function with double
comparison in it if I expect that always the same execution path is taken,
regardless if the function is called in a unit test with “Process(100.0)” or
called from the real application using double.Parse(string)?
I guess the answer is that the tolerance is problem domain specific anyway,
I must choose a reasonable tolerance (e.g. 10^-10).
So are you happy to treat the value as being 100.0 even if it's
actually 99.9999999999? If so, that's fine. Otherwise, it needs
further thought.

In some cases, I'd expect double.Parse(string) to accept a string like
"99.999999999999999999999999999999999" and convert that to 100.0. I
wouldn't expect it to ever convert a number beginning "100.0" to a
value less than 100.0. Note that you're in the happy situation where
100.0 is exactly representable.

This would make it easy if your logic were using >= instead of - but
I guess your tolerance here is really "how close to 100 can the value
be (from above) and still count as being greater than 100". Is that
fair to say?

Jon
Jun 27 '08 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

6
by: J | last post by:
Would anyone know if there a type tag to format a double? I have f for floating point, but cannot find one for double.
4
by: Jonathan Fielder | last post by:
Hi, My program (below) casts a double (which is in range for a float) to a float. As far as I know this should give me the nearest representable float, which will loose some precision. I...
31
by: Bjřrn Augestad | last post by:
Below is a program which converts a double to an integer in two different ways, giving me two different values for the int. The basic expression is 1.0 / (1.0 * 365.0) which should be 365, but one...
2
by: Ronny Mandal | last post by:
Is there a function that will do this task properly? -- Thanks Ronny Mandal
67
by: lcw1964 | last post by:
This may be in the category of bush-league rudimentary, but I am quite perplexed on this and diligent Googling has not provided me with a clear straight answer--perhaps I don't know how to ask the...
11
by: Ole Nielsby | last post by:
First, sorry if this is off-topic, not strictly being a C++ issue. I could not find a ng on numerics or serialization and I figure this ng is the closest I can get. Now the question: I want...
29
by: Virtual_X | last post by:
As in IEEE754 double consist of sign bit 11 bits for exponent 52 bits for fraction i write this code to print double parts as it explained in ieee754 i want to know if the code contain any...
206
by: md | last post by:
Hi Does any body know, how to round a double value with a specific number of digits after the decimal points? A function like this: RoundMyDouble (double &value, short numberOfPrecisions) ...
2
by: clintonb | last post by:
Victor said: The double value that I'm trying to convert to GCSMoney (which is implemented as cents) was produced by multiplying a dollar amount by an interest rate to get interest. double...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shćllîpôpď 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.