JDK-4191279 : Float.toString() produces incorrect results
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version:
    1.0.2,1.1,1.1.2,1.1.4,1.1.5,1.1.6,1.1.7,1.2.0,1.3.0 1.0.2,1.1,1.1.2,1.1.4,1.1.5,1.1.6,1.1.7,1.2.0,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 1998-11-19
  • Updated: 2022-06-02
  • Resolved: 2022-06-02
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: dkC59003			Date: 11/18/98



This is almost same bug as reported in #4023198 (jdk 1.0.2, Float.toString 
produces incorrect results). Indeed 4023198 is closed, Float.toString()
still continue to produce incorrect results for some other arguments. 

Error arises in following releases:

    JDK 1.0.2: fails under: solaris-sparc, win32
    JDK 1.1.x: fails under: solaris-x86  , win32
    JDK 1.2  : fails under: solaris-x86          (both with and without JIT)

The problem is the following:

JLS section 20.9.16 uniquely defines canonical result of Float.toString(x) 
for every float value x. However, the JDK releases listed above fail to 
produce correct result of Float.toString(x) for some particular values x.

Below are the samples:

------------------------------------ fpm03504_bug.java:

import java.lang.Float;

class fpm03504_bug {

    static void main (String args[]) {
	float b59 = Float.intBitsToFloat(0x5d000000);	// 2**59
	float b60 = Float.intBitsToFloat(0x5d800000);	// 2**60
	float b61 = Float.intBitsToFloat(0x5e000000);	// 2**61
	float b62 = Float.intBitsToFloat(0x5e800000);	// 2**62

	String s59 = Float.toString(b59);
	String s60 = Float.toString(b60);
	String s61 = Float.toString(b61);
	String s62 = Float.toString(b62);

	String c59 = "5.7646075E17";	// canonical representations
	String c60 = "1.1529215E18";	//   computed under JDK 1.2 
	String c61 = "2.30584301E18";	//   fcsR / solaris-sparc
	String c62 = "4.611686E18";

	boolean e59 = s59.compareTo(c59) == 0;
	boolean e60 = s60.compareTo(c60) == 0;
	boolean e61 = s61.compareTo(c61) == 0;
	boolean e62 = s62.compareTo(c62) == 0;

	System.out.println("b59: "+s59+"\t" + (e59? " -- Ok": " instead of: "+c59));
	System.out.println("b60: "+s60+"\t" + (e60? " -- Ok": " instead of: "+c60));
	System.out.println("b61: "+s61+"\t" + (e61? " -- Ok": " instead of: "+c61));
	System.out.println("b62: "+s62+"\t" + (e62? " -- Ok": " instead of: "+c62));
    }
}

---------------------- produces under some JDK releases:

java fpm03504_bug

b59: 5.7646788E17	 instead of: 5.7646075E17
b60: 1.15293577E18	 instead of: 1.1529215E18
b61: 2.30587156E18	 instead of: 2.30584301E18
b62: 4.6116886E18	 instead of: 4.611686E18

--------------------------------------------------

I have found, that b59,b60,b61,b62 are the only float values
having the form 2**n, which bring Float.toString() to fail.

======================================================================

Name: boT120536			Date: 01/22/2001


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


The library routines for converting floats to Strings still have some bugs in
them.

According to the specs of Float.toString:
"How many digits must be printed for the fractional part of m or a? There must
be at least one digit to represent the fractional part, and beyond that as many,
but only as many, more digits as are needed to uniquely distinguish the argument
value from adjacent values of type float. That is, suppose that x is the exact
mathematical value represented by the decimal representation produced by this
method for a finite nonzero argument f. Then f must be the float value nearest
to x; or, if two float values are equally close to x then f must be one of them
and the least significant bit of the significand of f must be 0."

Take the number 123456789.0f.  This rounds to the exact value 123456792 (the bit
pattern 0x4ceb79a3, by Float.floatToIntBits).  The nearest two floats
are Float.intBitsToFloat(0x4ceb79a2), which is exactly 123456784, and
Float.intBitsToFloat(0x4ceb79a4), which is exactly 1234567800.

The representation 1.2345679E8 is closer to 123456792 than 123456784, so no
further accuracy is allowed.  However, System.out.println("" + 123456789f)
produces 1.23456792E8, where the second digit '2' is spurious, according to the
specs.
(Review ID: 113581)
======================================================================
###@###.### 2004-11-11 21:42:37 GMT

Comments
Fixed in JDK-4511638
02-06-2022

Same situation obtains in JDK9-dev as for the comment of 2001-08-23: first test cases pass but the spurious extra digit is still produced for the example cited.
10-03-2014

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon
14-06-2004

EVALUATION The first set of test cases mentioned in the description (2^n) have worked since 1.2. The issues of unneeded trailing digits still remains; however, that is not a very serious problem in practice since the string still rounds back to the right floating-point value. ###@###.### 2001-08-24
24-08-2001