2013-03-07 69 views
10

有没有什么方法可以将乘法返回的精度加倍(以避免溢出)?将C++模板类型T修改为“long T”?

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

喜欢的东西:

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

所以这是否 '诠释', '长',或 '双' 被赋予,一个 '长整型', '很长很长' 或“长双'会从乘法中返回。

这是一个普遍的问题。我在内部使用double来解决它。但我的问题是,是否有任何机制在C++中将类型推广到其“长”变体?

+0

它可能会更好,如果你想避免溢出只使用'长long'为你的'T'。 – Pubby 2013-03-07 23:10:56

+4

'long'不是可以应用于类型名称的限定符; 'long int'是一个不可分割的类型名称,恰好与两个关键字'long'和'int'拼写在一起。 – 2013-03-07 23:11:45

+0

我不明白你为什么要使用“长T”。 T是一个模板参数,它可以是你想要的任何基本类型或实例对象,因为long *操作符被覆盖。在某些情况下,你可以将T投入长时间。 – user1929959 2013-03-07 23:12:50

回答

13

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

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!"); 
} 
+3

根据预期的用途,你可能想要从通用模板中省略'type',否则确保你得到编译错误if你用一个没有'long'er版本的类型来试试这个,因此无论如何都会溢出。为了安全起见,您可以使用'int8_t' - >'int16_t','int16_t' - >'int32_t'和'int32_t' - >'int64_t'来定义特化,以确保您真的在每个阶段都增加了大小。 Ofc的可移植性稍差,因为它们是可选类型,但是在系统上,代码不能移植到“multiply”可能溢出,这是最好的避免。 – 2013-03-07 23:21:25

+0

@SteveJessop:确实,很好的观察。它主要取决于'MyClass'是如何使用的 – 2013-03-07 23:24:17

+1

@SteveJessop:'unsigned'部分被“等等”评论覆盖;-) – 2013-03-07 23:24:42

2

@Andy有正确答案,效果很好。

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

:但是,对于那些谁想要一个编译时错误,如果MyClass的与一类为其中有没有“长”价值实例化,我和@ SteveJessop出色的留言,提供以下解决方案结合它“longT”的实例:为MyClass

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<float> my; 
printf("result = %lf\n", my.multiply(3.4e38, 3.4e38)); 
+0

在所有这些'intX_t's之间,寂寞的'long int'怎么样?如果'std :: int32_t'是'typedef'ed到'long int'呢? – 2013-03-08 08:37:41

+0

@ChristianRau:很好。这是遗留下来,并已被删除。 – 2013-03-08 20:25:40

相关问题