不同的32位转换成long/__int64,为什么?

发布于 2024-08-12 06:06:22 字数 1843 浏览 1 评论 0原文

我正在编写自己的小型多精度库,在编写减法方法时,遇到了一些奇怪的错误。这是我为多精度减法编写的代码块:

/* 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

城歌 2024-08-19 06:06:22

您的环境中的 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. your unsigned long are actually 32-bit values.

唐婉 2024-08-19 06:06:22
  p_aReverseIter->m_Value = static_cast<unsigned int>(temp & 0xffffffff); 
  carry = static_cast<unsigned long>(temp >> 32);

不要对这样的值进行硬编码。您无法保证 unsigned long 具有任何特定大小(并且它通常不会像您假设的那样是 64 位)。因此,位移位以及按位“与”必须考虑到这一点。您可以将 32 替换为 sizeof(unsigned long)*8 之类的内容。而不是 0xffffffff~0L 就可以解决问题,或者如果你勇敢的话,可能是 -1。 (只要有符号整数由二进制补码表示,它就可以工作,通常是这种情况,但标准不保证)

  p_aReverseIter->m_Value = static_cast<unsigned int>(temp & 0xffffffff); 
  carry = static_cast<unsigned long>(temp >> 32);

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 like sizeof(unsigned long)*8 perhaps. And instead of 0xffffffff, ~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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文