Link to home
Start Free TrialLog in
Avatar of skiboy825
skiboy825

asked on

Float/BigDecimal problem...

Im having trouble with some float/decimal/double format issue.

I have a class called MeasureFact with a Float property, called actual.

When I enter a value in a textbox on a form, it gets stored into actual property in MeasureFact.

If I enter 123456.78, it stores correctly as 123456.78

But if I enter 12345678.91, it stores as 1.2345679E7

If I change the actual property in the MeasureFact class to a BigDecimal, it works no problem. But the thing is, Ive got so many lines of code where I have it set to Float. So its gonna be a pain to change it all over the place and then double check for bugs.

I was thinking I could just convert the Float actual to a BigDecimal before I store into the database, but it still shows up as 1.2345679E7. Is there a way to convert this value to the way I entered it on the form (12345678.91) ?

BigDecimal actual = BigDecimal.valueOf(measureFact.getActual().doubleValue());

Open in new window

Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

>>but it still shows up as 1.2345679E7

Shows up where? All you need to do is format it before displaying it
The Java Language Specification requires that floats and doubles conform to the IEEE-754 Floating Point specification for single and double-precision floating point numbers. This specification calls for decimal values to be represented as a sign, mantissa (significant digits), radix (or base) and exponent. The radix is always 2. So, ignoring the sign for the moment, values are represented in IEEE-754 format as

    mantissa * 2 ^ exponent

As a direct result, _all_ float and double values are merely approximations of their decimal values. Some decimal values can be represented exactly in this scheme. Some cannot. So when working with floats and doubles (the Java primitives), one should never assume exact values. The primitives are best used when the representation errors are not significant and performance is of the utmost importance. If you want arbitrary precision decimal value representation and are willing or must take the performance hit to get it (as in financial calculations), use the java.math.BigDecimal class.

If you want more information on floating point values, you might look at the following sites. (The last is a page which shows how decimal floating point values are represented in 32-bit and 64-bit IEEE-754.)

http://www.research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
http://babbage.cs.qc.edu/courses/cs341/IEEE-754.html

Best regards,
Jim Cakalic
Should have checked those links before I posted them from my bookmarks. The microsoft link doesn't work anymore.
Do
field.setText(String.format("%.2f", measureFact));

Open in new window

Avatar of skiboy825
skiboy825

ASKER

When I say it shows up as '1.2345679E7', i mean that the 'actual' variable in my code snippet still returns '1.2345679E7'. How can I format the '1.2345679E7' to what I originally entered (12345678.91)?

>>How can I format the '1.2345679E7' to what I originally entered (12345678.91)?


See above ( http:#23673857 )
Maybe I wasn't clear the first time. You can't store the value 12345678.91 in a float without losing precision. It gets rounded up to 12345679 because there aren't enough bits in the mantissa to hold all the significant digits. The way to store arbitrary precision decimal numbers is with the BigDecimal class.
Perhaps another way to demonstrate is with the code snippet below. If you were to run this the result printed on the console would be:
12345679.00

    float value = 12345678.91f;
    System.out.println(String.format("%.2f", value));

Open in new window

floating point numbers do not have an exact representation, read the following for more details.

http://mindprod.com/jgloss/floatingpoint.html

To store it in database with the required precision you will need to use a different data type, such as string or a number type that supports precision

Jim,

I converted my original Float value into a BigDecimal but it was still stored as '1.2345679E7'.  Since '1.2345679E7' is essentially a representation of '12345678.91', how can I format this to '12345678.91' ?
you need to change the database type


			Float oldActual;
						
			// 1. entered "12345678.91", gets stored into oldActual
			
			// 2. But value stored inside oldActual is "1.2345679E7"
			
			// 3. So I convert oldActual into a BigDecimal, newActual
			BigDecimal newActual = BigDecimal.valueOf(measureFact.getActual().doubleValue());
 
			// 4. newActual value is still "1.2345679E7"
			
			// 5. I want to format "1.2345679E7" to "12345678.91"
			
			// 6. ??

Open in new window

ignore the post above... made small correction to code.
			Float oldActual;
						
			// 1. entered "12345678.91", gets stored into oldActual
			
			// 2. But value stored inside oldActual is "1.2345679E7"
			
			// 3. So I convert oldActual into a BigDecimal, newActual
			BigDecimal newActual = BigDecimal.valueOf(oldActual.doubleValue());
 
			// 4. newActual value is still "1.2345679E7"
			
			// 5. I want to format "1.2345679E7" to "12345678.91"
			
			// 6. ??

Open in new window

>>how can I format this to '12345678.91'

I've already answered that. If you've got it as BigDecimal, then the easiest way is to call doubleValue on it with the code i posted earlier
objects, the datatype in my Sql db is decimal. All this happens before I store into the db anyway.
how it is formatted in your code has nothing really  to do with how it is stored in the database.

>                         BigDecimal newActual = BigDecimal.valueOf(oldActual.doubleValue());

you should instead use the ctor that takes a string and use the *string* exactly as entered instead of first parsing it to a float


You don't format it *before* it goes in the db, you format it just before you need to display it
Sorry, I wasn't clear. I need to format it before it gets displayed.
>>Sorry, I wasn't clear. I need to format it before it gets displayed.

Then use the code i posted
then do your formatting *after* you pull it from database

CEHJ,

I tried your code, but it returns '12345679'
>>I tried your code, but it returns '12345679'

Make sure you haven't put it into an int. Can you post the code you used?
check your using a suitable type in the database

objects, the database type is 'decimal', with precision 13, scale 4.

cehj, i will post my code...

// Entered "12345678.91"
 
Float oldActual = measureFact.getActual();
System.out.println(oldActual);	    
// Output: 1.2345679E7
 
BigDecimal newActual1 = new BigDecimal(oldActual.toString(), MathContext.DECIMAL32);
System.out.println(newActual1);
System.out.println(String.format("%.2f", newActual1));
// Output: 1.234568E+7
// Output: 12345680.00
 
 
BigDecimal newActual2 = new BigDecimal(oldActual.toString(), MathContext.DECIMAL64);
System.out.println(newActual2);
System.out.println(String.format("%.2f", newActual2));
// Output: 12345679
// Output: 12345679.00
 
BigDecimal newActual3 = new BigDecimal(oldActual.toString(), MathContext.DECIMAL128);
System.out.println(newActual3);
System.out.println(String.format("%.2f", newActual3));
// Output: 12345679
// Output: 12345679.00
 
BigDecimal newActual4 = new BigDecimal(oldActual.toString(), MathContext.UNLIMITED);
System.out.println(newActual4);
System.out.println(String.format("%.2f", newActual4));
// Output: 12345679
// Output: 12345679.00
 
BigDecimal newActual5 = new BigDecimal(oldActual.toString());
System.out.println(newActual5);
System.out.println(String.format("%.2f", newActual5));
// Output: 12345679
// Output: 12345679.00

Open in new window

You can do
Float oldActual = measureFact.getActual();
float f = oldActual.floatValue();
String output = String.format("%.2f", f);

Open in new window

hmm, it still outputs as '12345679.00'
That would happen naturally after rounding to two DP. How many do you want?
i want 2 decimal places.  it needs to show up as 12345678.91.
ASKER CERTIFIED SOLUTION
Avatar of Jim Cakalic
Jim Cakalic
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
and dont't use getFloat() to get it from database

I was afraid of that. Thanks for the help.