2

We can not compare binary floating point directly. I am writting a drop-in replacements class for float which override the bulti-in compare operators::

template<class U>
class Float {
    private:
        U val;
    public:
        Float(U v = 0): val(v) {}
        operator U() const { return val; }

        friend bool operator<(Float a, Float b) { return a.val + 1e-6 < b.val; }
        friend bool operator==(Float a, Float b) { return !(a < b) && !(b < a); }

        friend Float operator*(Float a, Float b) { return a.val * b.val; }
        template<class T>
        friend Float operator*(T a, Float b) { return a * b.val; }
        template<class T>
        friend Float operator*(Float a, T b) { return a.val * b; }
};

Now we can write something like this::

#include<assert.h>
int main() {
    Float<double> a = 0.2, b = 0.02;
    assert(a * a == 2 * b);
}

However, this code will show a unexpected behavior::

#include<complex>
int main() {
    std::complex< Float<double> > a(0.2);
    a * 2.0;
}

It will call Float::operator*(std::complex<Float<double> >, Float) again and again like a recursive endless loop, and finally get stack overflow. How to fix this?

Edit

DeadMG and Charles Bailey point out that From ISO/IEC 14882:2011, 26.4: "The effect of instantiating the template complex for any type other than float, double, or long double is unspecified."

Maybe I have given a wrong counter example. We could still discuss how to write a good drop-in replacements class for fundamental type.

Let me clear my motivation, assert(0.1 * 0.1 == 0.01); is counterintuitive. That is why I write a Float class which used "almost equal" behavior to compare two floating number.

4

1 回答 1

2

使您的构造函数显式。

a * 2.0;

隐式构造一个浮点数,然后调用:

template<class T>
friend Float operator*(T a, Float b) 
{
    return a * b.val;
}

当您在 b.val 上调用 * 运算符时,这反过来又隐式构造了另一个 Float;然后你从那里递归。

在我提出完整的修复建议之前,您需要进一步充实您的预期行为。

我用来探索它并测试修复的代码:

#include <iostream>

template<class U>
class Float {
    private:
        U val;
    public:
        explicit Float(U v = 0): val(v) 
        {
            std::cout << "constructor ";
        }
        operator U() const { return val; }

        friend bool operator<(Float a, Float b) { return a.val + 1e-6 < b.val; }
        friend bool operator==(Float a, Float b) { return !(a < b) && !(b < a); }

        friend Float operator*(Float a, Float b) { return a.val * b.val; }
    template<class T>
    friend Float operator*(T a, Float b) 
    {
        std::cout << "here";
        return a * b.val;
     }

        template<class T>
        friend Float operator*(Float a, T b) { return a.val * b; }
};

#include<complex>
int main() {
    std::complex< Float<double> > a(0.2);
    a * 2.0;
}
于 2012-06-29T04:46:09.420 回答