2013-03-07 22 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

相關問題