不同的32位转换成long/__int64,为什么?
我正在编写自己的小型多精度库,在编写减法方法时,遇到了一些奇怪的错误。这是我为多精度减法编写的代码块:
/* subtraction */
for (; p_aReverseIter != a.m_elements.rend(); ++p_aReverseIter, ++p_bReverseIter)
{
temp = static_cast<__int64>(static_cast<__int64>(p_aReverseIter->m_Value) -
static_cast<__int64>(p_bReverseIter->m_Value) +
(carry));
--- debug output-
p_aReverseIter->m_Value = static_cast<unsigned int>(temp & 0xffffffff);
carry = static_cast<unsigned long>(temp >> 32);
}
p_aReverseIter->m_Value 是 32 位无符号整数,而 a,b 是 BigInt。值以大端格式存储在向量内。 temp 是 __int64 并且进位应该作为 32 位无符号长。
假设我们从 a 中减去 b,a > 。 b(无符号减法),但b中的所有32位字都大于a。该例程产生以下输出:
a = 0xfefefefe (10 elem) 0xfefefefe (10 elem) 0xfefefefe (10 elem)
0xfefefefe (10 elem)
b = 0x12 (2 elem) 0x12121212 (9 elem) 0x12121212 (9 elem) 0x12121212
(9 elem) 0x12121212 (9 elem)
a[i]: 12121212
b[i]: fefefefe
old carry: 0
temp = a - b + carry: ffffffff13131314
Value: 13131314
new carry: ffffffffffffffff
a[i]: 12121212
b[i]: fefefefe
old carry: ffffffff
temp = a - b + carry: 13131313
Value: 13131313
new carry: 0
a[i]: 12121212
b[i]: fefefefe
old carry: 0
temp = a - b + carry: ffffffff13131314
Value: 13131314
new carry: ffffffffffffffff
a[i]: 12121212
b[i]: fefefefe
old carry: ffffffff
temp = a - b + carry: 13131313
Value: 13131313
new carry: 0
...
但进位应始终为 0xffffffffff。每次它为零时,结果都是“13131314”,这是错误的。现在让我们将进位从 unsigned long 更改为 unsigned __int64 并更改
carry = static_cast<unsigned long>(temp >> 32);
为
carry = static_cast<unsigned __int64>(temp >> 32);
现在进位始终计算正确并设置为 0xffffffff。 但是右移 2^32 的 64 位值应该总是产生 32 位结果。
我的问题是:为了理解不同的结果,我错过了什么?
非常感谢。
I'm writing my own small multiprecision library, and while writing the method for subtraction, I encountered some weird error. Here is the code block I wrote for for multiprecision subtraction:
/* subtraction */
for (; p_aReverseIter != a.m_elements.rend(); ++p_aReverseIter, ++p_bReverseIter)
{
temp = static_cast<__int64>(static_cast<__int64>(p_aReverseIter->m_Value) -
static_cast<__int64>(p_bReverseIter->m_Value) +
(carry));
--- debug output-
p_aReverseIter->m_Value = static_cast<unsigned int>(temp & 0xffffffff);
carry = static_cast<unsigned long>(temp >> 32);
}
p_aReverseIter->m_Value is 32 bit unsigned int, while a,b are BigInt. Values are stored inside a vector in Big Endian style.
temp is __int64 and carry should work as 32 bit unsigned long.
Let's say we substract b from a, a > b (unsigned subtraction), but all the 32bit words in b are larger then a. This routine produces following output:
a = 0xfefefefe (10 elem) 0xfefefefe (10 elem) 0xfefefefe (10 elem)
0xfefefefe (10 elem)
b = 0x12 (2 elem) 0x12121212 (9 elem) 0x12121212 (9 elem) 0x12121212
(9 elem) 0x12121212 (9 elem)
a[i]: 12121212
b[i]: fefefefe
old carry: 0
temp = a - b + carry: ffffffff13131314
Value: 13131314
new carry: ffffffffffffffff
a[i]: 12121212
b[i]: fefefefe
old carry: ffffffff
temp = a - b + carry: 13131313
Value: 13131313
new carry: 0
a[i]: 12121212
b[i]: fefefefe
old carry: 0
temp = a - b + carry: ffffffff13131314
Value: 13131314
new carry: ffffffffffffffff
a[i]: 12121212
b[i]: fefefefe
old carry: ffffffff
temp = a - b + carry: 13131313
Value: 13131313
new carry: 0
...
But the carry should always be 0xfffffffff. Everytime it is zero, the result is '13131314' which is wrong. Now lets change the carry from unsigned long to unsigned __int64 and
carry = static_cast<unsigned long>(temp >> 32);
to
carry = static_cast<unsigned __int64>(temp >> 32);
Now the carry is always calculated correctly and is set to 0xffffffff.
But rightshifting a 64bit value of 2^32 should always produce a 32 bit result.
My question is: To understand the different results, what am I missing?
Thank you very much.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的环境中的
sizeof(long)
是什么?我怀疑如果你测试一下你会发现它是 4,即你的unsigned long
实际上是 32 位值。What's
sizeof(long)
in your environment? I suspect if you test you'll find it's 4, i.e. yourunsigned long
are actually 32-bit values.不要对这样的值进行硬编码。您无法保证
unsigned long
具有任何特定大小(并且它通常不会像您假设的那样是 64 位)。因此,位移位以及按位“与”必须考虑到这一点。您可以将 32 替换为sizeof(unsigned long)*8
之类的内容。而不是0xffffffff
,~0L
就可以解决问题,或者如果你勇敢的话,可能是 -1。 (只要有符号整数由二进制补码表示,它就可以工作,通常是这种情况,但标准不保证)Don't hardcode values like these. You're not guaranteed that an
unsigned long
is any particular size (and it often won't be 64-bit as you assume). So bit shifting as well as your bitwise 'and' have to take that into account. You could replace the 32 with something likesizeof(unsigned long)*8
perhaps. And instead of0xffffffff
,~0L
would do the trick, or perhaps -1 if you're feeling brave. (It'll work as long as signed ints are represented by two's complement, which is usually the case, but it's not guaranteed by the standard)