[Python-ideas] Way to check for floating point "closeness"?
Ron Adam
ron3200 at gmail.com
Thu Jan 15 03:13:42 CET 2015
On 01/14/2015 06:04 PM, Steven D'Aprano wrote:
> On Wed, Jan 14, 2015 at 03:18:17PM -0600, Ron Adam wrote:
>> >
>> >
>> >On 01/14/2015 04:39 AM, Steven D'Aprano wrote:
> [...]
>>> > >Suppose you have a value which should be exactly 0.5, but you calculate
>>> > >it as 0.51. Then the absolute error is 0.51-0.5 = 0.01, and the relative
>>> > >error is 0.01/0.5 = 0.02 (or 2%).
>>> > >
>>> > >But consider two values, 0.0 and 0.1. Then the absolute error is 0.1-0.0
>>> > >= 0.1, and the relative error is 0.1/0.0 which is infinite.
>>> > >
>>> > >So 0.0 and -0.0 are problematic when dealing with relative errors.
>> >
>> >I'm not sure why, but it seems like something here is out of place to me.
>> >Either it's not something that would come up, or it's something you would
>> >expect and handle differently. Or it's would be an error, signalling you
>> >need to handle it differently.
> You're going to have to explain what you think is "out of place".
>
> Of course doing division by zero is an error. The whole point of this
> discussion is that you cannot talk about errors relative to zero. At
> zero, you can still have an absolute error, but you cannot have a
> relative error. The definition of the error between two numeric values:
>
> def abserr(a, b):
> return abs(a - b)
>
> def relerr(a, b):
> return abs(a - b)/min(abs(a), abs(b))
>
>
> If either a or b is zero, relarr() fails. This is a mathematical
> limitation, not a bug to be fixed.
I would probably write like this.
def relerr(actual, expected):
return abs(actual - expected)/expected
Where expected is a non-zero reference value.
it needs a third value. In the above the expected value is the scaler.
And then use it this way to measure a resistors tolerance.
if relerr(218.345, 220) <= 0.05:
print("Good")
else:
print("Bad")
Note that you would never compare to an expected value of zero.
relerr(a - b, expected_feet) < tolerance # relative feet from b
relerr(a - 0, expected_feet) < tolerance # relative feet from zero
relerr(a - b, ulp) # percentage of ulp's
What Chris is looking for is a way to get a closeness function that works
most of the time. (He posted while I'm writing this.)
But I don't see how you can do that without specifying some scaler to give
it context, and a tolerance.
def is_close(a, b, unit, good):
return (abs(a - b) / unit) <= good
is_close(218.345, 220, 1, .05) # OHMs
is_close(a, b, ULP, 2) # ULPs
is_close(a, b, AU, .001) # astronomical units
I don't see anyway to generalise those with just a function.
By using objects we can do a bit more. I seem to recall coming across
measurement objects some place. They keep a bit more context with them.
Cheers,
Ron
More information about the Python-ideas
mailing list