double type problem

  • Thread starter Thread starter Kürþat
  • Start date Start date
K

Kürþat

Hi,

I have a strange problem about a simple sum operation on a double variable.
There is a loop in my application like this :

double _max = 0.4;
double _step = 0.1;

for (double d = 0.0; i < _max || double_equal (i, _max); i += step)
{
// Do something...
}

double_equal() is an epsilon based equality test function.

The problem is i's value on 4. turn. When I watch I see 0.30000000000000004
insted of 0.3
This is problematic because I compare it some other doubles in the loop but
even epsilon based approximitation will fail in this case.

It is interesting that this only appears on loop's 4. turn. On 5.turn the
value is 0.4, excellent!

What is the reason and how can I overcome this?

Thanks in advance.
 
Kürþat said:
I have a strange problem about a simple sum operation on a double variable.
There is a loop in my application like this :

double _max = 0.4;
double _step = 0.1;

for (double d = 0.0; i < _max || double_equal (i, _max); i += step)
{
// Do something...
}

double_equal() is an epsilon based equality test function.

The problem is i's value on 4. turn. When I watch I see 0.30000000000000004
insted of 0.3
This is problematic because I compare it some other doubles in the loop but
even epsilon based approximitation will fail in this case.

Sounds like your epsilon is too small then.
It is interesting that this only appears on loop's 4. turn. On 5.turn the
value is 0.4, excellent!

What is the reason and how can I overcome this?

See http://pobox.com/~skeet/csharp/floatingpoint.html and
http://pobox.com/~skeet/csharp/decimal.html
 
I used the Epsilon provided by the double class and expected deviations
related to the double arithmetics will fall the range that this provided
epsilon determines.

It seems I should determine an appropriate epsilon value instead of relying
on the provided epsilon.

Kürþat said:
I have a strange problem about a simple sum operation on a double
variable.
There is a loop in my application like this :

double _max = 0.4;
double _step = 0.1;

for (double d = 0.0; i < _max || double_equal (i, _max); i += step)
{
// Do something...
}

double_equal() is an epsilon based equality test function.

The problem is i's value on 4. turn. When I watch I see
0.30000000000000004
insted of 0.3
This is problematic because I compare it some other doubles in the loop
but
even epsilon based approximitation will fail in this case.

Sounds like your epsilon is too small then.
It is interesting that this only appears on loop's 4. turn. On 5.turn the
value is 0.4, excellent!

What is the reason and how can I overcome this?

See http://pobox.com/~skeet/csharp/floatingpoint.html and
http://pobox.com/~skeet/csharp/decimal.html
 
Kürsat said:
I used the Epsilon provided by the double class and expected deviations
related to the double arithmetics will fall the range that this provided
epsilon determines.

It seems I should determine an appropriate epsilon value instead of relying
on the provided epsilon.

Yes. If you look at the documentation for double.Epsilon you'll see why
it's really not suitable for this kind of use.
 
I used the Epsilon provided by the double class and expected deviations
related to the double arithmetics will fall the range that this provided
epsilon determines.

MSDN has this to say on Double.Epsilon:

"If you create a custom algorithm that determines whether two floating-
point numbers can be considered equal, you must use a value that is
greater than the Epsilon constant to establish the acceptable absolute
margin of difference for the two values to be considered equal.
(Typically, that margin of difference is many times greater than
Epsilon.)"

I don't see why you don't just use <= in your specific case here,
since the number will fall in the range you require... but if you
really need it, you'd probably want to just use decimal (it has
similar issues as well, but they're more predictable because it's
decimal and not binary - so you can be sure that any decimal number is
represented exactly as you wrote it).
 
To see why the "<=" operator would not be appropriate let's look at an
example:

I want to add numbers between 0.0-0.3 stepping 0.1 (0.0, 0.1, 0.2, 0.3) to a
listbox:

double _start = 0.0;
double _end = 0.3;
double _step = 0.1;

for (double d = _start; d <= _end; d+=_step)
{
lb.Items.Add (d.ToSting());
}

This adds "0.0", "0.1" and "0.2" to the ListBox but not "0.3" bacause on 4.
turn, d contains the value 0.30000000000000004 which is neither less than
nor equal to 0.3.


I used the Epsilon provided by the double class and expected deviations
related to the double arithmetics will fall the range that this provided
epsilon determines.

MSDN has this to say on Double.Epsilon:

"If you create a custom algorithm that determines whether two floating-
point numbers can be considered equal, you must use a value that is
greater than the Epsilon constant to establish the acceptable absolute
margin of difference for the two values to be considered equal.
(Typically, that margin of difference is many times greater than
Epsilon.)"

I don't see why you don't just use <= in your specific case here,
since the number will fall in the range you require... but if you
really need it, you'd probably want to just use decimal (it has
similar issues as well, but they're more predictable because it's
decimal and not binary - so you can be sure that any decimal number is
represented exactly as you wrote it).
 
Kürsat said:
I used the Epsilon provided by the double class and expected deviations
related to the double arithmetics will fall the range that this provided
epsilon determines.

It seems I should determine an appropriate epsilon value instead of relying
on the provided epsilon.

The provided epsilon value would work if the difference would come from
a single calculation. The difference grows for each iteration, so you
need a larger epsilon value the more iterations you have.

Use an integer for the loop, and calculate the double value from that in
each iteration. That way you don't have any problems with the loop, and
you don't have any accumulative error in the value:

for (int i = 0; i < 4; i++) {
double d = (double)i * 0.1;
// do something...
}
 
Göran Andersson said:
The provided epsilon value would work if the difference would come from
a single calculation.

No.

Double.Epsilon is not related to the uncertainty of a number x.

It is the smallest number > 0.

It is not (even though the name somehow gives the association)
the well known eps (smallest number where x + eps = x).

System.Double.Epsilon is 4.94065645841247e-324

machar eps is 2.22044605E-016

(and even if it were eps, then the uncertainty would not
be eps even on a single calculation)

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top