On 20-ott-10, at 17:52, Don wrote:

Andrei Alexandrescu wrote:
On 10/20/10 5:32 CDT, 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 wonder what would be a sensible default. If the default for absolute error is zero, then you'd have an equally odd behavior for very small numbers (and most notably zero). Essentially nothing would be approximately zero.
Andrei

I don't think it's possible to have a sensible default for absolute tolerance, because you never know what scale is important. You can do a default for relative tolerance, because floating point numbers work that way (eg, you can say they're equal if they differ in only the last 4 bits, or if half of the mantissa bits are equal).

I would even think that the acceptable relative error is almost always known at compile time, but the absolute error may not be.

I had success in using (the very empiric)

/// feqrel version more forgiving close to 0
/// if you sum values you cannot expect better than T.epsilon absolute error. /// feqrel compares relative error, and close to 0 (where the density of floats is high) it is
/// much more stringent.
/// To guarantee T.epsilon absolute error one should use shift=1.0, here we are more stingent
/// and we use T.mant_dig/4 digits more when close to 0.
int feqrel2(T)(T x,T y){
    static if(isComplexType!(T)){
        return min(feqrel2(x.re,y.re),feqrel2(x.im,y.im));
    } else {
        const T shift=ctfe_powI(0.5,T.mant_dig/4);
        if (x<0){
            return feqrel(x-shift,y-shift);
        } else {
            return feqrel(x+shift,y+shift);
        }
    }
}

(from blip.narrray.NArrayBasicOps)

Reply via email to