Hi,
I am trying to implement some SUnit tests and I need to compare float (or double) values. Even when the two values compared are equal, I still get an AssertionFailed error. I could define a very small float and assert the absolute value of the difference between the two numbers to be less than this number, but I do not like this solution. Is there a workaround for this? Thanks, Richard Wettel |
You say "they are equal", but floats arrived at from different points of
view (different calculations) may not be equal. For example 4.0 / 2.0 = 2.0 may result in false. Floats are inherently approximations, so your solution of comparing to a small value is a possibility. You might want to say "it has to be within 0.1% or something like that. I always wondered why there was not an "almostequal" method. Richard Wettel wrote: > Hi, > > I am trying to implement some SUnit tests and I need to compare float > (or double) values. > Even when the two values compared are equal, I still get an > AssertionFailed error. > > I could define a very small float and assert the absolute value of the > difference between the two numbers to be less than this number, but I > do not like this solution. > Is there a workaround for this? > > Thanks, > Richard Wettel > > > -- Dennis Smith [hidden email] Cherniak Software Development Corporation +1 905.771.7011 400-10 Commerce Valley Dr E Fax: +1 905.771.6288 Thornhill, ON Canada L3T 7N7 http://www.CherniakSoftware.com |
> -----Original Message-----
> From: Dennis Smith [mailto:[hidden email]] > Sent: Thursday, November 16, 2006 2:12 PM > To: vwnc >> "VWNC, " > Subject: Re: Float comparison > > You say "they are equal", but floats arrived at from > different points of > view > (different calculations) may not be equal. > > For example > 4.0 / 2.0 = 2.0 > may result in false. > > Floats are inherently approximations, so your solution of > comparing to a > small value is a possibility. > You might want to say "it has to be within 0.1% or something > like that. > > I always wondered why there was not an "almostequal" method. I agree, but you would need fuzzy logic for this to determine almost :) I also miss something like #equals:precision: in Number with all that double dispatching to different number types (Integers, FixedPoints, Float, Doubles, etc) e.g. (2.19999 equals: 2.2 precision 0.01) == true I would need that, too. Thomas |
In reply to this post by Richard Wettel-2
I defined my own TestCase>>closeEnough:to: that asserts that one is
close enough to another. The precision of the check is higher for Doubles than for Floats. Rather than assert: in my test cases I just call closeEnough: aFloat to: anotherFloat. Mike Mike Hales Engineering Manager KnowledgeScape (801)413-2809 (801)880-6270 Fax [hidden email] On Nov 16, 2006, at 8:07 AM, Richard Wettel wrote: > Hi, > > I am trying to implement some SUnit tests and I need to compare > float (or double) values. > Even when the two values compared are equal, I still get an > AssertionFailed error. > > I could define a very small float and assert the absolute value of > the difference between the two numbers to be less than this number, > but I do not like this solution. > Is there a workaround for this? > > Thanks, > Richard Wettel > > > |
In reply to this post by Richard Wettel-2
Richard Wettel wrote:
> > I am trying to implement some SUnit tests and I need to compare > float (or double) values. > Even when the two values compared are equal, I still get an > AssertionFailed error. One problem with floats is that what you see is not what you get: when converting between what you see (decimal) and what you get (binary) you can get small conversion errors. As you have experienced you can have two floats that look the same (decimal) but aren't (binary). > I could define a very small float and assert the absolute value of > the difference between the two numbers to be less than this number, > but I do not like this solution. Using a fudge factor is a common solution that will probably do what you need in the context of unit tests. I recall that the Numerical Methods bundle in the pub repository contains a test to measure the precision of the float implementation, you could run that test to derive your fudge factor. > Is there a workaround for this? Well, given the above you could try to specify the expected float values precisely (binary, not decimal) in your unit tests. You can get to the binary representation with something like: 0.5 copy changeClassTo: ByteArray and in the other direction: #[0 0 0 63] copy changeClassTo: Float However for the case where the decimal representation of two floats looks the same there is a simpler solution: compare the #displayString of the two floats instead of their value. HTH, Reinout ------- |
>
>> I could define a very small float and assert the absolute value of >> the difference between the two numbers to be less than this >> number, but I do not like this solution. > > Using a fudge factor is a common solution that will probably do > what you need in the context of unit tests. I forgot to mention that applying a fudge to a float value comparison is at odds with what a float does: you'll need bigger fudges for bigger values. So it is probably better to apply the fudge to only the mantissa of the float instead of to the float itself. R - |
In reply to this post by Richard Wettel-2
I've added the following to some TestCase subclasses:
is: a equivalentTo: b | difference epsilon answer | epsilon := (a abs max: b abs) * 1.0e-08. difference := (a - b) abs asScaledDecimal: 12. answer := difference <= epsilon. ^answer. -----Original Message----- From: Richard Wettel [mailto:[hidden email]] Sent: Thursday, November 16, 2006 5:07 AM To: vwnc-list Subject: Float comparison Hi, I am trying to implement some SUnit tests and I need to compare float (or double) values. Even when the two values compared are equal, I still get an AssertionFailed error. I could define a very small float and assert the absolute value of the difference between the two numbers to be less than this number, but I do not like this solution. Is there a workaround for this? Thanks, Richard Wettel |
This might not be as helpful as the practical advice you've already
gotten, but I recommend that you read the classic article What Every Computer Scientist Should Know About Floating-Point Arithmetic http://docs.sun.com/source/806-3568/ncg_goldberg.html -----Original Message----- From: James Foster [mailto:[hidden email]] Sent: Thursday, November 16, 2006 8:01 AM To: 'vwnc-list' Subject: RE: Float comparison I've added the following to some TestCase subclasses: is: a equivalentTo: b | difference epsilon answer | epsilon := (a abs max: b abs) * 1.0e-08. difference := (a - b) abs asScaledDecimal: 12. answer := difference <= epsilon. ^answer. -----Original Message----- From: Richard Wettel [mailto:[hidden email]] Sent: Thursday, November 16, 2006 5:07 AM To: vwnc-list Subject: Float comparison Hi, I am trying to implement some SUnit tests and I need to compare float (or double) values. Even when the two values compared are equal, I still get an AssertionFailed error. I could define a very small float and assert the absolute value of the difference between the two numbers to be less than this number, but I do not like this solution. Is there a workaround for this? Thanks, Richard Wettel |
In reply to this post by Richard Wettel-2
Hi again,
Thanks for all the answers. Richard Wettel |
In reply to this post by James Foster-3
On Nov 16, 2006, at 8:01, James Foster wrote:
We did something like this at Siemens. We didn't use the ScaledDecimal part. But you can basically put all this behavior on LimitedPrecisionReal and have a method called "approximates:". And then the receiver can return it's "accuracy" (i.e. 7.5ish for Floats and 14.something for Doubles). And if you really wanna go nuts, you can even write your own binary selector. Maybe ?= :) It's of course not entirely technically correct to do this--read the paper referenced in one of the other posts--but you can actually get quite a bit of pragmatic mileage out of the approach. -- Travis Griggs Objologist "Every institution finally perishes by an excess of its own first principle." - Lord Acton |
In reply to this post by Richard Wettel-2
"James Foster" <[hidden email]> wrote:
| I've added the following to some TestCase subclasses: | is: a equivalentTo: b | | difference epsilon answer | | epsilon := (a abs max: b abs) * 1.0e-08. | difference := (a - b) abs asScaledDecimal: 12. | answer := difference <= epsilon. | ^answer. what's wrong with this is that it doesn;t say "close enough to depends on te size of the numbers". e.g. 100,000,001 is quite close to 100,000,000, but 1.5 is not very close to 0.5. You want something like a abs - b abs / (a abs + b abs) < 1e-8 and eliminate zero by a = b or: [a abs - b abs / (a abs + b abs) < 2d-8] | -----Original Message----- | From: Richard Wettel [mailto:[hidden email]] | Sent: Thursday, November 16, 2006 5:07 AM | To: vwnc-list | Subject: Float comparison | Hi, | I am trying to implement some SUnit tests and I need to compare float | (or double) values. | Even when the two values compared are equal, I still get an | AssertionFailed error. | I could define a very small float and assert the absolute value of | the difference between the two numbers to be less than this number, | but I do not like this solution. | Is there a workaround for this? | Thanks, | Richard Wettel --- Eliot Miranda ,,,^..^,,, mailto:[hidden email] VisualWorks Engineering, Cincom Smalltalk: scene not herd Tel +1 408 216 4581 3350 Scott Blvd, Bldg 36 Suite B, Santa Clara, CA 95054 USA Fax +1 408 216 4500 |
The 'epsilon' is calculated based on the size of the numbers, so your first
example returns true while your second example returns false. -----Original Message----- From: [hidden email] [mailto:[hidden email]] Sent: Thursday, November 16, 2006 10:38 AM To: [hidden email] Cc: [hidden email] Subject: Re: Float comparison "James Foster" <[hidden email]> wrote: | I've added the following to some TestCase subclasses: | is: a equivalentTo: b | | difference epsilon answer | | epsilon := (a abs max: b abs) * 1.0e-08. | difference := (a - b) abs asScaledDecimal: 12. | answer := difference <= epsilon. | ^answer. what's wrong with this is that it doesn;t say "close enough to depends on te size of the numbers". e.g. 100,000,001 is quite close to 100,000,000, but 1.5 is not very close to 0.5. You want something like a abs - b abs / (a abs + b abs) < 1e-8 and eliminate zero by a = b or: [a abs - b abs / (a abs + b abs) < 2d-8] | -----Original Message----- | From: Richard Wettel [mailto:[hidden email]] | Sent: Thursday, November 16, 2006 5:07 AM | To: vwnc-list | Subject: Float comparison | Hi, | I am trying to implement some SUnit tests and I need to compare float | (or double) values. | Even when the two values compared are equal, I still get an | AssertionFailed error. | I could define a very small float and assert the absolute value of | the difference between the two numbers to be less than this number, | but I do not like this solution. | Is there a workaround for this? | Thanks, | Richard Wettel --- Eliot Miranda ,,,^..^,,, mailto:[hidden email] VisualWorks Engineering, Cincom Smalltalk: scene not herd Tel +1 408 216 4581 3350 Scott Blvd, Bldg 36 Suite B, Santa Clara, CA 95054 USA Fax +1 408 216 4500 |
In reply to this post by Richard Wettel-2
> "James Foster" <[hidden email]> wrote:
> > | I've added the following to some TestCase subclasses: > > | is: a equivalentTo: b > > | | difference epsilon answer | > | epsilon := (a abs max: b abs) * 1.0e-08. > | difference := (a - b) abs asScaledDecimal: 12. > | answer := difference <= epsilon. > | ^answer. Eliot Miranda wrote: > what's wrong with this is that it doesn;t say "close enough to depends on > te size of the numbers". e.g. 100,000,001 is quite close to 100,000,000, > but 1.5 is not very close to 0.5. You want something like > > a abs - b abs / (a abs + b abs) < 1e-8 Or to avoid problems when a=-b: (a - b) abs / (a abs + b abs) < 1e-8 > and eliminate zero by > a = b or: [a abs - b abs / (a abs + b abs) < 2d-8] Or rather, to avoid the divisor being zero: scale := a abs + b abs. scale isZero or: [(a - b) abs / scale < 2d-8] What the accuracy should be depends on what you are doing with the numbers. If you want +/- 1% for both a and b, then (a - b) abs is at most 2%, so dividing by (a abs + b abs) - effectively 200% - nicely means that you can just put the error you are willing to accept on the right-hand side of the comparison. If you know a is right, and want b to be +/- 1%, you'll need to put half the error you are willing to accept on the right-hand side. Steve > | -----Original Message----- > | From: Richard Wettel [mailto:[hidden email]] > | Sent: Thursday, November 16, 2006 5:07 AM > | To: vwnc-list > | Subject: Float comparison > > | Hi, > > | I am trying to implement some SUnit tests and I need to compare float > | (or double) values. > | Even when the two values compared are equal, I still get an > | AssertionFailed error. > > | I could define a very small float and assert the absolute value of > | the difference between the two numbers to be less than this number, > | but I do not like this solution. > | Is there a workaround for this? > > | Thanks, > | Richard Wettel > --- > Eliot Miranda ,,,^..^,,, > mailto:[hidden email] > VisualWorks Engineering, Cincom Smalltalk: scene not herd Tel +1 408 > 4581 > 3350 Scott Blvd, Bldg 36 Suite B, Santa Clara, CA 95054 USA Fax +1 408 216 > 4500 > |
Free forum by Nabble | Edit this page |