【问题标题】:Converting negative decimal to two's complement in C在C中将负十进制转换为二进制补码
【发布时间】:2021-05-16 10:12:53
【问题描述】:

我正在编写一个程序,假设输入始终是一个有效的负十进制整数,返回二进制补码表示(16 位)。

我的逻辑是我从命令行获取输入,然后通过简单的转换将其转换为二进制并将它们添加到初始化的二进制数组中。然后,我取一个补码(只需将 0 更改为 1,反之亦然)并将其放入 oneCom 数组中。但是,对于添加 1 部分来找到二进制补码,我认为这就是问题所在,但我正在努力寻找它。我正在对最低有效位执行二进制加法。

【问题讨论】:

  • 是的,你更喜欢保留你的逻辑和代码......但是你的代码完全被破坏了,你需要修复你的 sn-p,并发布一个Minimal, Reproducible and Complete 代码示例。编辑您的代码以使其看起来像可测试的东西,并发布一个显示您的输入问题以及预期和实际输出的最小示例。例如。如果您的length 变量是unsigned,那么length >= 0 将始终为真,但我们无法检查,因为您没有包含length... 的声明等等。

标签: c binary twos-complement


【解决方案1】:

当从一补码转换为二补码时,即加 1,您的循环应该从 LSB 开始,而不是从 MSB 开始。

因此,

                        for (j=15; j>=0; j--) { // <-- Error Here
                                if (onesCom[j] == 1 && carryOver == 1) {
                                        twosCom[j] = 0;
                                } else if (onesCom[j] == 0 && carryOver == 1) {
                                        twosCom[j] = 1;
                                        carryOver = 0;
                                } else {
                                        twosCom[j] = onesCom[j];
                                }
                           }

应替换为:

                        for (j=0; j<=15; j++) {
                                if (onesCom[j] == 1 && carryOver == 1) {
                                        twosCom[j] = 0;
                                } else if (onesCom[j] == 0 && carryOver == 1) {
                                        twosCom[j] = 1;
                                        carryOver = 0;
                                } else {
                                        twosCom[j] = onesCom[j];
                                }
                        }

在您的代码中,您计算​​一补码,然后推导出二补码。请注意,直接计算二补比较容易,以防您不需要一补,如下所示:

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

int main(int argc, char *argv[]) {
    int binary[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    if (argc == 1) return 1;
    int decimal = atoi(argv[1]);
    int counter = 0;
    if (decimal > -32768 && decimal < 0) {
        decimal = 65536 + decimal;
        while(decimal > 0) {
                binary[counter] = decimal%2;
                decimal = decimal/2;
                counter++;
        }
        for (int length = 15; length >=0; length--) {
                printf("%d", binary[length]);
        }
        printf ("\n");
    } 
    return 0;
}

【讨论】:

  • 我的代码中还有什么需要修复的吗?当我测试-211 时,我得到1248742504483355443232766-3863075360012487377921249376864124874261701.
  • 我通过-211 得到正确答案。你检查过 OneComplement 数组吗?
  • 等等,唯一的变化是改变了 for 循环吗?而且,对于您的其他解决方案,它不适用于我的代码..我不确定我做错了什么。我得到0000000011010011-211
  • 使用新代码,我得到1111111100101101 对应-211。对于您的代码,我只更改了 for 循环。在您的帖子中,您写道您得到了-211 的好答案。还是这样吗?
  • 这一行与Two's complement的定义有关。
【解决方案2】:

由于您的 sn-p 完全模糊,我只能建议您两种解决问题的方法:

  • 第一个假设您一直在进行二进制补码运算,在这种情况下,数字相加必须使用符号来完成。
  • 第二个假设您只解析无符号值并保留符号以在最后进行符号交换。

可能这两种方法都将导致几乎相同的效率并被编译成非常相似的代码。我对其中任何一个都没有偏好。

int decode(char *str, int base)
{
    int result = 0,
        c,
        neg = FALSE;

    /* skip whitespace, delete this if you don't
     * want to cope with whitespace */
    for (; isspace(c = *str); str++) {
        continue;
    }

    if (*str == '-') {
        neg = TRUE; /* negative */
        str++; /* skip it */
    }

    /* the next characters might be all digits */
    for (; isdigit(c = *str); str++) {

        /* multiply by the base */
        result *= base;

        /* add positive for positives and
         * subtract it for negatives */
        int d = c - '0'; /* convert c to the digit value */

        /* negative if number is negative */
        if (neg) d = -d;

        /* and add/subtract it */
        result = result + d;
    }

    /* :) got it!! */
    return result;
}

第二种方法是:

int decode(char *str, int base)
{
    int result = 0,
        c,
        neg = FALSE;

    /* skip whitespace, delete this if you don't
     * want to cope with whitespace */
    for (; isspace(c = *str); str++) {
        continue;
    }

    if (*str == '-') {
        neg = TRUE; /* negative */
        str++; /* skip it */
    }

    /* the next characters might be all digits */
    for (; isdigit(c = *str); str++) {

        /* multiply by the base */
        result *= base;

        /* add positive for positives and
         * subtract it for negatives */
        int d = c - '0'; /* convert c to the digit value */

        /* and add/subtract it */
        result = result + d;
    }

    /* :) got it!! */
    return neg ? -result : result;
}

你能看出区别吗? (提示,我已经删除了循环中的一行并在最后更改了一行:))

