还有另外一个thread与此相似,但它并不重复,所以请不要将其标记为此类 .
我有一个通信模拟,它接受测试数据 - 浮点数和整数 - 并将它们转换为二进制字符串,然后通过管道发送它们,并由另一端的监听器接收它们 . 然后他们'解包'并转换回数字 .
但是,使用Integer.parseInt()返回转换会抛出异常,即使消息中的二进制文件显然是正确形成的IEEE-754 binary32单精度格式 .
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格式,适用于Signed Double,而不是像Float这样的单一精度数据类型 .
我有一个解决方案,在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;
我肯定错过了什么 .
3 回答
"11000111001100101010010011101110"
是一个以1开头的32位二进制数 . 这意味着它可以表示2的补码中的负int
.但是,
Integer.parseInt
不是补充表示 . 它期望标志用前导-
表示,而不是用符号位表示,因为你可以在Javadoc中读到:因此,它将
"11000111001100101010010011101110"
视为32位正数,这超出了int
类型的范围 .以下内容可用于重新计算
intFloat
的值:现在
intFloat
和revint
将等于-952982290
.编辑:
Java确实拥有您需要的API,您只是没有使用正确的方法 . 由于
toBinaryString(int i)
返回“整数参数的字符串表示形式为基数为2的 unsigned 整数”,因此应使用Integer.parseUnsignedInt(String, int)
来恢复传递给toBinaryString
的值:你错过了
Integer.toBinaryString(integer)
的逆变换是Integer.parseUnsignedInt(string, 2)
...而不是Integer.parseInt(string)
.至于为什么他们以这种方式设计API:这对设计师来说是一个问题 .
但请记住,
Integer
API已经发展了很多年,并且进化的主要要求是变化应该向后兼容 . (他们可以在过去的20年里为客户付费 . )值得注意的是,
parseUnsignedInt
仅在Java 1.8中添加 .我的问题的答案似乎是,一个看似与其功能名称相反的方法,将完成这项工作 . 使用Signed Float和“Integer.parseUnsignedInt”的工作示例位于底部 .
不幸的是,"Don't trust the JavaDoc"似乎更贴切'answer' . 如果"Integer.parseUnsignedInt(String, Radix)"用于转换浮点数的IEEE-754有符号二进制表示,那么它需要更好的名称和更好的JavaDoc .
我感谢所有参与此次讨论的人 . 对于读者来说,JavaDoc通常不会告诉您:此方法是否在内部切断Sign-bit并将其余的String解析为UnsignedInt,然后应用符号位?这就是为什么有人将它命名为“parseUnsignedInt()”,尽管事实上它解析了签名值?也许 . 我们可以说的是,尽管方法名称,但它清楚地解析了负浮点值的已签名Int表示 .
对于's trying this, the example below will generate an IEEE-754 32-bit Signed Binary String from a Float, conforming to the spec'的“binary32”格式的下一个人,并将其转换回您开始使用的相同的Signed Binary Float .
输出:
进程以退出代码0结束
这是一个有用的online validation工具,因此您可以使用它的IEEE格式可视化二进制文件并查看转换 .
请注意,如果您从Double-to-Long-to-String开始,并使用Long.parseUnsignedLong进行转换以交换符合IEEE-754标准的“binary64 " format between processes in Binary, except that the output is in Scientific " x.yEn”符号,则情况也是如此 . 尝试打印它:
输出: