簡體   English   中英

使用C在定點算法中使用32位數據進行64位操作

[英]Doing 64 bit manipulation using 32 bit data in Fixed point arithmetic using C

我陷入了一個問題。 我正在僅支持32位操作的硬件上工作。

sizeof(int64_t) is 4. Sizeof(int) is 4.  

我正在移植一個應用程序,該應用程序假定int64_t的大小為8個字節。 問題是它具有此宏BIG_MULL(a,b)((int64_t)(a)*(int64_t)(b)>> 23)

結果始終是32位整數,但是由於我的系統不支持64位操作,因此它總是向我返回該操作的LSB,所有結果的取整使我的系統崩潰。

有人可以幫我嗎?

此致Vikas Gupta

您根本無法可靠地以32位整數存儲64位數據。 您要么必須重新設計軟件,以使用32位整數作為最大可用大小,要么提供一種為64位整數提供64位存儲的方法。 都不是簡單的-要禮貌。

創建一種結構是一種可能的方法-不是一件容易的事:

typedef struct { uint32_t msw; uint32_t lsw; } INT64_t;

然后,您可以將數據存儲在兩個32位整數中,並對結構的組成部分進行算術運算。 當然,一般來說,32位乘32位的乘法會產生64位的答案。 要進行完全乘法運算而不會溢出,您可能被迫存儲4個16位無符號數字(因為可以乘以16位數字以產生32位結果而不會產生溢出)。 您將使用函數來完成艱苦的工作-因此,該宏將成為對一個函數的調用,該函數接受兩個INT64_t結構(指向?)並返回一個。

它不會像以前那樣快...但是,如果他們在必要的地方都使用宏,它就有一定的工作機會。

我假設您要相乘的數字是32位整數。 您只想生成一個大於32位的乘積。 然后,您要從產品中刪除一些已知數量的最低有效位。

首先,這會將兩個整數相乘並溢出。

#define WORD_MASK ((1<<16) - 1)
#define LOW_WORD(x)  (x & WORD_MASK) 
#define HIGH_WORD(x) ((x & (WORD_MASK<<16)) >> 16)
#define BIG_MULL(a, b) \
    ((LOW_WORD(a)  * LOW_WORD(b))  <<  0) + \
    ((LOW_WORD(a)  * HIGH_WORD(b)) << 16) + \
    ((HIGH_WORD(a) * LOW_WORD(b))  << 16) + \
    ((HIGH_WORD(a) * HIGH_WORD(b)) << 32)

如果要從中刪除23個最低有效位,則可以像這樣調整它。

#define WORD_MASK ((1<<16) - 1)
#define LOW_WORD(x)  (x & WORD_MASK) 
#define HIGH_WORD(x) ((x & (WORD_MASK<<16)) >> 16)
#define BIG_MULL(a, b) \
    ((LOW_WORD(a)  * HIGH_WORD(b)) >> 7) + \
    ((HIGH_WORD(a) * LOW_WORD(b))  >> 7) + \
    ((HIGH_WORD(a) * HIGH_WORD(b)) << 9)

請注意,如果乘法的實際乘積大於41(= 64-23)位,這仍然會溢出。


更新:

我已經調整了代碼以處理有符號整數。

#define LOW_WORD(x)  (((x) << 16) >> 16) 
#define HIGH_WORD(x) ((x) >> 16)
#define ABS(x) (((x) >= 0) ? (x) : -(x))
#define SIGN(x) (((x) >= 0) ? 1 : -1)
#define UNSIGNED_BIG_MULT(a, b) \
    (((LOW_WORD((a))  * HIGH_WORD((b))) >> 7) + \
     ((HIGH_WORD((a)) * LOW_WORD((b)))  >> 7) + \
     ((HIGH_WORD((a)) * HIGH_WORD((b))) << 9))
#define BIG_MULT(a, b) \
    (UNSIGNED_BIG_MULT(ABS((a)), ABS((b))) * \
     SIGN((a)) * \
     SIGN((b)))

如果您將宏更改為

#define  BIG_MULL(a,b) ( (int64_t)(a) * (int64_t)(b))

因為它看起來像為您定義了int64_t它應該工作

盡管sizeof(int64_t) == 4提出了其他問題,但這是錯誤的:

#define BIG_MULL(a,b) ( (int64_t)(a) * (int64_t)(b) >> 23)

如果平台支持,則標准要求intN_t類型的N = intN_t和64...。

您應該使用的類型是intmax_t ,它被定義為平台支持的最大整數類型。 如果您的平台沒有64位整數,則代碼不會因intmax_t而中斷。

您可能想要查看一個bignum庫,例如GNU GMP 從某種意義上說,bignum庫是多余的,因為它們通常支持任意大小的數字,而不僅僅是增加固定大小的數字。 但是,由於它已經完成,因此它做得比您想做的要多的事實可能不是問題。

另一種方法是將兩個32位int打包到類似於Microsoft LARGE_INTEGER的結構中:

typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    };
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
    LONGLONG QuadPart;
} LARGE_INTEGER;

並創建接受此類型參數並返回此類型結構結果的函數。 您也可以將這些操作包裝在C ++類中,該類將允許您定義運算符重載,使表達式看起來更自然。 但是,我將看一下已經制作的庫(例如GMP),看看它們是否可以使用-可以節省很多工作。

我只是希望您不需要在直的C語言中使用像這樣的結構來實現除法-這很痛苦而且運行緩慢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM