That the 0 for the sign is "missing" is just a number writing convention.
In the decimal system you will write 1067 instead of 0001067, right? This is just wha Java did. Th 0s exist in memory, they are just not displayed, because you don't need them forth number.
Also this is a floating point representation of a binary number.
If you convert 1.5*10^-12 to a binary number, it will have a lot of 0s at the beginning (I started, but then my paper ended - there are definitely more than 12 0s at the beginning). This binary number is then normalized (so that there is only one 1 before the point) and the exponent of this normalization is used as the exponent. I guess the binary exponent of 1.5*10^-12 is indeed 40.
In other words: the exponent of an IEEE number represents the value 2^exponent, not 10^exponent, like we use it in the decimal system.
According to this page you will need to multiply each digit of the mantisse with the corresponding power of 2 starting with 2^-1, then 2^-2 and so on and add them up.
Then you use this formula:
(-1)^(sign bit) * (1+fraction) * 2^(exponent - bias)
where fraction
is the number you calculated from the mantisse.
exponent
is the decimal representation of the exponent. bias
depends on your precision, in your case double precision, which means 1023. For single precision it's only 127.
You cannot directly convert the binary representation parts (say the binary exponent) to the decimal counterparts (the decimal exponent). At least I don't konw how.
So you will need to convert the complete number to decimal and then split it into the number and its exponent.
Here is the Java code to convert the binary representation to decimal:
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));
}
Note that the result is not exactly accurete, since the floating point arithmetics in computers are not accurate and there is a limited sapce in which to store the information.
I dont't know how to extract the number and it's exponent from a double. My best guess is manipulation the String representation linke this:
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]);
I hope this helped.