2

2 進浮動小数点を直接比較することはできません。私は一括比較演算子をオーバーライドする float のドロップイン置換クラスを書いています::

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; }
};

これで、次のように書くことができます::

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

ただし、このコードは予期しない動作を示します::

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

再帰的な無限ループのように何度も呼び出さFloat::operator*(std::complex<Float<double> >, Float)れ、最終的にスタック オーバーフローが発生します。これを修正する方法は?

編集

DeadMG と Charles Bailey は、ISO/IEC 14882:2011、26.4 から次のように指摘しています。

多分私は間違った反例を与えました。基本型の適切なドロップイン置換クラスを作成する方法については、まだ議論できます。

私の動機を明確にさせてください、assert(0.1 * 0.1 == 0.01);直感に反しています。そのため、「ほぼ等しい」動作を使用して 2 つの浮動小数点数を比較する Float クラスを作成します。

4

1 に答える 1

2

コンストラクターを明示的にします。

a * 2.0;

暗黙的に Float を構築してから、次を呼び出します。

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 に答える