【问题标题】:Converting binary to decimal goes wrong in C在 C 中将二进制转换为十进制会出错
【发布时间】:2021-11-16 19:34:42
【问题描述】:

我编写了这个程序,将二进制数传递给函数并打印该二进制数的十进制值。问题是如果二进制数变大(如 11 个数字),该函数会打印完全不同的东西。我现在尝试解决了几个小时,但没有任何效果。

所以我的问题是:如何更改我的程序,以便在二进制数变大的情况下打印正确的十进制数?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>

int int_log2_64(uint64_t x) { return 63 ^ __builtin_clzll(x); }
#define K(T) (((sizeof(#T) - 1) << 32) - T)
int digit_count(uint32_t x)
{

    static uint64_t table[] = {
        K(0), K(0), K(0),
        K(10), K(10), K(10),                         // 64
        K(100), K(100), K(100),                      // 512
        K(1000), K(1000), K(1000),                   // 4096
        K(10000), K(10000), K(10000),                // 32k
        K(100000), K(100000), K(100000),             // 256k
        K(1000000), K(1000000), K(1000000),          // 2048k
        K(10000000), K(10000000), K(10000000),       // 16M
        K(100000000), K(100000000), K(100000000),    // 128M
        K(1000000000), K(1000000000), K(1000000000), // 1024M
        K(1000000000), K(1000000000)                 // 4B
    };

    int lg2 = int_log2_64(x);

    uint64_t n = (uint64_t)(x) + table[lg2];

    return n >> 32;
}

void binaryToDecimal(long long int bin)
{
    int l = digit_count(bin);
    char str[l];
    itoa(bin, str, 10);
    float sum[l];
    int x = l - 1;
    float answer;

    for (int i = 0; i < l; i++)
    {
        if (str[i] == '1')
        {
            sum[i] = pow(2, x);
        }
        x--;
    }

    for (int i = 0; i < l; i++)
    {
        answer = answer + sum[i];
    }
    printf("%.0f", answer);
}

int main()
{
    long long int bin = 10101101101;
    binaryToDecimal(bin);
}

附:我把代码改成了这个,它可以工作

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

void binaryToDecimal(char *bin)
{
    int l = strlen(bin);
    int x = l - 1;
    float sum[l];
    float answer = 0;

    for (int i = 0; i < l; i++)
    {
        if (bin[i] == '1')
            answer += pow(2, x);
        else
            sum[i] = 0;
        x--;
    }

    printf("%.0f", answer);
}

int main()
{
    binaryToDecimal("010101101101");
}

【问题讨论】:

  • 你想让binaryToDecimal(100)返回4吗?您是否意识到您可以用 64 位表示的最大 int184467440737095516159223372036854775807,如果已签名)?
  • 另外,itoa()(不在标准中,不在 POSIX 中)将int 作为第一个参数。您正在使用long long int,它可能会被转换为警告。打开所有编译器警告。 注意警告
  • 最大无符号 32 位整数是 4294967295,有符号 32 位整数是 2147483647
  • 除了使用 itoa 和使用 float 的所有问题之外,char str[l] 太短了,因为它没有空间容纳空终止符(也没有空间容纳可能导致的减号将long long int 转换为int 时算术溢出)。另外,answer 还没有被初始化。
  • @hasan void binaryToDecimal(long long int bin)。输入参数应该是一个字符串而不是long long int

标签: c binary decimal


【解决方案1】:

如何更改我的程序,以便在二进制数变大的情况下打印正确的十进制数?

通过将bin 变量设为字符串

也就是说,你想要

void binaryToDecimal(const char *str)
{
   ...
}

然后你可以调用类似的东西

binaryToDecimal("101111000110000101001110");

在进行基本转换时,我认为使用整数变量作为输入总是错误的。如果我说

int x = 12;

x 是十进制整数”是真的。 x 是一个整数,句号——我只是碰巧使用了一个十进制常量来获取一个值。或者如果我说

int y = 0x7b;

那么说y 是十六进制就没有意义了——同样,y 只是一个整数。

表示整数的基数很重要:

  • 在输入时,当我们使用scanf%d%o%x 格式从用户那里读取数字时
  • 使用标准库atoistrtol 函数转换字符串时
  • 在输出时,当我们使用printf%d%o%x 格式打印数字时

但在所有这些情况下,基数很重要的表示是一串数字字符,而不是整数。

不编写接受整数的“binary to ...”函数有两个原因。一个是,正如您所看到的,它人为且不必要地限制了您可以转换的数字范围。但更大的原因是这会让你的读者感到困惑,因为它只是错误。如果我看到一个函数调用

f(1001)

我想,“好吧,常量值 1001 正在传递给函数 f。”在任何情况下,我都无法想象它实际上是在尝试传递二进制数 9。

【讨论】:

  • 对于初级人类程序员来说,它是“十进制”(在这个阶段是“数字”的同义词)。理解会随着时间而来
  • 谢谢,我把代码改成了几行就可以了!
【解决方案2】:

您的代码过于复杂。切勿使用浮点数进行整数计算。

unsigned binaryToDecimal(long long int bin)
{
    unsigned answer = 0;
    int shift = 0;
    while(bin)
    {
        answer += (bin % 10) << shift++;
        bin /= 10;
    }
    return answer;
}

int main()
{
    long long int bin = 10101101101;
    printf("%u\n", binaryToDecimal(bin));
}

https://godbolt.org/z/5E8Gv6oqf

或者使用字符串传递二进制数:

unsigned binaryToDecimal(char *str)
{
    unsigned answer = 0;
    while(*str)
    {
        answer <<= 1;
        answer += *str++ == '1';
    }
    return answer;
}

int main()
{ 
    printf("%u\n", binaryToDecimal("10101101101"));
}

https://godbolt.org/z/4vfnETY1f

【讨论】:

    猜你喜欢
    • 2012-12-26
    • 1970-01-01
    • 2019-03-24
    • 2019-04-26
    • 2012-06-26
    • 1970-01-01
    • 2020-09-10
    • 2021-12-26
    相关资源
    最近更新 更多