java - 如果 Java 的 parseInt 对于有效的 IEEE-754 二进制文件失败,那么哪个 API 不会失败?

标签 java floating-point binary ieee-754 signed

还有一个thread与此类似,但它不是与此重复,因此请不要将其标记为此类。

我有一个通信模拟,它获取测试数据( float 和整数)并将它们转换为二进制字符串,然后通过管道发送它们,并由另一端的监听器接收它们。然后它们被“解压”并转换回数字。

但是,使用 Integer.parseInt() 进行转换会引发异常,即使消息中的二进制显然是正确形成的 IEEE-754 二进制 32 单精度格式。

    float flt = -45732.9287f;
    int intFloat = Float.floatToRawIntBits(flt);
    String str = Integer.toBinaryString(intFloat);

    System.out.println("------- Now do the Reverse -------");

    int revint = Integer.parseInt(str, 2);

    .... Throws java.lang.NumberFormatException: For input string: "11000111001100101010010011101110"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)

在没有 Radix 的情况下使用 parseInt() 会引发类似的异常:

    "int revint = Integer.parseInt(str);" throws an exception too, "java.lang.NumberFormatException: For input string: "11000111001100101010010011101110"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)".

所以,这不仅仅是 Radix 使用问题。

使用 Long 和 BigInt 转换回来是不正确的,因为它们是 64 位 IEEE-754 格式,适用于有符号 double 据类型,而不是有符号单精度数据类型(如浮点型)。

我有一个解决方案,可以消除 Java 转换方法中的不对称性,但我觉得没有原生 API 是不协调的:

    System.out.println("------- Now do the Reverse -------");

    int revSign = str.substring(0,1).equals("1") ? -1: 1;
    System.out.println("The passed-in sign is:"+revSign);

    int revint = Integer.valueOf(str.substring(1), 2);

    float revFloat = Float.intBitsToFloat(revint)*revSign;

我一定错过了一些东西。

最佳答案

"11000111001100101010010011101110"是一个以1开头的32位二进制数。这意味着它可以表示负数int 2 的补码。

但是,Integer.parseInt不期望其输入采用 2 的补码表示形式。它期望该符号以前导 - 表示。 ,不带符号位,正如您可以在 Javadoc 中读到的那样:

int java.lang.Integer.parseInt(String s, int radix) throws NumberFormatException

Parses the string argument as a signed integer in the radix specified by the second argument. The characters in the string must all be digits of the specified radix (as determined by whether java.lang.Character.digit(char, int) returns a nonnegative value), except that the first character may be an ASCII minus sign '-' ('\u005Cu002D') to indicate a negative value or an ASCII plus sign '+' ('\u005Cu002B') to indicate a positive value. The resulting integer value is returned.

因此它对待 "11000111001100101010010011101110"作为 32 位正数,超出 int 的范围类型。

以下可用于重新计算 intFloat 的值:

// replace the leading 1 with - if it's a sign bit
str = (str.length () == 32 && str.charAt (0) == '1') ? ('-' + str.substring (1)) : str;
int revint = Integer.parseInt(str, 2);
// for negative number, we must compute the 2's complement of the number returned
// by parseInt
if (revint < 0) {
  revint = -1 * (revint + Integer.MAX_VALUE + 1);
}

现在都是intFloatrevint将等于 -952982290 .

编辑:

Java确实有你需要的API,只是你没有使用正确的方法。 自 toBinaryString(int i)返回“整数参数的字符串表示形式,以 2 为基数的无符号整数”,您应该使用 Integer.parseUnsignedInt(String, int)为了恢复传递给 toBinaryString 的值:

float flt = -45732.9287f;
int intFloat = Float.floatToRawIntBits(flt);
String str = Integer.toBinaryString(intFloat);
System.out.println("------- Now do the Reverse -------");
System.out.println (str);
int revint = Integer.parseUnsignedInt(str, 2);

关于java - 如果 Java 的 parseInt 对于有效的 IEEE-754 二进制文件失败,那么哪个 API 不会失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51691734/

相关文章:

C 编程位表示

java - 有人可以解释一下吗? (运动无法正常工作)

c - 串行端口 IAR 上的 Sprintf 和浮点值

java - 打印从文本文件创建的数组

javascript - 在 Javascript 中从缓冲区读取 C++ 浮点值

php - 0 到 1.0 php 之间的随机 float

c - 我如何接收 "cat"作为我的程序参数?

c - 如何打开使用 C 程序创建的二进制文件?

java - 如何实现新的 Google Play 服务(分析)?

java - 使用 GreenRobot EventBus 在线程之间进行通信