即使将变量从 int 更改为 double 再到 long 后,给定的代码也无法获得更大的值

The given code fails for larger values even after changing variable from int to double to long

提问人:hash 提问时间:11/9/2023 最后编辑:273Khash 更新时间:11/9/2023 访问量:59

问:

这是问题陈述。

*以 10 为底的整数的补码

整数的补码是将所有 0 翻转为 1 以及将所有 1 翻转为 0 时得到的整数。

例如,整数 5 是二进制中的“101”,它的补码是“010”,即整数 2。 给定一个整数 n,返回其 complemet*

我看到了一些使用位掩码解决此问题的解决方案,这是我要解决的问题,但首先我想知道为什么下面给出的代码不起作用?

它适用于较小的值,但 输入:299475 输出: 224816 预期输出:224812

为了更大的价值,问题似乎仍然存在。

#include <math.h>
class Solution {
#include <math.h> 
public:
int bitwiseComplement(int n) {
long a = 0;
int i = 0;
if ( n == 0) { 
     return 1;
}
while ( n != 0 ) { 
    int b = n & 1;
    if ( b == 1) { 
        b = 0;
    }
    else if (b == 0){ 
        b = 1;
    }
    n = n >> 1;
    a = a + (b * pow(10, i));
    i++;
        
}
long sol = 0;
int k = 0;
while ( a != 0) { 
    int b = a % 10;
    sol = sol + (b * pow(2, k));
    k++;
    a = a/10;
}
return sol;}
};
C++ 循环 二进制 掩码

评论

7赞 PaulMcKenzie 11/9/2023
不要用于基于整数的问题。是一个浮点函数,有了它,您将继承与浮点计算相关的所有问题(例如不精确的结果)。powpow
1赞 Aconcagua 11/9/2023
顺便说一句:已经在一次操作中为您提供了二进制补码......如果你想计算二进制补码,“以 10 为基数”是误导性的,因为还有一个以 10 为基数的补码:647 得到 352——它们的位模式不是二进制补码......~number
0赞 Aconcagua 11/9/2023
等一下——您正在尝试计算一个以 10 为基数的数字,该数字与二进制中的原始数字具有相同的数字?如果这个数字很大,那么这个数字也会比原来的数字大得多,很可能不适合,因此你遭受了溢出(有符号整数的未定义行为! 在许多系统上(例如 Windows – 与 64 位 Linux 相比)具有相同的大小,因此也无济于事,而是尝试(或根本不依赖系统的大小并从标头尝试。intlongintlong longuint64_tcstdint
0赞 Aconcagua 11/9/2023
还要注意的是,一般来说,如果只对位模式进行操作,那么无符号类型是更好的选择,如果值变得太大,则不会遭受值左移为负值(实际上也是 UB)的影响。
3赞 Alan Birtles 11/9/2023
为什么要将结果计算为以 10 为基数的二进制数?为什么不直接计算结果呢?(a = a + b << i)

答:

1赞 Aconcagua 11/9/2023 #1

显然,您正在计算一个数字,其中十进制表示看起来像原始数字的二进制表示。

问题在于这些数字比原始数字大得多(例如,8 得到 1000、16 得到 10000 等)。

1010 已经无法再容纳 32 位(假设 - 有符号或无符号 - 在您的系统上具有该大小)——因此,您可以以这种方式安全转换而不会丢失信息的最大数字是 210 - 1 = 1023,任何更大的数字都会引起溢出——甚至更糟:当您选择有符号整数时,实际上是未定义的行为int

现在在许多系统上(例如 32 位 linux 或 windows——与 64 位 linux 相比)的大小与 相同,因此在这种情况下也无济于事;您可以尝试改为,或者,因为不必依赖特定于操作系统的大小,请从 header。当时仍然适合的 10 的最大幂是 19,因此您仍然可以计算其表示的最大数字现在是 220 - 1 = 1 048 575。但这仍然很小......longintunsigned long longuint64_t<cstdint>

现在,相比之下,精度甚至比同等大小的有符号整数差,因为它使用一位作为符号,11 位作为指数,剩下的 52 位作为尾数,所以 53 位作为值,包括隐式的,从而允许精确地表示 1015,因此 216 - 1 = 65535 是您可以计算表示的最大值。double

这个问题的解决方案是跳过以 10 为基数的中间表示,直接计算以 2 为基数的补码:

unsigned int bit = 0;
while(n) // uint32_t!
{
   c |= !(n & 1) << bit++; // or 1 - (n & 1), if you prefer...
   n >>= 1;
}