approxEqual() has fooled me for a long time...

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Wed Oct 20 04:59:54 PDT 2010


On Wed, 20 Oct 2010 13:33:49 +0200, Fawzi Mohamed wrote:

> On 20-ott-10, at 13:18, Lars T. Kyllingstad wrote:
> 
>> On Wed, 20 Oct 2010 12:57:11 +0200, Don wrote:
>>
>>> Lars T. Kyllingstad wrote:
>>>> (This message was originally meant for the Phobos mailing list, but
>>>> for
>>>> some reason I am currently unable to send messages to it*.  Anyway,
>>>> it's probably worth making others aware of this as well.)
>>>>
>>>> In my code, and in unittests in particular, I use
>>>> std.math.approxEqual() a lot to check the results of various
>>>> computations.  If I expect my result to be correct to within ten
>>>> significant digits, say, I'd write
>>>>
>>>>  assert (approxEqual(result, expected, 1e-10));
>>>>
>>>> Since results often span several orders of magnitude, I usually don't
>>>> care about the absolute error, so I just leave it unspecified.  So
>>>> far,
>>>> so good, right?
>>>>
>>>> NO!
>>>>
>>>> I just discovered today that the default value for approxEqual's
>>>> default absolute tolerance is 1e-5, and not zero as one would expect.
>>>> This means that the following, quite unexpectedly, succeeds:
>>>>
>>>>  assert (approxEqual(1e-10, 1e-20, 0.1));
>>>>
>>>> This seems completely illogical to me, and I think it should be fixed
>>>> ASAP.  Any objections?
>>>
>>> I'm personally pretty upset about the existence of that function at
>>> all.
>>> My very first contribution to D was a function for floating point
>>> approximate equality, which I called approxEqual. It gives equality in
>>> terms of number of bits. It gives correct results in all the tricky
>>> special cases. Unlike a naive relative equality test involving
>>> divisions, it doesn't fail for values near zero. (I _think_ that's the
>>> reason why people think you need an absolute equality test as well).
>>> And it's fast. No divisions, no poorly predictable branches.
>>>
>>> Unfortunately, somebody on the ng insisted that it should be called
>>> feqrel(). Stupidly,  I listened. And now nobody uses my masterpiece
>>> because it has a totally sucky name.
> 
> I use it, but I think that having *also* a function with non zero
> absolute error is useful.
> With more complex operations you sum, and if the expected result is 0,
> then feqrel will consider *any* non zero number as completely wrong. For
> example testing matrix multiplication you cannot use feqrel alone. Still
> feqrel is a very useful primitive that I do use (thanks Don).
> 
>> That *is* a sucky name.  Well, now that I'm aware of it, I'll be sure
>> to
>> check it out. :)
>>
>> However, I, like most people, am a lot more used to thinking in terms
>> of
>> digits than bits.  If I need my results to be correct to within 10
>> significant digits, say, how (if possible) would I use feqrel() to
>> ensure
>> that?
> feqrel(a,b)>33 // 10*log(10)/log(2)

...which would be the solution of

  2^bits = 10^digits,

I guess.  Man, I've got to sit down and learn some more about FP numbers 
one day.

Thanks!

-Lars


More information about the Digitalmars-d mailing list