在C中做二进制算术的最佳方法是什么?

时间:2009-03-23 05:09:58

标签: c binary performance math processing-efficiency

我正在学习C并编写一个简单的程序,它将假设每个二进制数为2个字符串值,并根据用户选择执行算术运算:

  • 添加两个值
  • 从输入1减去输入2,或
  • 将这两个值相乘。

我的实现假定字符串中的每个字符都是二进制位,例如char bin5 = "0101";,但似乎太天真的方法是一次解析一个字符串。理想情况下,我希望直接使用二进制值。

在C中执行此操作的最有效方法是什么?有没有更好的方法将输入视为二进制值而不是scanf()并从字符串中获取每个位?

我做了一些研究,但从初学者的角度来看,我没有发现任何明显更好的方法。任何建议将不胜感激!

5 个答案:

答案 0 :(得分:12)

<强>建议:
没有多少比一次在字符串中进行字符并确保用户只输入1和0更好。请记住,即使您假设所有内容都是10,您也可以编写真正的快速汇编程序,但实际上并不是这样想要那样做。用户可以输入任何内容,并且您希望能够告诉他们是否搞砸了。

与添加实际数字可能需要的几个周期相比,这似乎令人难以置信地缓慢但是如果你在纳秒或毫秒内得到你的答案真的很重要吗?无论如何,人类只能检测到30毫秒的延迟。

最后,从用户输入并将输出写入屏幕比解析字符串或添加数字需要更长的时间,因此您的算法不是这里的瓶颈。保存您对实际计算密集型事物的花哨优化: - )。

你应该关注的是让任务减少人力。并且,事实证明有人已经为你做了这件事。

<强>解决方案:
看看the strtol() manpage

long strtol(const char *nptr, char **endptr, int base);

这将允许您将任何基数中的字符串(nptr)转换为long。它也会检查错误。转换二进制字符串的示例用法:

#include <stdlib.h>

char buf[MAX_BUF];
get_some_input(buf);

char *err;
long number = strtol(buf, &err, 2);
if (*err) {
    // bad input: try again?
} else {
    // number is now a long converted from a valid binary string.
}

提供基数2告诉strtol转换二进制文字。

答案 1 :(得分:3)

首先我建议你按照tgamblin的建议使用像strtol这样的东西, 最好使用lib给你的东西,而不是一遍又一遍地创建轮子。

但是既然你正在学习C,那我就做了一个没有strtol的小版本, 这既不快也不安全,但我确实以位操作为例。

int main()
{
    unsigned int data = 0;
    int i = 0;

    char str[] = "1001";

    char* pos;
    pos = &str[strlen(str)-1];

    while(*pos == '0' || *pos == '1')
    {
        (*pos) -= '0';
        data += (*pos) << i;

        i++;
        pos--;
    }

    printf("data %d\n", data);
    return 0;
}

答案 2 :(得分:1)

为了获得最佳性能,您需要区分功能的可信和不可信输入。

例如,应检查接受用户输入的getBinNum()函数,检查有效字符并压缩以删除前导零。首先,我们将展示一个通用的就地压缩函数:

// General purpose compression removes leading zeroes.
void compBinNum (char *num) {
    char *src, *dst;

    // Find first non-'0' and move chars if there are leading '0' chars.
    for (src = dst = num; *src == '0'; src++);
    if (src != dst) {
        while (*src != '\0')
            *dst++ = *src++;
        *dst = '\0';
    }

    // Make zero if we removed the last zero.
    if (*num == '\0')
            strcpy (num, "0");
}

然后提供一个checker函数,该函数返回传入的值,如果它无效则返回NULL:

// Check untested number, return NULL if bad.
char *checkBinNum (char *num) {
    char *ptr;

    // Check for valid number.
    for (ptr = num; *ptr == '0'; ptr++)
        if ((*ptr != '1') && (*ptr != '0'))
            return NULL;

    return num;
}

然后输入函数本身:

#define MAXBIN 256

// Get number from (untrusted) user, return NULL if bad.
char *getBinNum (char *prompt) {
    char *num, *ptr;

    // Allocate space for the number.
    if ((num = malloc (MAXBIN)) == NULL)
        return NULL;

    // Get the number from the user.
    printf ("%s: ", prompt);
    if (fgets (num, MAXBIN, stdin) == NULL) {
        free (num);
        return NULL;
    }

    // Remove newline if there.
    if (num[strlen (num) - 1] == '\n')
        num[strlen (num) - 1] = '\0';

    // Check for valid number then compress.
    if (checkBinNum (num) == NULL) {
        free (num);
        return NULL;
    }
    compBinNum (num);

    return num;
}

应该编写要添加或乘法的其他函数,以假设输入已经有效,因为它将由此库中的某个函数创建。我不会为他们提供代码,因为它与问题无关:

char *addBinNum (char *num1, char *num2) {...}
char *mulBinNum (char *num1, char *num2) {...}

如果用户选择从getBinNum()以外的地方获取数据,您可以允许他们拨打checkBinNum()进行验证。

如果你真的是偏执狂,你可以检查传递给你的例程的每个数字并采取相应的行动(返回NULL),但这需要相对昂贵的检查,这是不必要的。

答案 3 :(得分:0)

将字符串解析为整数,然后对整数执行数学会不会更容易?

我认为这是一项学校作业,但我赞成你,因为你似乎正在努力。

答案 4 :(得分:-1)

假设字符串是二进制数,仅仅因为它只包含来自集合{0,1}的数字是危险的。例如,当您的输入为“11”时,用户可能意味着十进制十一,而不是二进制三。正是这种疏忽导致了可怕的错误。您的输入模糊不完整,您应该确实要求用户指定基数。