如何将 IEEE-754 二进制表示字符串转换为 Java 中的浮点数或双精度数?
How can I convert an IEEE-754 binary representation String to a float or double in Java?
由于所有 Java 浮点数,即 floats 和 doubles,在内部都表示为位,我想要找到一个 efficient 算法来转换表示 float 或 double 的位的字符串并转换它转换成相应的浮点数 - 我找不到它的内置库函数所以我求助于自己编写它。
长度为 32 的二进制字符串表示 float,其中长度为 64 的二进制字符串将转换为 double。所有 floats 都可以转换为 doubles 而不会损失准确性。忽略空格。
例子
"0 10000000 10010010000111111011011"
变成 3.141592
作为 float.
"1 11111111 00000000000000000000000"
变为 -infinity
.
"0 11111111 10010010000111111011011"
变为 float NaN
.
"1 10000000000 0101101111110000101010001011000101000101011101101001"
成为最接近-e的double值,即2.71828182845904509079559829843
到目前为止我有这么一大堆代码:
public static double ieee(String binString) throws Exception {
binString = binString.replace(" ", "");
if (binString.length() == 32) {
String exponentB = binString.substring(1, 9);
String mantissaB = binString.substring(9, 32);
int sgn = binString.charAt(0) == '0' ? 1 : -1;
int exponent = Integer.parseInt(exponentB, 2) - 127; // Biased by 127
double mantissa = 1 + Integer.parseInt(mantissaB, 2) / Math.pow(2, 23);
if (exponent == 128 && mantissa == 1)
return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
if (exponent == 128 && mantissa != 0)
return Double.NaN;
if (exponent == -127)
return sgn*Math.pow(2,-126)*(mantissa - 1);
return sgn*Math.pow(2, exponent)*mantissa;
}
else if (binString.length() == 64) {
String exponentB = binString.substring(1, 12);
String mantissaB = binString.substring(12, 64);
int sgn = binString.charAt(0) == '0' ? 1 : -1;
int exponent = Integer.parseInt(exponentB, 2) - 1023; // Biased by 1023
double mantissa = 1 + Long.parseLong(mantissaB, 2) / Math.pow(2, 52);
if (exponent == 1024 && mantissa == 1)
return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
if (exponent == 1024 && mantissa != 0)
return Double.NaN;
if (exponent == -1023)
return sgn*Math.pow(2,-1022)*(mantissa - 1);
return sgn*Math.pow(2, exponent)*mantissa;
}
else {
throw new Exception("Does not represent internal bits of a floating-point number");
}
}
尽管我的代码目前有效,但就速度和数量而言,将 IEEE-754 二进制表示字符串转换为其 float
或 double
的最简洁或最快的方法是什么代码?优先考虑最有效的方法,并能很好地解释其效率和专业知识。
这种方法可能更有效。它当然更简单,更易于维护。
- 从字符串中删除空格
- 验证字符串长度...
- 将二进制字符串转换为
int
- 调用
Float.intBitsToFloat(int)
转换为 float
。
对于双打,使用 long
和等效的 Double
方法。
Is the simplified code more efficient?
唯一可以确定的方法是对其进行基准测试。但是根据您的代码所做的,我相信是这样。
来自@StephenC,将IEEE-754二进制表示转换为相应浮点值的改进代码仅占一行:
return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
Integer.parseUnsignedInt(binString, 2)
将二进制数字中的 unsigned int 从范围 0 转换为 232-1到 int
表示。 parseInt(...)
不起作用,因为 parseInt
在其 binString
中包含一个显式符号,如果它表示负整数,则需要前导连字符而不是 2[=36 的值=]31 或更高。同样,Long.parseUnsignedLong(binString, 2)
适用于 64 位情况。
Float.intBitsToFloat(int n)
表示内部存储与 int 值 n
相同位的浮点值。同样,Double.longBitsToDouble(long n)
适用于 64 位情况。
使用"method composition",这一行首先将(无符号)二进制字符串转换为其对应的int,然后将其转换为具有相同存储位的浮点值。
最终代码为
public static double ieeeToFloat(String binString) throws Exception {
binString = binString.replace(" ", "");
/* 32-bit */
if (binString.length() == 32) {
return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
}
/* 64-bit */
else if (binString.length() == 64) {
return Double.longBitsToDouble(Long.parseUnsignedLong(binString, 2));
}
/* An exception thrown for mismatched strings */
else {
throw new Exception("Does not represent internal bits of a floating-point number");
}
}
由于所有 Java 浮点数,即 floats 和 doubles,在内部都表示为位,我想要找到一个 efficient 算法来转换表示 float 或 double 的位的字符串并转换它转换成相应的浮点数 - 我找不到它的内置库函数所以我求助于自己编写它。
长度为 32 的二进制字符串表示 float,其中长度为 64 的二进制字符串将转换为 double。所有 floats 都可以转换为 doubles 而不会损失准确性。忽略空格。
例子
"0 10000000 10010010000111111011011"
变成3.141592
作为 float."1 11111111 00000000000000000000000"
变为-infinity
."0 11111111 10010010000111111011011"
变为 floatNaN
."1 10000000000 0101101111110000101010001011000101000101011101101001"
成为最接近-e的double值,即2.71828182845904509079559829843
到目前为止我有这么一大堆代码:
public static double ieee(String binString) throws Exception {
binString = binString.replace(" ", "");
if (binString.length() == 32) {
String exponentB = binString.substring(1, 9);
String mantissaB = binString.substring(9, 32);
int sgn = binString.charAt(0) == '0' ? 1 : -1;
int exponent = Integer.parseInt(exponentB, 2) - 127; // Biased by 127
double mantissa = 1 + Integer.parseInt(mantissaB, 2) / Math.pow(2, 23);
if (exponent == 128 && mantissa == 1)
return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
if (exponent == 128 && mantissa != 0)
return Double.NaN;
if (exponent == -127)
return sgn*Math.pow(2,-126)*(mantissa - 1);
return sgn*Math.pow(2, exponent)*mantissa;
}
else if (binString.length() == 64) {
String exponentB = binString.substring(1, 12);
String mantissaB = binString.substring(12, 64);
int sgn = binString.charAt(0) == '0' ? 1 : -1;
int exponent = Integer.parseInt(exponentB, 2) - 1023; // Biased by 1023
double mantissa = 1 + Long.parseLong(mantissaB, 2) / Math.pow(2, 52);
if (exponent == 1024 && mantissa == 1)
return sgn == 1 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
if (exponent == 1024 && mantissa != 0)
return Double.NaN;
if (exponent == -1023)
return sgn*Math.pow(2,-1022)*(mantissa - 1);
return sgn*Math.pow(2, exponent)*mantissa;
}
else {
throw new Exception("Does not represent internal bits of a floating-point number");
}
}
尽管我的代码目前有效,但就速度和数量而言,将 IEEE-754 二进制表示字符串转换为其 float
或 double
的最简洁或最快的方法是什么代码?优先考虑最有效的方法,并能很好地解释其效率和专业知识。
这种方法可能更有效。它当然更简单,更易于维护。
- 从字符串中删除空格
- 验证字符串长度...
- 将二进制字符串转换为
int
- 调用
Float.intBitsToFloat(int)
转换为float
。
对于双打,使用 long
和等效的 Double
方法。
Is the simplified code more efficient?
唯一可以确定的方法是对其进行基准测试。但是根据您的代码所做的,我相信是这样。
来自@StephenC,将IEEE-754二进制表示转换为相应浮点值的改进代码仅占一行:
return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
Integer.parseUnsignedInt(binString, 2)
将二进制数字中的 unsigned int 从范围 0 转换为 232-1到int
表示。parseInt(...)
不起作用,因为parseInt
在其binString
中包含一个显式符号,如果它表示负整数,则需要前导连字符而不是 2[=36 的值=]31 或更高。同样,Long.parseUnsignedLong(binString, 2)
适用于 64 位情况。Float.intBitsToFloat(int n)
表示内部存储与 int 值n
相同位的浮点值。同样,Double.longBitsToDouble(long n)
适用于 64 位情况。使用"method composition",这一行首先将(无符号)二进制字符串转换为其对应的int,然后将其转换为具有相同存储位的浮点值。
最终代码为
public static double ieeeToFloat(String binString) throws Exception {
binString = binString.replace(" ", "");
/* 32-bit */
if (binString.length() == 32) {
return Float.intBitsToFloat(Integer.parseUnsignedInt(binString, 2));
}
/* 64-bit */
else if (binString.length() == 64) {
return Double.longBitsToDouble(Long.parseUnsignedLong(binString, 2));
}
/* An exception thrown for mismatched strings */
else {
throw new Exception("Does not represent internal bits of a floating-point number");
}
}