如果你想在一个完整、完整和可验证的示例中运行此代码,下面有一个,只需将上述函数之一替换另一个,然后运行即可。

#include <stdio.h>
#include <ctype.h>

/* these macros are for easy printing, and outputting the file, line and
 * function name where the trace is being made */
#define F(_f) __FILE__":%d:%s:"_f, __LINE__, __func__
#define P(_f, ...) printf(F(_f), ##__VA_ARGS__)

/* I use these for portability, as <stdbool.h> is not always available */
#define FALSE       (0)
#define TRUE        (!FALSE)

int decode(char *str, int base)
{
    /* substitute here the body of the function above you want to test */
}

int main()
{
    static char *tests[] = {
        "0", "-1", "-210", "-211", "-222", "1",
        "210", "211", "222", "5400",
        /* add more testing cases to your wish */
        NULL,
    };

    int i, passed = 0;
    for (i = 0; tests[i]; i++) {

        char *test = tests[i];
        int expected, actual;

        P("Testing '%s' conversion\n", test);

        /* expected, decoded with system routines */
        if (sscanf(test, "%i", &expected) != 1) {
            P("problem scanning %s\n", test);
            continue;
        }

        /* actual, decoded with our function */
        actual = decode(test, 10);
        char *operator = actual == expected ? "==" : "!=";
        P("Test result: actual(%i) %s expected(%i)\n",
                actual, operator, expected);
        if (actual == expected)
            passed++;
    }
    P("passed %d/%d tests\n", passed, i);
}

编辑

以下代码可让您轻松将值转换为二进制:

#define CHK(_n) ((_n) <= sz)

char *to_binary(int p_val, char *buf, size_t sz)
{
    CHK(2); /* at least two bytes of buffer space */
    buf += sz; /* we start from the end, backwards to avoid having to use
                * one bit masks moving all the time around */
    *--buf = '\0'; /* this is the last '\0' that should end the string */
    sz--; /* update buffer size */

    /* we operate better with unsigned, as the
     * sign doesn't get involved in shifts (we are reinterpreting
     * the sign bit as a normal bit, which makes the assumption that
     * integers are stored in two's complement.  This is essentially
     * nonportable code, but it will work in the stated assumptions. */
    unsigned val = (unsigned) p_val;

    /* the first below is the second char we check
     * above */
    do {
        *--buf = val & 1 ? '1' : '0';
        sz--;
        val >>= 1;
    } while (CHK(1) && val);
    return buf; /* return what we have */
}

最终的main() 代码如下所示:

int main()
{
    static char *tests[] = {
        "0", "-1", "-210", "-211", "-222", "1",
        "210", "211", "222", "5400",
        NULL,
    };

    int i, passed = 0;
    for (i = 0; tests[i]; i++) {

        char *test = tests[i];
        int expected, actual;

        P("Testing '%s' conversion\n", test);

        /* expected, decoded with system routines */
        if (sscanf(test, "%i", &expected) != 1) {
            P("problem scanning %s\n", test);
            continue;
        }

        /* actual, decoded with our function */
        actual = decode(test, 10);
        char *operator = actual == expected ? "==" : "!=";
        char buff[100]; /* temporary variable to hold the
                         * converted value to binary */
        P("Test result: actual(%i/0b%s)\n",
                actual,
                to_binary(actual, buff, sizeof buff));
        P("        %s expected(%i/0b%s)\n",
                operator,
                expected,
                to_binary(expected, buff, sizeof buff));
        if (actual == expected)
            passed++;
    }
    P("passed %d/%d tests\n", passed, i);
}

【讨论】:

    猜你喜欢
    • 2013-09-28
    • 1970-01-01
    • 2019-04-26
    • 1970-01-01
    • 2014-11-15
    • 2014-03-01
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多