不久前,我創建了一堆用於定點值操作的C宏。受到SO上幾個問題和答案的鼓舞,我希望在計算密集型計劃中獲得性能提升。雖然代碼看起來能產生正確的結果,但我想知道它是不是太天真/過於簡化了,因爲它實際上比我的例程的常規浮點版本(我在Wintel上進行雙三次圖像插值)運行速度慢。您能否看看這段包含我的宏的代碼並提出一些改進建議,特別是在性能方面?謝謝。我的定點算術實現是否正確?
// these are architecture-dependent
typedef short int fixed16;
typedef int fixed32;
typedef __int64 fixed64;
// value of 2^n
#define POW2(n) (1 << n)
// create 16bit integer-based fixed point value from a floating point value, n is the number of bits reserved for the fractional part
#define FP_MAKE16(x, n) ((x) > 0.0 ? static_cast<fixed16>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed16>(ceil((x) * POW2(n) - 0.5)))
// the same, 32bit
#define FP_MAKE32(x, n) ((x) > 0.0 ? static_cast<fixed32>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed32>(ceil((x) * POW2(n) - 0.5)))
// and 64bit
#define FP_MAKE64(x, n) ((x) > 0.0 ? static_cast<fixed64>(floor((x) * POW2(n) + 0.5)) : static_cast<fixed64>(ceil((x) * POW2(n) - 0.5)))
// convert a fixed-point integer from one (n) format to another (m) assuming n < m
#define FP_CONVERT_UP(x, n, m) ((x) << (m-n))
// same for n > m
#define FP_CONVERT_DOWN(x, n, m) ((x) >> (n-m))
// convert floating-point value back to float
#define FP_FLOAT(x, n) (static_cast<float>(x)/POW2(n))
// same for double
#define FP_DOUBLE(x, n) (static_cast<double>(x)/POW2(n))
// and for int. fractional part will be discarded!
#define FP_INT(x, n) ((x) >> n)
// arithmetic operations for same-format numbers
#define FP_NEG(a) ((~a)+1)
#define FP_ADD(a, b) ((a) + (b))
#define FP_SUB(a, b) ((a) + FP_NEG(b))
#define FP_MUL(a, b, n) (((a) * (b)) >> n)
#define FP_DIV(a, b, n) (((a) << n)/(b))
#define FP_POW2(a, n) (((a) * (a)) >> n)
#define FP_POW3(a, n) (((((a) * (a)) >> n)*(a)) >> n)
// arithmetic for different-format numbers, assuming n is the target (result) format and n > m
#define FP_ADD_UP(a, b, n, m) ((a) + ((b) << (n-m)))
#define FP_SUB_UP(a, b, n, m) ((a) + FP_NEG((b) << (n-m)))
#define FP_MUL_UP(a, b, n, m) (((a) * (b)) >> m)
#define FP_DIV_UP(a, b, n, m) (((a) << m)/(b))
// same for n < m
#define FP_ADD_DOWN(a, b, n, m) ((a) + ((b) >> (m-n)))
#define FP_SUB_DOWN(a, b, n, m) ((a) + FP_NEG((b) >> (m-n)))
#define FP_MUL_DOWN(a, b, n, m) (((a) * (b)) >> m)
#define FP_DIV_DOWN(a, b, n, m) (((a) << m)/(b))
編輯:基本上,答案和註釋轉向這兩點:
- 的代碼是可怕的,很難使用和維護:我wholehartedly同意並會花時間把它封裝在一個類中。我對一些表現出色的問題表示了一些擔憂,並且我確信它們是毫無根據的,我毫不知情地付出了所有的麻煩。 :)
- 無論如何,固定點並不值得麻煩:儘管在我的平臺上這可能是正確的,但我創建這個來提高我的代碼在沒有浮點硬件的平臺上的執行速度。在那裏,浮點操作耗時過長,固定是要走的路。我只在英特爾測試了這個,因爲目前我無法訪問目標硬件
雖然我非常感謝迄今爲止提供的洞察力,但我希望聽到某個實際做了一些計算的人定點告訴我這些算術運算是否確實是要走的路。也許還有一些我沒有意識到的額外的點點滴滴,這會對性能或精度產生影響嗎?換句話說,如果我要封裝這些代碼,我可以在內聯運算符函數中保留基本相同的算術指令,還是應該以某種方式更改它們?
刪除'C'標籤,因爲這不是'C'代碼。 – Puppy 2011-03-17 15:58:31
使用這些宏編寫的代碼將是殘酷的。你爲什麼想做這個?說實話,如果我看到'#define FP_ADD(a,b)((a)+(b))'代碼被強制維護,我會深表擔憂。 – meagar 2011-03-17 15:58:32
我想我會避免一些開銷,如果我拒絕整個面向對象的東西。我可以將整個東西包裝在一個類和重載算術運算符中,但是由於AFAIK它們實際上被實現爲具有調用開銷的函數,所以我希望通過這種方式獲得一些性能。這些天我有點迷戀。另外,我想也許編譯器會更容易優化它。 – neuviemeporte 2011-03-17 16:02:52