[英]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.