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()到底怎么执行的?

解决方案 »

  1.   

    找到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);
        }