简体   繁体   English

使用溢出的二进制补码

[英]Two's complement using overflow

On Stack Overflow, some people have already answered the question of converting an integer in binary notation to two's complement.在 Stack Overflow 上,有些人已经回答了将二进制表示法中的 integer 转换为二进制补码的问题。 Anyway, I did not find any of the answers I saw satisfactory because they do not consider the number of bits being predetermined.无论如何,我没有找到任何令我满意的答案,因为他们没有考虑预先确定的位数。 Also, the code I found on Stack Overflow crashes the terminal or gives strange errors with large numbers.此外,我在 Stack Overflow 上找到的代码会使终端崩溃或给出大量奇怪的错误。

For these reasons, I have rewritten the following Bash function from scratch, which seems to accomplish the task I wish to give it correctly.由于这些原因,我从头开始重写了以下 Bash function ,这似乎正确地完成了我希望交给它的任务。 I have commented on the code for clarity.为了清楚起见,我对代码进行了评论。

As you can see, I intentionally generate an overflow , in the line: x=$((2**($bits-1)-$x));如您所见,我故意在以下行中生成一个溢出x=$((2**($bits-1)-$x));

My question is whether this code is always reliable in Bash since, in other languages, the overflow is an error condition;我的问题是这段代码在 Bash 中是否总是可靠的,因为在其他语言中,溢出是一种错误情况; here, however, I use it to get the desired result.但是,在这里,我使用它来获得所需的结果。

# Given a decimal number, prints its two's complement with the number of bits used by Bash
twos() {
    x=$1; # input number in base 10
    msb="0"; # the "most significant bit" is 0 for positive integers, 1 for negative integers
    bits=$(getconf LONG_BIT); # detect the machine architecture, 32bit or 64bit
    if [ "$x" -lt 0 ]; then
        # the input number $x is negative
        x=$((2**($bits-1)-$x)); # 2^(bits-1)-1 is the max integer number, -$x is positive, so it's an overflow
        msb="1"; # "most significant bit" of negative numbers
    fi
    out=$(echo "obase=2;$x" | bc | tr -dc '0-9'); # conversion of $x to binary base, any sign is removed
    n=$(($bits-1-${#out})); # number of zeros to add
    if [ "$n" -gt 0 ]; then
        zeros=$(printf '%0.s0' $(seq 1 $n)); # string consisting only of zeros
    else
        zeros=""; # deletes the variable that may be left in memory from a previous function call
    fi
    echo $msb$zeros$out; # prints the two's complement
}

Some examples:一些例子:

$ twos 0
0000000000000000000000000000000000000000000000000000000000000000
$ twos 1
0000000000000000000000000000000000000000000000000000000000000001
$ twos 2
0000000000000000000000000000000000000000000000000000000000000010
$ twos 100
0000000000000000000000000000000000000000000000000000000001100100
$ twos -1
1111111111111111111111111111111111111111111111111111111111111111
$ twos -2
1111111111111111111111111111111111111111111111111111111111111110
$ twos -100
1111111111111111111111111111111111111111111111111111111110011100
$ twos 9223372036854775807
0111111111111111111111111111111111111111111111111111111111111111
$ twos -9223372036854775808
1000000000000000000000000000000000000000000000000000000000000000

A bit simpler:简单一点:

twos() {
  n=$(getconf LONG_BIT)
  printf 'obase=2; 2^%d+%d\n' "$n" "$1" | bc | sed -E "s/.*(.{$n})$/\1/"
}

twos 100
0000000000000000000000000000000000000000000000000000000001100100

This simply uses bc to add 2^n (where n is 32 or 64), print in base 2 and keeps only the n least significant bits.这只是使用bc添加2^n (其中n为 32 或 64),以 2 为基数打印并仅保留n最低有效位。

Note that technically the two's complement of a number is its opposite.请注意,从技术上讲,数字的二进制补码是相反的。 So what you are looking for is more the binary representation of a number in two's complement .所以你正在寻找的更多是二进制补码中数字的二进制表示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM