|
code
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Problem comparing double valueswith. I have an application that involves a comparison of two numbers, one of which is made up of the sum of the values in an array. The code is as follows: Private Sub CompareNumbers() Dim intIndex As Integer Dim arNumbers(5) As Double Dim dblTotal As Double Dim dblComparison As Double arNumbers(0) = 16843.2 arNumbers(1) = 40348.41 arNumbers(2) = 371910.18 arNumbers(3) = 148183.27 arNumbers(4) = 29183.96 arNumbers(5) = 143530.98 For intIndex = 0 To 5 dblTotal = dblTotal + arNumbers(intIndex) Next dblComparison = 750000 If dblComparison = dblTotal Then MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & Chr$(9) & dblComparison & vbCr & "Numbers match" Else MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & Chr$(9) & dblComparison & vbCr & "No match" End If End Sub Notice the oddity? The numbers are apparently identical and yet according to the code, they do not match. What is even more bizzare is that if I reduce the total of the numbers in the array to 597000, made up of the following: '' arNumbers(0) = 57843.2 '' arNumbers(1) = 44348.41 '' arNumbers(2) = 371910.18 '' arNumbers(3) = 50183.27 '' arNumbers(4) = 29183.96 '' arNumbers(5) = 43530.98 the comparison suceeded. I don't think I have ever come up against anything so strange or so frustrating; if anyone can shed any light on this it would be greatly appreciated. Thanks in advance Chris *** Sent via Developersdex http://www.developersdex.com *** Floating point is not an exact numeric representation Chris. I'm afraid the
newsgroups are full of questions like this. I don't have a link to hand that would explain all the why's and where's, but maybe someone else will post one. From the values you have, it looks like they're all monetary values. If so then try changing all your 'Double' types to 'Currency'. That is an exact numeric representation. To be extra safe, I'd probably stick an '@' character at the end of any numeric literals (e.g. 16843.2@) to make sure that VB compiles them correctly Tony Proctor Show quoteHide quote "Chris Eden" <ec2***@hotmail.com> wrote in message news:#9934aVgFHA.3936@TK2MSFTNGP10.phx.gbl... > Hello all, I have a strange problem that I would appreciate any help > with. I have an application that involves a comparison of two numbers, > one of which is made up of the sum of the values in an array. The code > is as follows: > > Private Sub CompareNumbers() > Dim intIndex As Integer > Dim arNumbers(5) As Double > Dim dblTotal As Double > Dim dblComparison As Double > > arNumbers(0) = 16843.2 > arNumbers(1) = 40348.41 > arNumbers(2) = 371910.18 > arNumbers(3) = 148183.27 > arNumbers(4) = 29183.96 > arNumbers(5) = 143530.98 > > For intIndex = 0 To 5 > dblTotal = dblTotal + arNumbers(intIndex) > Next > > dblComparison = 750000 > If dblComparison = dblTotal Then > MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & > Chr$(9) & dblComparison & vbCr & "Numbers match" > Else > MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & > Chr$(9) & dblComparison & vbCr & "No match" > End If > End Sub > > Notice the oddity? The numbers are apparently identical and yet > according to the code, they do not match. What is even more bizzare is > that if I reduce the total of the numbers in the array to 597000, made > up of the following: > '' arNumbers(0) = 57843.2 > '' arNumbers(1) = 44348.41 > '' arNumbers(2) = 371910.18 > '' arNumbers(3) = 50183.27 > '' arNumbers(4) = 29183.96 > '' arNumbers(5) = 43530.98 > the comparison suceeded. > > I don't think I have ever come up against anything so strange or so > frustrating; if anyone can shed any light on this it would be greatly > appreciated. > > Thanks in advance > > Chris > > *** Sent via Developersdex http://www.developersdex.com *** > Floating point is not an exact numeric representation Chris. I'm afraid the INFO: Visual Basic and Arithmetic Precision> newsgroups are full of questions like this. I don't have a link to hand that > would explain all the why's and where's, but maybe someone else will post > one. http://support.microsoft.com/default.aspx?scid=http://support.microsoft..com:80/support/kb/articles/Q279/7/55.ASP&NoWebContent=1 (Complete) Tutorial to Understand IEEE Floating-Point Errors http://support.microsoft.com/default.aspx?scid=http://support.microsoft..com:80/support/kb/articles/Q42/9/80.ASP&NoWebContent=1 Rick - MVP Thanks Rick! ...check in the post... <g>
Tony Proctor "Rick Rothstein" <rickNOSPAMnews@NOSPAMcomcast.net> wrote in message INFO: Visual Basic and Arithmetic Precisionnews:ewDgHiWgFHA.2180@TK2MSFTNGP15.phx.gbl... > Floating point is not an exact numeric representation Chris. I'm afraid the > newsgroups are full of questions like this. I don't have a link to hand that > would explain all the why's and where's, but maybe someone else will post > one. http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q279/7/55.ASP&NoWebContent=1 (Complete) Tutorial to Understand IEEE Floating-Point Errors http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q42/9/80.ASP&NoWebContent=1 Rick - MVP Tony Proctor wrote:
> My favorite is What Every Computer Scientist Should Know About Floating> Floating point is not an exact numeric representation Chris. I'm afraid the > newsgroups are full of questions like this. I don't have a link to hand that > would explain all the why's and where's, but maybe someone else will post > one. .... Point a reprint of the original of which can be found at http://docs.sun.com/source/806-3568/ncg_goldberg.html There are some on MSN as well....
Show quote
Hide quote
"Chris Eden" <ec2***@hotmail.com> wrote in message news:%239934aVgFHA.3936@TK2MSFTNGP10.phx.gbl... The problem is that they are not the same due to inherent rounding errors and the internal representation of floating point numbers.> Hello all, I have a strange problem that I would appreciate any help > with. I have an application that involves a comparison of two numbers, > one of which is made up of the sum of the values in an array. The code > is as follows: > > Private Sub CompareNumbers() > Dim intIndex As Integer > Dim arNumbers(5) As Double > Dim dblTotal As Double > Dim dblComparison As Double > > arNumbers(0) = 16843.2 > arNumbers(1) = 40348.41 > arNumbers(2) = 371910.18 > arNumbers(3) = 148183.27 > arNumbers(4) = 29183.96 > arNumbers(5) = 143530.98 > > For intIndex = 0 To 5 > dblTotal = dblTotal + arNumbers(intIndex) > Next > > dblComparison = 750000 > If dblComparison = dblTotal Then > MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & > Chr$(9) & dblComparison & vbCr & "Numbers match" > Else > MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & > Chr$(9) & dblComparison & vbCr & "No match" > End If > End Sub > > Notice the oddity? The numbers are apparently identical and yet > according to the code, they do not match. What is even more bizzare is > that if I reduce the total of the numbers in the array to 597000, made > up of the following: > '' arNumbers(0) = 57843.2 > '' arNumbers(1) = 44348.41 > '' arNumbers(2) = 371910.18 > '' arNumbers(3) = 50183.27 > '' arNumbers(4) = 29183.96 > '' arNumbers(5) = 43530.98 > the comparison suceeded. > > I don't think I have ever come up against anything so strange or so > frustrating; if anyone can shed any light on this it would be greatly > appreciated. > > Thanks in advance > > Chris > > *** Sent via Developersdex http://www.developersdex.com *** ?dblComparison-dblTotal 1.16415321826935E-10 The following will work. It uses variants and the decimal subtype. Private CompareNumbers() Dim intIndex As Integer Dim arNumbers(5) As Double Dim dblTotal As Variant Dim dblComparison As Variant arNumbers(0) = CDec(16843.2) arNumbers(1) = CDec(40348.41) arNumbers(2) = CDec(371910.18) arNumbers(3) = CDec(148183.27) arNumbers(4) = CDec(29183.96) arNumbers(5) = CDec(143530.98) For intIndex = 0 To 5 dblTotal = dblTotal + arNumbers(intIndex) Next dblComparison = CDec(750000) If dblComparison = dblTotal Then MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & _ Chr$(9) & dblComparison & vbCr & "Numbers match" Else MsgBox "Array Total:" & Chr$(9) & dblTotal & vbCr & "Comparison:" & _ Chr$(9) & dblComparison & vbCr & "No match" End If End Sub -- Al Reid
Show quote
Hide quote
> Hello all, I have a strange problem that I would appreciate any help If you can go with the Currency or Decimal data type solutions, that would probably be the way to go. However, for completeness sake, if you want to work with numbers of type Double, the best way to test equality is to choose some value such that if the difference between the two floating point numbers is less than it, you would be willing to call the numbers equal. For example> with. I have an application that involves a comparison of two numbers, > one of which is made up of the sum of the values in an array. The code > is as follows: > > Private Sub CompareNumbers() > Dim intIndex As Integer > Dim arNumbers(5) As Double > Dim dblTotal As Double > Dim dblComparison As Double > > ......<code snipped>...... > > Notice the oddity? The numbers are apparently identical and yet > according to the code, they do not match. Dim A As Double Dim B As Double ' A and B get their values from some set of calculations If Abs(A - B) < 1e-10 Then ' Close enough to be considered equal End If Here I've chosen 1e-16 which is 0.0000000001 but you can chose any value suitable for your needs and the data type of your variables. Rick - MVP Rick Rothstein wrote:
Show quoteHide quote >> Hello all, I have a strange problem that I would appreciate any help Hi Rick,>> with. I have an application that involves a comparison of two >> numbers, one of which is made up of the sum of the values in an >> array. The code is as follows: >> >> Private Sub CompareNumbers() >> Dim intIndex As Integer >> Dim arNumbers(5) As Double >> Dim dblTotal As Double >> Dim dblComparison As Double >> >> ......<code snipped>...... >> >> Notice the oddity? The numbers are apparently identical and yet >> according to the code, they do not match. > > If you can go with the Currency or Decimal data type solutions, that > would probably be the way to go. However, for completeness sake, if > you want to work with numbers of type Double, the best way to test > equality is to choose some value such that if the difference between > the two floating point numbers is less than it, you would be willing > to call the numbers equal. For example > > Dim A As Double > Dim B As Double > ' A and B get their values from some set of calculations > If Abs(A - B) < 1e-10 Then > ' Close enough to be considered equal > End If > > Here I've chosen 1e-16 which is 0.0000000001 but you can chose any > value suitable for your needs and the data type of your variables. > > Rick - MVP In most cases using the 'epsilon' tolerance won't cause any problem. Theoretically, however, it isn't quite correct - you break the transitivity of the equality relation. Example (untested): Function NearlyEqual(ByVal A As Double, ByVal B As Double) As Boolean NearlyEqual = Abs(A - B) < 1e-5 End Function Private Sub TestThem() Const cUB As Long = 10 Dim aTemp(0 To cUB) As Double Dim i As Long Dim dW As Double Const cDelta As Double = 4e-6 For i = 0 To cUB aTemp(i) = dW dW = dW + cDelta Next i For i = 1 To cUB Debug.Print "Item-" & ( i-1); " is near to Item-" & i; " : "; NearlyEqual(aTemp(i-1), aTemp(i)) Next i ' But of course: Debug.Print "Item-" & 0; " is near to Item-" & cUB; " : "; NearlyEqual(aTemp(0), aTemp(cUB)) End Sub For this reason, I would prefer something like the following instead: Function NearlyEqual2(ByVal A As Double, ByVal B As Double) As Boolean NearlyEqual2 = (Round(A,5) = Round(B,5)) End Function -- PZ > In most cases using the 'epsilon' tolerance won't cause any problem. Unless I'm missing some subtle aspect of your comment, I don't see this> Theoretically, however, it isn't quite correct - you break the transitivity > of the equality relation. Example (untested): as being significant in any way when we are talking about a "nearly equal" type of function. > For this reason, I would prefer something like the following instead: Yes, you could you this approach also. Actually, I like this approach> > Function NearlyEqual2(ByVal A As Double, ByVal B As Double) As Boolean > NearlyEqual2 = (Round(A,5) = Round(B,5)) > End Function better than the epsilon test even if it will probably be ever so slightly slower... two function calls instead of one(?). However, I wouldn't use the Round function as can produce transitivity problems of its own due to its use of Banker's Rounding. Consider this.... Print Round(11.111115, 5), Round(11.111125, 5), Round(11.111135, 5) Use the Format function instead as that will produce the "correct" type of rounding. Function NearlyEqual3(ByVal A As Double, ByVal B As Double) As Boolean NearlyEqual3 = (Format(A, "#.#####") = Format(B, "#.#####")) End Function Rick "Rick Rothstein" <rickNOSPAMnews@NOSPAMcomcast.net> wrote in message If speed is of concern then converting to and from String like that is notnews:%23JiSoBjgFHA.1948@TK2MSFTNGP12.phx.gbl > Yes, you could you this approach also. Actually, I like this approach > better than the epsilon test even if it will probably be ever so > slightly slower... two function calls instead of one(?). However, I > wouldn't use the Round function as can produce transitivity problems > of its own due to its use of Banker's Rounding. Consider this.... > > Print Round(11.111115, 5), Round(11.111125, 5), Round(11.111135, 5) > > Use the Format function instead as that will produce the "correct" > type of rounding. the best idea, especially when wrapping them up in Variants -- Reply to the group so all can participate VB.Net: "Fool me once..." Inline ...
Rick Rothstein wrote: >> In most cases using the 'epsilon' tolerance won't cause any problem. When used in simple situations, I totally agree. But if you build a complex>> Theoretically, however, it isn't quite correct - you break the >> transitivity of the equality relation. Example (untested): > > Unless I'm missing some subtle aspect of your comment, I don't see > this as being significant in any way when we are talking about a > "nearly equal" type of function. system dealing with floating point values and using this relation systematically as equivalence criterion, then the effect can be significant - you can arrive at the result that 0 is equivalent with 1, or whatever. It seems a rather contrieved example, but I had really encountered something similar. Show quoteHide quote > Yes, I know about this, but I don't think it leads to transitivity error.> >> For this reason, I would prefer something like the following instead: >> >> Function NearlyEqual2(ByVal A As Double, ByVal B As Double) As >> Boolean NearlyEqual2 = (Round(A,5) = Round(B,5)) >> End Function > > Yes, you could you this approach also. Actually, I like this approach > better than the epsilon test even if it will probably be ever so > slightly slower... two function calls instead of one(?). However, I > wouldn't use the Round function as can produce transitivity problems > of its own due to its use of Banker's Rounding. Consider this.... > > Print Round(11.111115, 5), Round(11.111125, 5), Round(11.111135, 5) The essential goal is to map the fine-grain machine representation values to some coarser subset. The rounding method will have effect on the choice of the 'nearest' allowed representative in borderline cases, but the effect is not rippling. As for the efficiency - yes, this is certainly much slower, esp. because rounding is performed for the decimal place, not very fast on binary machines. If one's going to need it for heavy duty, it is better to mask off the tail part of the internal representation of the mantissa. Show quoteHide quote > > Use the Format function instead as that will produce the "correct" > type of rounding. > > Function NearlyEqual3(ByVal A As Double, ByVal B As Double) As Boolean > NearlyEqual3 = (Format(A, "#.#####") = Format(B, "#.#####")) > End Function > > Rick
Programatically design a form
Divide a path into a Drivename, Pathname, and Filename? How should I select a folder, create and select the folder? SaveSetting question Default Property in VB6 Class Return Security Events for Yesterday Emergency: Unicode Characters in a Dataset. Help with WMI Time fired event, error out of stack space Enumerate Devices |
|||||||||||||||||||||||