我得到了双数的二进制代码:
Double d = 1.5E12;
long l = Double.doubleToLongBits(d);
String bin = Long.toBinaryString(l);
System.out.println(bin);
System.out.println(bin.length());但是,生成的代码不像双比特代码,它没有任何意义:
1.5E12 --> 100001001110101110100111110111101111001100000000000000000000000 (length: 63)
-1.5E12 --> 1100001001110101110100111110111101111001100000000000000000000000 (length: 64)
1.5E-12 --> 11110101111010011000110110011001000001110001001101111100011010 (length: 62)
-1.5E-12 --> 1011110101111010011000110110011001000001110001001101111100011010 (length: 64)我试图通过分组来理解这些数字:
1.5E12 --> 10000100111 0101110100111110111101111001100000000000000000000000
-1.5E12 --> 1 10000100111 0101110100111110111101111001100000000000000000000000
1.5E-12 --> (0)1111010111 1010011000110110011001000001110001001101111100011010
-1.5E-12 --> 1 01111010111 1010011000110110011001000001110001001101111100011010首先,它为减号添加/删除了一点(这是解析器的糟糕thing...speaking )。但更甚的是,指数显示了非常可疑的数字:例如10000100111被认为是1035 (= 1023 + 12),而不是1063 (1063 - 1023 = 40!),(0)1111010111应该是1011 (= 1023-12)而不是983 (983-1023= -40!)。
有人知道怎么读这个双位码吗?即,如何从以上位码中求出正确的指数和伪码?
(例如:如何将1.5E12的值从位代码中再次提取出来? 100001001110101110100111110111101111001100000000000000000000000 -> 1.5E12)
更新:
通过使用Java的掩码,我最终得到了如下的值:
static final long SIGN = 0x8000000000000000L;
static final long EXPN = 0x7ff0000000000000L;
static final long SGNF = 0x000fffffffffffffL;
Double d = ...;
long lng = Double.doubleToLongBits(d);
String bin = Long.toBinaryString(lng);
long sign = (lng & SIGN) >>> (bin.length()-1);
long expn = (lng & EXPN) >>> 52;
long sgnf = lng & SGNF;我可以轻松地打印出来:
System.out.println("sign-bin: "+Long.toBinaryString(sign));
System.out.println("expn-bin: "+Long.toBinaryString(expn));
System.out.println("sgnf-bin: "+Long.toBinaryString(sgnf));
System.out.println("sign-string: "+Long.toString(sign));
System.out.println("expn-string: "+Long.toString(expn));
System.out.println("sgnf-string: "+Long.toString(sgnf));在双1.5E12中,我得到了如下结果:
sign-bin: 0
expn-bin: 10000100111
sgnf-bin: 101110100111110111101111001100000000000000000000000
sign-string: 0
expn-string: 1063
sgnf-string: 1640400372629504你知道如何从它们中提取“实”十进制值吗?(例如1640400372629504 -> 1.5及1063年-> E12)
发布于 2014-05-13 13:14:10
标志的0是“缺失”,这只是一个数字书写惯例。
在十进制中,你将写1067,而不是0001067,对吗?这正是Java所做的。它存在于内存中,它们只是没有显示,因为你不需要它们的第四位。
这也是二进制数的浮点表示形式。
如果你把1.5*10^-12转换成二进制数,它在开始的时候会有很多0(我开始了,但是我的论文结束了--开始的时候肯定有超过12 0)。然后对这个二进制数进行归一化(因此在点之前只有一个1),并使用这个归一化的指数作为指数。我猜1.5*10^-12的二元指数确实是40。
换句话说: IEEE数的指数表示值2^指数,而不是10^指数,就像我们在十进制中使用的那样。
根据此页,你需要用相应的2的幂乘每个数字,从2^-1开始,然后2^-2等等,然后把它们加起来。
然后使用这个公式:
(-1)^(符号位)* (1+fraction) *2^(指数偏差)
其中fraction是你从曼蒂塞计算出来的数字。exponent是指数的十进制表示。bias取决于您的精度,在您的例子中是双精度,这意味着1023。单精度只有127。
不能直接将二进制表示部分(例如二进制指数)转换为十进制对应部分(十进制指数)。至少我不知道怎么做。
所以你需要把完整的数字转换成十进制,然后把它分解成数字和指数。
下面是将二进制表示转换为十进制的Java代码:
static final long SIGN = 0x8000000000000000L;
static final long EXPN = 0x7ff0000000000000L;
static final long SGNF = 0x000fffffffffffffL;
public static void main(String[] args){
Double d = -0.0000000000015;//1500000000000d;
long lng = Double.doubleToLongBits(d);
String bin = Long.toBinaryString(lng);
long sign = (lng & SIGN) >>> (bin.length()-1);
long expn = (lng & EXPN) >>> 52;
long sgnf = lng & SGNF;
System.out.println("sign-bin: "+Long.toBinaryString(sign));
System.out.println("expn-bin: "+Long.toBinaryString(expn));
System.out.println("sgnf-bin: "+Long.toBinaryString(sgnf));
System.out.println("sign-string: "+Long.toString(sign));
System.out.println("expn-string: "+Long.toString(expn));
System.out.println("sgnf-string: "+Long.toString(sgnf));
String mantisse = Long.toBinaryString(sgnf);
int pow2 = 2;
double fraction = 0;
for(int i = 0; i < mantisse.length(); i++){
if(mantisse.charAt(i) == '1'){
double curr = 1.0/pow2;
fraction += Double.isInfinite(curr)? 0: curr;
}
//System.out.println(fraction + " " + pow2);
pow2 <<= 1;
}
System.out.println((1+fraction));
System.out.println("Back to decimal: " + (sign == 1?(-1):1) * (1+fraction) * Math.pow(2, expn - 1023));
}请注意,结果并不完全正确,因为计算机中的浮点算法不准确,而且存储信息的智库有限。
我不知道如何从双倍中提取数字和指数。我的最佳猜测是操作字符串表示形式linke如下:
String[] number = Double.toString(dBack).split("E");
System.out.println("Decimal exponent: " + (number.length == 2?number[1]: 1));
System.out.println("Decimal mantisse: " + number[0]);希望这能帮上忙。
发布于 2014-05-13 23:51:39
如维基百科页面所述,该数字的值为

