Float类有2个toString函数~一个是类函数,一个是成员函数。成员函数其实最后也是调用了类函数。
上函数原型:
public static String toString(float f) {
return new FloatingDecimal(f).toJavaFormatString();
}
据说功能是打印double类型的值与最靠近它的临近值区分出来的最短小数,他在小数点之前之后都至少有一位。
float是按照IEEE754类型存储的。参照http://blog.csdn.net/treeroot/article/details/95071。很多小数都是被截断表示的。这就造成了System.out.println(2.0-1.1);输出0.8999999999999999(参考java解惑)。运行了一段代码:
System.out.println(Float.toString(1.00000001f));
System.out.println(Float.toString(1.00000005f));
System.out.println(Float.toString(1.00000006f));
System.out.println(Float.toString(1.0000001f));
System.out.println(Float.toString(1.0000002f));
System.out.println(Float.toString(1.0000003f));
System.out.println(Float.toString(1.0000004f));
System.out.println(Float.toString(1.0000005f));
System.out.println(Float.toString(1.0000006f));
System.out.println(Float.toString(1.0000007f));
System.out.println(Float.toString(1.0000008f));结果:
1.0
1.0
1.0000001
1.0000001
1.0000002
1.0000004
1.0000004
1.0000005
1.0000006
1.0000007
1.0000008按照IEEE754标准的
1.0
1.00000011920928955078
1.00000023841857910156
1.00000035762786865234
是实际存储值。
上述代码涉及2个问题,第一个问题:一个无法准确表示的数,如1.00000001是如何表示到底取到1.0还是1.00000011920928955078?
而第二个问题1.00000011920928955078实际输出时采用的是什么策略(打印double类型的值与最靠近它的临近值区分出来的最短小数)?如何保证该数可分辨?11920928955078/2 = 5960464477539; System.out.println(Float.toString(1.00000005960464477539f));
System.out.println(Float.toString(1.000000059604644775391f));
System.out.println(Float.toString(1.0000000596046447753901f));
结果:
1.0
1.0000001
1.0
这里好像会让人更糊涂,小于等于一半时表示为向下的,然而第三条输出否定了我的结论。 System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.00000005960464477539f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.000000059604644775391f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.0000000596046447753901f)));
运行这三条也证明了确实转化出了问题。我就想1.0000000596046447753901f会不会被截断成了1.000000059604644775390f?
这个只是猜测。然后问题一就卡在这里了System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.0000000596046447753907f)));证明了我的猜测是错误的。然后我就纠结了。再尝试了负数
System.out.println(Float.toString(-1.00000005960464477539f));
System.out.println(Float.toString(-1.000000059604644775391f));
System.out.println(Float.toString(-1.0000000596046447753901f));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.00000005960464477539f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.000000059604644775391f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.0000000596046447753906f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.0000000596046447753907f)));
结果:
-1.0
-1.0000001
-1.0
10111111100000000000000000000000
10111111100000000000000000000001
10111111100000000000000000000000
10111111100000000000000000000001
看来负数和正数在IEEE754中只是符号差别,我发现我一直忽略一个问题1.00000005960464477539f肯定是float无法表示
那中间表示的是什么?FloatingDecimal?编译器把1.00000005960464477539当做字符串创建了一个FloatingDecimal对象?在就是问题二:FloatingDecimal(f).toJavaFormatString()到底怎么执行的?
上函数原型:
public static String toString(float f) {
return new FloatingDecimal(f).toJavaFormatString();
}
据说功能是打印double类型的值与最靠近它的临近值区分出来的最短小数,他在小数点之前之后都至少有一位。
float是按照IEEE754类型存储的。参照http://blog.csdn.net/treeroot/article/details/95071。很多小数都是被截断表示的。这就造成了System.out.println(2.0-1.1);输出0.8999999999999999(参考java解惑)。运行了一段代码:
System.out.println(Float.toString(1.00000001f));
System.out.println(Float.toString(1.00000005f));
System.out.println(Float.toString(1.00000006f));
System.out.println(Float.toString(1.0000001f));
System.out.println(Float.toString(1.0000002f));
System.out.println(Float.toString(1.0000003f));
System.out.println(Float.toString(1.0000004f));
System.out.println(Float.toString(1.0000005f));
System.out.println(Float.toString(1.0000006f));
System.out.println(Float.toString(1.0000007f));
System.out.println(Float.toString(1.0000008f));结果:
1.0
1.0
1.0000001
1.0000001
1.0000002
1.0000004
1.0000004
1.0000005
1.0000006
1.0000007
1.0000008按照IEEE754标准的
1.0
1.00000011920928955078
1.00000023841857910156
1.00000035762786865234
是实际存储值。
上述代码涉及2个问题,第一个问题:一个无法准确表示的数,如1.00000001是如何表示到底取到1.0还是1.00000011920928955078?
而第二个问题1.00000011920928955078实际输出时采用的是什么策略(打印double类型的值与最靠近它的临近值区分出来的最短小数)?如何保证该数可分辨?11920928955078/2 = 5960464477539; System.out.println(Float.toString(1.00000005960464477539f));
System.out.println(Float.toString(1.000000059604644775391f));
System.out.println(Float.toString(1.0000000596046447753901f));
结果:
1.0
1.0000001
1.0
这里好像会让人更糊涂,小于等于一半时表示为向下的,然而第三条输出否定了我的结论。 System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.00000005960464477539f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.000000059604644775391f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.0000000596046447753901f)));
运行这三条也证明了确实转化出了问题。我就想1.0000000596046447753901f会不会被截断成了1.000000059604644775390f?
这个只是猜测。然后问题一就卡在这里了System.out.println(Integer.toBinaryString(Float.floatToIntBits(1.0000000596046447753907f)));证明了我的猜测是错误的。然后我就纠结了。再尝试了负数
System.out.println(Float.toString(-1.00000005960464477539f));
System.out.println(Float.toString(-1.000000059604644775391f));
System.out.println(Float.toString(-1.0000000596046447753901f));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.00000005960464477539f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.000000059604644775391f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.0000000596046447753906f)));
System.out.println(Integer.toBinaryString(Float.floatToIntBits(-1.0000000596046447753907f)));
结果:
-1.0
-1.0000001
-1.0
10111111100000000000000000000000
10111111100000000000000000000001
10111111100000000000000000000000
10111111100000000000000000000001
看来负数和正数在IEEE754中只是符号差别,我发现我一直忽略一个问题1.00000005960464477539f肯定是float无法表示
那中间表示的是什么?FloatingDecimal?编译器把1.00000005960464477539当做字符串创建了一个FloatingDecimal对象?在就是问题二:FloatingDecimal(f).toJavaFormatString()到底怎么执行的?
现在剩下问题一了。研究代码中
public String
toJavaFormatString(){
char result[] = new char[ nDigits + 10 ];
int i = 0;
if ( isNegative ){ result[0] = '-'; i = 1; }
if ( isExceptional ){
System.arraycopy( digits, 0, result, i, nDigits );
i += nDigits;
} else {
if ( decExponent > 0 && decExponent < 8 ){
// print digits.digits.
int charLength = Math.min( nDigits, decExponent );
System.arraycopy( digits, 0, result, i, charLength );
i += charLength;
if ( charLength < decExponent ){
charLength = decExponent-charLength;
System.arraycopy( zero, 0, result, i, charLength );
i += charLength;
result[i++] = '.';
result[i++] = '0';
} else {
result[i++] = '.';
if ( charLength < nDigits ){
int t = nDigits - charLength;
System.arraycopy( digits, charLength, result, i, t );
i += t;
} else{
result[i++] = '0';
}
}
} else if ( decExponent <=0 && decExponent > -3 ){
result[i++] = '0';
result[i++] = '.';
if ( decExponent != 0 ){
System.arraycopy( zero, 0, result, i, -decExponent );
i -= decExponent;
}
System.arraycopy( digits, 0, result, i, nDigits );
i += nDigits;
} else {
result[i++] = digits[0];
result[i++] = '.';
if ( nDigits > 1 ){
System.arraycopy( digits, 1, result, i, nDigits-1 );
i += nDigits-1;
} else {
result[i++] = '0';
}
result[i++] = 'E';
int e;
if ( decExponent <= 0 ){
result[i++] = '-';
e = -decExponent+1;
} else {
e = decExponent-1;
}
// decExponent has 1, 2, or 3, digits
if ( e <= 9 ) {
result[i++] = (char)( e+'0' );
} else if ( e <= 99 ){
result[i++] = (char)( e/10 +'0' );
result[i++] = (char)( e%10 + '0' );
} else {
result[i++] = (char)(e/100+'0');
e %= 100;
result[i++] = (char)(e/10+'0');
result[i++] = (char)( e%10 + '0' );
}
}
}
return new String(result, 0, i);
}