• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1532
  • Last Modified:

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

0
skiboy825
Asked:
skiboy825
  • 12
  • 9
  • 6
  • +1
1 Solution
 
CEHJCommented:
>>but it still shows up as 1.2345679E7

Shows up where? All you need to do is format it before displaying it
0
 
Jim CakalicSenior Developer/ArchitectCommented:
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
0
 
Jim CakalicSenior Developer/ArchitectCommented:
Should have checked those links before I posted them from my bookmarks. The microsoft link doesn't work anymore.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
CEHJCommented:
Do
field.setText(String.format("%.2f", measureFact));

Open in new window

0
 
skiboy825Author Commented:
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)?

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


See above ( http:#23673857 )
0
 
Jim CakalicSenior Developer/ArchitectCommented:
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.
0
 
Jim CakalicSenior Developer/ArchitectCommented:
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

0
 
objectsCommented:
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

0
 
skiboy825Author Commented:
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' ?
0
 
objectsCommented:
you need to change the database type

0
 
skiboy825Author Commented:

			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

0
 
skiboy825Author Commented:
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

0
 
CEHJCommented:
>>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
0
 
skiboy825Author Commented:
objects, the datatype in my Sql db is decimal. All this happens before I store into the db anyway.
0
 
objectsCommented:
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


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

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

0
 
skiboy825Author Commented:
CEHJ,

I tried your code, but it returns '12345679'
0
 
CEHJCommented:
>>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?
0
 
objectsCommented:
check your using a suitable type in the database

0
 
skiboy825Author Commented:
objects, the database type is 'decimal', with precision 13, scale 4.

cehj, i will post my code...
0
 
skiboy825Author Commented:

// 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

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

Open in new window

0
 
skiboy825Author Commented:
hmm, it still outputs as '12345679.00'
0
 
CEHJCommented:
That would happen naturally after rounding to two DP. How many do you want?
0
 
skiboy825Author Commented:
i want 2 decimal places.  it needs to show up as 12345678.91.
0
 
Jim CakalicSenior Developer/ArchitectCommented:
At the risk of repeating myself, you can't get there from here with float. Floats only have 6-7 digits of precision. Doubles have 15 so, in this one case, it would be possible. But the correct way to represent arbitrary precision decimal numbers is with BigDecimal. You need to do what you first suggested: go back and replace your use of float with BigDecimal so that the user input can be correctly captured.
0
 
objectsCommented:
and dont't use getFloat() to get it from database

0
 
skiboy825Author Commented:
I was afraid of that. Thanks for the help.
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

  • 12
  • 9
  • 6
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now