。
所以二元指数是1063 - 1023 = 40。这是有意义的,因为它将尾数乘以2^40,约为10^12 (因为2^10约为1000,2^40将为1000^4)。(这种指数编码方法称为零偏移距。它被使用,而不是2s的补充,因为它导致了更简单的硬件。)
尾数的原始位是0101110100111110111101111001100000000000000000000000,,所以前面的公式是1,我们有:
1.0101110100111110111101111001100000000000000000000000现在,将二进制点40位移到指数的右边,我们有:
10101110100111110111101111001100000000000.000000000000幸运的是,在十进制中,这是整数1500000000000,这正是我们想要的。
这样你就能得到算法了。第一步是计算整数部分(正如我前面所做的),并使用打印整数的标准算法:
i = 0;
while (int_part > 0) {
digit[i] = int_part % 10
int_part = int_part / 10
i = i + 1
}
if (i == 0) return '0'
else reverse digits[0..i-1] and return这就留下了分数位。如果有N位,那么把它们当作一个N位整数,除以2^N。例如,1位分数1是1/2。你可以通过实现长除法得到十进制数。例如,二进制.11是3/4。实现长除法,我们首先得到3*10/4 = 7R2。然后2*10/4 = 7R0。所以十进制数字是.75。伪码:
num = frac_part
den = 2 ^ (number of bits in frac_part)
i = 0
do {
num = num * 10
digit[i] = num / den
num = num % den
i = i + 1
} while (num != 0)注意,这些算法是概念性的,不实用的。首先,它们假定任意精度整数。实际上,您不需要这样的开销,所以计算实际上是用浮点进行的。Wirth写的一本好的老书“算法+数据结构=程序”详细介绍了它是如何工作的。
如果您正在实现printf或类似的库函数,则基本转换的细节非常复杂,很难以良好的速度得到正确的处理。我所说的“对”是指能够在基数10中打印一个数字,并以完全有信心的方式将这个表示读回来,相信你会得到完全相同的数字。不要低估这个问题。
另外,正如其他人所说的,您的Java打印例程只是在省略所有的前导零,因为它们是为人设计的,而且人们通常不关心前导零。
https://stackoverflow.com/questions/23631417
复制相似问题