12

有没有办法将乘法返回的精度加倍(以避免溢出)?

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”。

这是一个普遍的问题。我正在通过在内部使用双精度来解决它。但我的问题是,是否有任何机制可以将类型提升为 C++ 中的“长”变体?

4

2 回答 2

15

一个可能的解决方案是定义自己的类型特征:

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...

这是您在课堂上使用它的方式:

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

这是一个小测试:

#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 被实例化为没有“长”值的类型时出现编译时错误的人,我将它与@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 回答