Solved

For Next loop not counting correctly

Posted on 2008-10-01
13
210 Views
Last Modified: 2012-05-05
Hi Experts,

When I execute the attached code the loop does not count from 1 to 2 in the expected way.

1
1.1
...
1.9
2.0

Instead it doe something like this

1
1.1
1.2000000000000002
...
1.9000000000000008
(never reaches 2)

I am sure it is because binary can not store the number 0.1 accurately so what is the accepted way to count this loop.

For LoopCount As Double = 1 To 2 Step 0.1

   ListBox1.Items.Add(LoopCount)

Next

Open in new window

0
Comment
Question by:DColin
  • 5
  • 5
  • 2
  • +1
13 Comments
 
LVL 11

Expert Comment

by:ladarling
ID: 22617197
Your double is being cast to 'Object' in the add() method, which is causing 'widening' of your number. Assert the Double to Decimal at the last second to preserve the narrowing during the cast to object.
Try:
ListBox1.Items.Add(CDec(LoopCount))
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22617309
The ToString() method is being implicitly called on the resulting decimal in ladarling's above code:

    ListBox1.Items.Add(CDec(LoopCount))     ----->     ListBox1.Items.Add(CDec(LoopCount).ToString)

You could just call it directly like this:

    For LoopCount As Double = 1 To 2 Step 0.1
        ListBox1.Items.Add(LoopCount.ToString)
    Next

0
 
LVL 37

Expert Comment

by:samtran0331
ID: 22617594
Another option is to use FormatNumber which also returns a string, but there are a lot of options as far as how to...well...format the number....

Also, to have 2.0 in the list, you'd actually have to step up to 2.1....

        For LoopCount As Double = 1 To 2.1 Step 0.1
            ListBox1.Items.Add(FormatNumber(LoopCount, 1))
        Next
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22617683
Or go from 10 to 20 instead and display it with the formatting in ToString() itself:

        For LoopCount As Integer = 10 To 20
            ListBox1.Items.Add(CDbl(LoopCount / 10).ToString("0.0"))
        Next
0
 
LVL 11

Expert Comment

by:ladarling
ID: 22617692
Idle_Mind said: The ToString() method is being implicitly called on the resulting decimal in ladarling's above code.
Why makes you say that? Casting to the 'Object' type does not imply a conversion of any kind, since all types widen to object. And conversion from double to decimal types is explicit and narrowing within the numeric types, and also does not imply a string conversion.
http://msdn.microsoft.com/en-us/library/k1e94s7e(VS.80).aspx

ListBox items are type Object, so I am not confused by your assertion...
0
 
LVL 11

Expert Comment

by:ladarling
ID: 22617701
And by not confused, I me 'confused", lol. Confusing, eh?
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22618169
The act of converting to decimal with CDec() doesn't call ToString()...on that you are correct.  =)

It is the ListBox itself that is calling ToString() on your Decimal object when it displays it on the GUI for you.

See: http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.objectcollection.add.aspx

    "When an object is added to the collection, the ListBox first checks to see if the DisplayMember property of the ListControl class has the name of a member from the object specified to reference when obtaining the item text. If the DisplayMember property does not have a member specified, the ListBox then calls the ToString method of the object to obtain the text to display in the list."

It is the ToString() call (that is automatically being done for you) that actually causes the proper display of the value...not the CDec() conversion.

This is evidenced by the snippet I posted:

    For LoopCount As Double = 1 To 2 Step 0.1
        ListBox1.Items.Add(LoopCount.ToString)
    Next

It resulted in the output below.  Note that NO conversion to Decimal was necessary at all...  =)


ListBox.jpg
0
 
LVL 11

Accepted Solution

by:
ladarling earned 500 total points
ID: 22618938
Idle_Mind: It resulted in the output below.  Note that NO conversion to Decimal was necessary at all...  =)
Everything you posted makes perfect sense, I like it, except that if the ListBox is intrinsically calling the objects ToString() method, why is the author seeing this problem (and thus posting the question =-) on Double type variables?
So.. there seems to be something else going on with the listbox control. Any idea what it is, Idle. If you know the answer, dont tell me, I will post it for points :-)
-----------------------------------------------
I would point out to the author, by the way, that if you use a Decimal for LoopCount in the first place, all of our discussion here is moot. It works like a champ (and even actually displays 2.0). Right now I just want to pick Idls' brain on this.
 
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22619588
A perplexing problem...    *** knocks head on table ***

The ListBox.Items.Add() method expects Objects...thus we get a widening conversion on the Double to Object when it is stored in the ListBox.

It is still a Double though as the code below shows.

(Immediate Window Output)
Double : 1
Double : 1.1
Double : 1.2
Double : 1.3
Double : 1.4
Double : 1.5
Double : 1.6
Double : 1.7
Double : 1.8
Double : 1.9

But the ListBox shows it differently so as you said, "...there seems to be something else going on with the listbox control.".

To be honest, I really don't know why the ListBox's ToString() call results in different output than calling ToString() directly on the Double...or even iterating the Items() collection manually calling ToString() on each item.

I tried many combinations, converting to Object and then back to Double...I even tried displaying the values using ToString() with System.Globalization.CultureInfo.CurrentCulture and System.Globalization.CultureInfo.InvariantCulture but still couldn't reproduce the ListBoxes output.

I did find that setting the ListBox.FormatString() property to "N1" results in the desired output...not really an answer to the underlying question...just found it interesting.

So please enlighten us with a TECHNICAL answer on why the ListBox output is different.

I love learning new things.  ;)


Public Class Form1
 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        For LoopCount As Double = 1 To 2 Step 0.1

            ListBox1.Items.Add(LoopCount)

        Next

    End Sub
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        For Each O As Object In ListBox1.Items

            Debug.Print(TypeName(O) & " : " & O)

        Next

    End Sub
 

End Class

Open in new window

ListBox.jpg
0
 

Author Comment

by:DColin
ID: 22620950
Hi Experts,

My problem is not with the list box display but the fact that this loop will not count to 2. I thought this is because binary can not store the number 0.1 so the loop does not count
1
1.1
1.2
...
1.9
2.0
But instead counts as closely to binary as the double's precision will allow. This means that the last two counts should be.
1.9
2.0
But due to the precision limitations of binary are actually.
1.900000000000008
2.000000000000009
And therefore the loop count will not go past 2 and so halts at 1.9000000000008. If this is the case how do I get around this problem using the accepted methods. VB.Net does not have a Binary Coded Decimal number type.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22621049
In ladarlings last comment he stated:

    "I would point out to the author, by the way, that if you use a Decimal for LoopCount in the first place, all of our discussion here is moot. It works like a champ (and even actually displays 2.0)."

So change your variable from Double to Decimal.
0
 

Author Comment

by:DColin
ID: 22621277
Thank you Idle Mind I missed ladarling's Decimal advice. It would seem VB.Net has a BCD data type after all.
0
 
LVL 11

Expert Comment

by:ladarling
ID: 22624242
Idle: So please enlighten us with a TECHNICAL answer on why the ListBox output is different.

Chris: I have no Idea! I was hoping you would...lol. I did the same kind of thing you did, experimenting with debug output, etc, and could not figure it out. My *theory* is that the Listbox's double>object conversion operator is busted. I guess I could start digging through the ListBox code with the MSIL disassembler, but that sounds like tedious, tedious work (to which I am strongly opposed :-)
 But, I will post it for further exploration. Maybe someone out there has the technical solution, not just a theory. I dont. :-)
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now