12

乗算によって返される精度を 2 倍にする方法はありますか (オーバーフローを避けるため)。

template<class T> class MyClass {
     T multiply (T a, T b) { return a * b; }
}

何かのようなもの:

long T multiply (T a, T b) { return a * b; }

そのため、'int'、'long'、または 'double' のいずれが指定されても、'long int'、'long long'、または 'long double' が乗算から返されます。

これは一般的な質問です。内部で double を使用して回避しています。しかし、私の質問は、C++ で型を「長い」バリアントに昇格させるメカニズムがあるかどうかです。

4

2 に答える 2

15

A possible solution is to define your own type trait:

template<typename T>
struct add_long { typedef T type; };

template<>
struct add_long<int> { typedef long int type; };

template<>
struct add_long<double> { typedef long double type; };

template<>
struct add_long<long int> { typedef long long int type; };

// And so on...

This is how you would use it in your class:

template<class T>
class MyClass {
public:
    typedef typename add_long<T>::type longT;
    longT multiply (longT a, longT b) { return a * b; }
};

And here is a small test:

#include <type_traits>

int main()
{
    MyClass<int> m;
    auto l = m.multiply(2, 3);
    static_assert(std::is_same<decltype(l), long int>::value, "Error!");
}
于 2013-03-07T23:15:49.997 に答える
4

@Andyは正しい答えを持っていますが、これは非常にうまく機能します。しかし、MyClassが「long」値のない型でインスタンス化された場合にコンパイル時エラーが必要な場合は、@ SteveJessopの優れたコメントと組み合わせて、次の解決策を提供します。

// --- Machinery to support double-precision 'T' to avoid overflow in method 'multiply' ---
// Note: uncomment typedef if don't want compile-time errors 
// when no "long" type exists
// ----
template<typename T>
struct add_long { /*typedef T type;*/ };

template<> struct add_long<int8_t>   { typedef int16_t  type; };
template<> struct add_long<int16_t>  { typedef int32_t  type; };
template<> struct add_long<int32_t>  { typedef int64_t  type; };
template<> struct add_long<uint8_t>  { typedef uint16_t type; };
template<> struct add_long<uint16_t> { typedef uint32_t type; };
template<> struct add_long<uint32_t> { typedef uint64_t type; };

template<> struct add_long<float>    { typedef double        type; };
template<> struct add_long<double>   { typedef long double   type; };

'longT'の使用例:

template<class T> class MyClass
{
    // Note: a compiler error on the next line means that 
    //       class T has no double-precision type defined above.
    typedef typename add_long<T>::type longT;
public:
    longT multiply (T a, T b) { return longT(a) * b; }
}

MyClassの使用例:

MyClass<float> my;
printf("result = %lf\n", my.multiply(3.4e38, 3.4e38));
于 2013-03-08T06:06:47.060 に答える