二进制补码在java中给出不同的答案

问题描述

抱歉,如果我的问题是基本问题或与另一个问题重复。无论如何,我正在尝试执行二进制补码以更改数字的符号并在 java 中检查结果,但结果与我手动计算的结果不同。

例如:
二进制中的 8 是 00001000
执行 2 的补码后的二进制 -8 应为 11111000

但是当我使用 Integer.parseInt("11111000",2) 而不是 -8 时,我得到 248。
我是否误解了 2 的补码概念,或者 Java 中有什么我不知道的东西。

你能帮我吗?

解决方法

如果您查看 javadoc,您将看到:

将字符串参数解析为第二个参数指定的基数中的有符号整数。字符串中的字符必须都是指定基数的数字(由 Character.digit(char,int) 是否返回非负值决定),除了第一个字符可以是 ASCII 减号 '-' ('\u002D ') 表示负值或 ASCII 加号 '+' ('\u002B') 表示正值。返回结果整数值。

Java 的 Integer.parseInt 不接受 2 补码字符串。事实上,如果你提供一个 32 个字符的字符串,你会得到一个异常(最左边的位是内部为符号保留的)。

,

我是否误解了 2 的补码概念,或者 Java 中有一些我不知道的东西。

是的,您错过的是 Integer.parseInt("ones and zeroes",2) 不是 java-ese for:这里有一些位,请给我这个确切位序列的 int 值。

正如方法所说,“解析这个数字”。 2 的补码不是街上普通人所理解的有效数学。

如果我拿着麦克风出去,然后在一张纸上写下 11111000,然后在街上随便问一些人:这是以 2 为底的,它是什么数字 - 你希望他们说 -8,你'显然已经走到了尽头。

需要明确的是,Integer.parseInt 不会永远给你一个负数,除非你传递给它的字符串以减号开头。它会给你一个正数,或者如果字符串中的数字不适合 int 数字的正空间,它就会崩溃。

好的,那我该怎么做呢?

实际上并没有直接的方法,2 的补码是一个您可以观察到的实现细节,但它永远不会让您默默地编写(无论是字符串形式还是文字)a正数,可以是位、十进制或十六进制,但仍然可以将该字面解析为负数。

所以,我们尝试观察它。投射会很好用:

int x = 248;
int y = 0b11111000;

// x and y are the exact same value. `javap -c` to observe:
// they are _Exactly_ identical and it is hence impossible to tell the difference.

System.out.println(x == y); // prints true
byte b = (byte) x;
System.out.println(b); // prints -8

此处使用的概念:

  • 0b111000 这只是编写整数文字的另一种方式。 0x110b1 之间没有区别 - 所有值都是 1。所有数字最终都是位。他们不存储它们是如何制作的。 0b 用于以 2 为基数的写法,只写以 10 为基数的数字,以 0 为基数的前面加上 0x 表示以 16 为基数:0x10 == {{ 1}} == 16 == 0b10000。试试看!

  • 将 int 转换为一个字节将占用您的 32 位,去掉“最左边”的 24 位,然后将剩余的 8 位直接推入一个字节中,如果这意味着该数字现在是负数,那么就这样。这是 Java 中极少数允许 2s 补码影响发生的事情(与抛出某些东西相比)的概念的操作之一。