我遇到了问题。我正在开发一个只支持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,舍入所有结果使我的系统崩溃。
有人能帮助我吗?
此致 维卡斯古普塔
答案 0 :(得分:7)
您无法在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结构的两个(指向?)并返回一个。
它不会像以前那么快......但如果他们在任何地方使用宏,它就有可能工作。
答案 1 :(得分:3)
我假设您尝试乘以的数字是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)))
答案 2 :(得分:0)
如果您将宏更改为
#define BIG_MULL(a,b) ( (int64_t)(a) * (int64_t)(b))
因为它看起来像是为你定义了int64_t它应该工作
答案 3 :(得分:0)
虽然sizeof(int64_t) == 4
提出了其他问题,但这是错误的:
#define BIG_MULL(a,b) ( (int64_t)(a) * (int64_t)(b) >> 23)
标准要求intN_t
类型的值为N = 8,16,32和64 ... 如果平台支持它们。
您应该使用的类型是intmax_t
,它被定义为平台支持的最大整数类型。如果您的平台没有64位整数,则代码不会因intmax_t
而中断。
答案 4 :(得分:0)
您可能希望查看一个bignum库,例如GNU GMP。在某种意义上,bignum库是过度的,因为它们通常支持任意大小的数字,而不仅仅是增加固定大小的数字。但是,由于它已经完成,它的功能超出了你想要的事实可能不是问题。
另一种方法是将一些32位整数打包到类似于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中使用这样的结构实现除法 - 这很痛苦并且运行缓慢。