DColin
asked on
For Next loop not counting correctly
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.
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
The ToString() method is being implicitly called on the resulting decimal in ladarling's above code:
ListBox1.Items.Add(CDec(Lo opCount)) -----> ListBox1.Items.Add(CDec(Lo opCount).T oString)
You could just call it directly like this:
For LoopCount As Double = 1 To 2 Step 0.1
ListBox1.Items.Add(LoopCou nt.ToStrin g)
Next
ListBox1.Items.Add(CDec(Lo
You could just call it directly like this:
For LoopCount As Double = 1 To 2 Step 0.1
ListBox1.Items.Add(LoopCou
Next
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(FormatN umber(Loop Count, 1))
Next
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(FormatN
Next
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(Lo opCount / 10).ToString("0.0"))
Next
For LoopCount As Integer = 10 To 20
ListBox1.Items.Add(CDbl(Lo
Next
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/libr ary/k1e94s 7e(VS.80). aspx
ListBox items are type Object, so I am not confused by your assertion...
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/
ListBox items are type Object, so I am not confused by your assertion...
And by not confused, I me 'confused", lol. Confusing, eh?
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(LoopCou nt.ToStrin g)
Next
It resulted in the output below. Note that NO conversion to Decimal was necessary at all... =)
ListBox.jpg
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(LoopCou
Next
It resulted in the output below. Note that NO conversion to Decimal was necessary at all... =)
ListBox.jpg
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.Cultu reInfo.Cur rentCultur e and System.Globalization.Cultu reInfo.Inv ariantCult ure 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. ;)
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.Cultu
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
ListBox.jpg
ASKER
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.
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.
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.
"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.
ASKER
Thank you Idle Mind I missed ladarling's Decimal advice. It would seem VB.Net has a BCD data type after all.
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. :-)
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. :-)
Try:
ListBox1.Items.Add(CDec(Lo