for loop does not work as it should

U

UnkleVo

Can someone run the code below and tell me why it never reaches 0.06?
I am really puzzled..... or just going crazy?

Dim i As Double
For i = 0.01 To 0.05 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.05************")

For i = 0.01 To 0.06 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.06************")

For i = 0.01 To 0.07 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.07************")

I get the output below:

0.01
0.02
0.03
0.04
0.05
*******max0.05************
0.01
0.02
0.03
0.04
0.05
*******max0.06************
0.01
0.02
0.03
0.04
0.05
0.06
0.07
*******max0.07************
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

UnkleVo said:
Can someone run the code below and tell me why it never reaches 0.06?
I am really puzzled..... or just going crazy?

Dim i As Double
For i = 0.01 To 0.05 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.05************")

For i = 0.01 To 0.06 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.06************")

For i = 0.01 To 0.07 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.07************")

I get the output below:

0.01
0.02
0.03
0.04
0.05
*******max0.05************
0.01
0.02
0.03
0.04
0.05
*******max0.06************
0.01
0.02
0.03
0.04
0.05
0.06
0.07
*******max0.07************

You can't rely on an exact value when you are using a floating point
number. Very few numbers can be expressed exactly as a floating point
number, most numbers are expressed as a number that is slightly off.

When you think that you are adding exactly 0.01 to the loop counter, you
are actually adding something that is very close to 0.01 but not
exactly. Each time you add to the counter, the result will be rounded to
the closest representation that can be stored in a double, and when you
get to the sixth step in the loop, the result will be slightly more than
0.06, which results in the loop ending.

It's not the middle loop that is wrong. You were just lucky that the
other two loops did not do the same.
 
S

SAL

That's right. Good one.
What you could do though is change your loop to a while loop, set your
starting value before you enter the loop and have the loop say:

While i < .07
' do something
i += .01
Wend

That should get you the results you are looking for. Or, you could do it in
C# as follows

for i = .01; i < .07, i += .01
{
// do something
}
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Actually, it doesn't matter how you do the loop, as long as you expect
floating point values to be exact, as you do in your code. You will
experience the same kind of unreliability, only with different results
for any given number as you are using the < operator instead of the <=
opreator that is used by the For loop.

A reliable way of looping using a floating point counter is to put the
end condition right between the number that should be included and the
number that shouldn't.

To loop from 0.01 to 0.05, the value 0.05 should be included but not
0.06. To make sure that this happens, put the end condition between 0.05
and 0.06:

For i = 0.01 to 0.055 Step 0.01
That's right. Good one.
What you could do though is change your loop to a while loop, set your
starting value before you enter the loop and have the loop say:

While i < .07
' do something
i += .01
Wend

That should get you the results you are looking for. Or, you could do it in
C# as follows

for i = .01; i < .07, i += .01
{
// do something
}
 
H

Herfried K. Wagner [MVP]

SAL said:
What you could do though is change your loop to a while loop, set your
starting value before you enter the loop and have the loop say:

While i < .07
' do something
i += .01
Wend

Note that 'Wend' has been replaced by 'End While' in VB.NET for some unknown
reasons.
 
M

Michael C

Göran Andersson said:
To loop from 0.01 to 0.05, the value 0.05 should be included but not 0.06.
To make sure that this happens, put the end condition between 0.05 and
0.06:

For i = 0.01 to 0.055 Step 0.01

Better to just use
for j = 1 to 5
i = i + 0.01
'OR
i = j * 0.01
next

I actually think the second would be better as it reduces rounding errors
slightly, although I suspect it would be insignificant in this particular
case.

Michael
 
J

Jay B. Harlow [MVP - Outlook]

UnkleVo,
In addition to the other comments, consider using Decimal instead of Double
or Single.

As Decimal is a base 10 floating point number, where as Single & Double are
base 2 floating point numbers. Base 10 floating point numbers (such as
Decimal) can exactly represent all base 10 floating point #, where as base 2
floating point numbers (such as Double & Single) may causing rounding
problems for various base 10 floating point numbers

Something like:

Dim i As Decimal
For i = 0.01D To 0.05D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.05************")

For i = 0.01D To 0.06D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.06************")

For i = 0.01D To 0.07D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.07************")

NOTE: 0.01D is a Decimal literal, where as 0.01 is a Double literal & 0.01F
is a Single literal.
 
U

UnkleVo

UnkleVo,
In addition to the other comments, consider using Decimal instead of Double
or Single.

As Decimal is a base 10 floating point number, where as Single & Double are
base 2 floating point numbers. Base 10 floating point numbers (such as
Decimal) can exactly represent all base 10 floating point #, where as base 2
floating point numbers (such as Double & Single) may causing rounding
problems for various base 10 floating point numbers

Something like:

Dim i As Decimal
For i = 0.01D To 0.05D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.05************")

For i = 0.01D To 0.06D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.06************")

For i = 0.01D To 0.07D Step 0.01D
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.07************")

NOTE: 0.01D is a Decimal literal, where as 0.01 is a Double literal & 0.01F
is a Single literal.

--
Hope this helps
Jay B. Harlow [MVP - Outlook]
.NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley -http://www.tsbradley.net




Can someone run the code below and tell me why it never reaches 0.06?
I am really puzzled..... or just going crazy?
Dim i As Double
For i = 0.01 To 0.05 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.05************")
For i = 0.01 To 0.06 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.06************")
For i = 0.01 To 0.07 Step 0.01
Debug.WriteLine(i)
Next
Debug.WriteLine("*******max0.07************")
I get the output below:
0.01
0.02
0.03
0.04
0.05
*******max0.05************
0.01
0.02
0.03
0.04
0.05
*******max0.06************
0.01
0.02
0.03
0.04
0.05
0.06
0.07
*******max0.07************- Hide quoted text -

- Show quoted text -

Thank you very much, everyone.
 

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

Top