Win a copy of Functional Reactive Programming this week in the Other Languages forum!

# Precision loss in String to Float and double to float

Yogesh Gandhi
Ranch Hand
Posts: 226

Can someone please explain me the behavior, why is this truncating the values?

I need to store 2 value upto 2 decimal places in a float variable only.
And there should not be any change in the actual data Becausee it is amount of a Bank.

Any suggestions.!!

Yogesh Gandhi
Ranch Hand
Posts: 226
There seem to be a known issue with floats...

http://stackoverflow.com/questions/916081/convert-float-to-double-without-losing-precision

J. Kevin Robbins
Bartender
Posts: 1801
28
Never use floats or doubles for currency or anything else that requires exacting precision. Use BigDecimal.

This post explains it.

Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15490
43
Yogesh Gandhi wrote:There seem to be a known issue with floats...

These are not "known issues" in the sense that these are not bugs. This is just how the float and double datatypes work: they are not arbitrary precision numbers.

If you need arbitrary precision decimal numbers, use BigDecimal instead.

Jeff Verdegan
Bartender
Posts: 6109
6
Yogesh Gandhi wrote:
Can someone please explain me the behavior, why is this truncating the values?

I need to store 2 value upto 2 decimal places in a float variable only.

Floats have a fixed number of total bits of precision, which must be shared among the integer and fractional parts. If you use more of those bits to store a larger integer portion (123456 vs. just 12), that leaves fewer for the fractional portion (.4 vs. .45678).

Also, you should be aware that since float and double are base-2 formats, rather than base-10, many values that can be represented with a small, finite number of digits in base-10 cannot be stored in a double or float. For instance, it is impossible to store exactly 1/10 (0.1) in a double or float, just as it's impossible to store 1/3 (0.333...) exactly in a finite number of digits in base-10.

That's something you should never mention in a forum. Your time constraints are not the concern of the people answering questions, and bringing them up just distracts from the problem at hand and can alienate people who might otherwise want to help you.

Campbell Ritchie
Sheriff
Posts: 50245
79
Yogesh Gandhi wrote: . . .

I need to store 2 value upto 2 decimal places in a float variable only.
And there should not be any change in the actual data Becausee it is amount of a Bank.

. . .

There is no such thing as urgent here. The answer is in the Java Tutorials. You need a high-precision calculation, so look what it tells you to use for high-precision calculations. Never a double, let alone a float, which only supports about 6 significant figures.

Look at these FAQ, especially No 20.

Yogesh Gandhi
Ranch Hand
Posts: 226
Thanks Jeff and Campbell for the wonderful responses.
Its pretty much clear to me now and I will have a better understanding of these numbers.

I am actually not very experienced with forums and all, so wrote urgent with the post.

But I agree with you guys, I should not have written it and will definitely not write in my future posts.

Thanks again for all your help !!

Yogesh Gandhi
Ranch Hand
Posts: 226
My friend Bear Bibeault

This forum as I can see is related to java only.

JavaRanch » Java Forums » Beginning Java

Campbell Ritchie
Sheriff
Posts: 50245
79
You’re welcome

Bear moved your question to this forum; it was obviously in an inappropriate location before the move.
And what are you using for your arithmetic now?

Yogesh Gandhi
Ranch Hand
Posts: 226
Well the real problem was a wrapper around this.

We used XSD->Jaxb-> java classes

XSD has data type xs:float mentioned in it, for which JAXB uses float type in java.
I was not the person who has to take a call on the change in XSD.

However, our client has the amount truncated to nearest rupee, so this issue might not get raised by client...

We'll see, if they ask us to change........For now......everything is cool

Campbell Ritchie
Sheriff
Posts: 50245
79
Yogesh Gandhi wrote: . . . However, our client has the amount truncated to nearest rupee, so this issue might not get raised by client...
Until the errors start building up.
We'll see, if they ask us to change........For now......everything is cool
That is a bit like your buyers not asking you to change the asbestos brakes to ceramic brakes in a car. The reason is that they don’t know there is anything wrong with asbestos brakes, or anything better about ceramic brakes.
Your leaving what you know to be unreliable code and justifying it by saying, “nobody has noticed” seems to me to be a cavalier attitude.

Yogesh Gandhi
Ranch Hand
Posts: 226
no my friend. we have clearly communicated this to the client that we are using float as it was float on the xsd.

also we have clearly communicated the limitations of float and they have told us that it wont create a problem there.

there is nothing hidden from the client.....its the client who will take a call what they need.

Winston Gutkowski
Bartender
Posts: 10527
64
Yogesh Gandhi wrote:no my friend. we have clearly communicated this to the client that we are using float as it was float on the xsd.
also we have clearly communicated the limitations of float and they have told us that it wont create a problem there.
there is nothing hidden from the client.....its the client who will take a call what they need.

Sounds bad to me. The client supplies business requirements; not technical implementation details (which float most certainly is). And I would say that the mere presence of this thread suggests that (a) they are wrong, and (b) you already DO have problems.

Wisnton

Yogesh Gandhi
Ranch Hand
Posts: 226
my friend...... xsd was the input file from which we started coding.

xsd was supplied by the client and if i have to change float to something else i need to make changes in xsd for which i need clients approval.
i cannot mAke changes to xsd at my will.

client has complete IT team sitting there....so they know the business as well as technical requirements

well i knew it could be of problem thats why i have highlighted it very clearly...

and more over making these changes would need time...which we didn't have...

Paul Clapham
Sheriff
Posts: 21416
33
Well, then, here's how things stand.

(1) The client has specified that you use float variables.

(2) You have observed how float variables work.

(3) Therefore that's what the client wanted.

You may disagree with the results, but they are what the client wanted. You don't have a problem.

Pat Farrell
Rancher
Posts: 4678
7
It is a sin to use float (or double) for money. It never works.
Use BigDecimal or better, write a Currency class and have type safety.

Yogesh Gandhi
Ranch Hand
Posts: 226
yeah thats a lesson i have just learnt from this project of mine...

would definitely use bigdecimal in future.

Campbell Ritchie
Sheriff
Posts: 50245
79
You should start by searching the API and this forum. I am presuming you know how to find the API already, so haven’t supplied a link.

Yogesh Gandhi
Ranch Hand
Posts: 226
Pat Farrell wrote:It is a sin to use float (or double) for money. It never works.
Use BigDecimal or better, write a Currency class and have type safety.

Yes it is actually a sin to use float...

As soon as the figure crosses 8 digit value, it start using E representation

<amount>1.2345679E7</amount>

Now, It is liable to cause a problem.......much more what I had visualized...

Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15490
43
Yogesh Gandhi wrote:As soon as the figure crosses 8 digit value, it start using E representation

But that doesn't have much to do with the real problem. That's just how floats are displayed by default, and it's easy to format a float so that you'll never see the "E" representation. Watch this:

The real problem is that floats don't have enough precision, which leads to rounding errors if you start doing arithmetic with them, and that they can't represent all decimal numbers precisely. For some applications the limited precision of a float is not a problem, but when working with money, it is a problem, because rounding errors of just one cent or so can lead to accounting errors, and since a float is limited to approximately 6 decimal digits of precision, it's not possible to accurately store large amounts.

Yogesh Gandhi
Ranch Hand
Posts: 226
Thanks Jesper de Jong

I think I was not able to put up my problem precisely.

Actually, I need to store such number in a float variable only.

Actually I have some generated Java classes which are using float as a data type to store amount.
And then I use those classes to generate an XML.

The example you gave, gives the output in a string.

Storage would not be a big trouble, but while converting the class values into XML, it converts into E format...That's the real headache for me

If there is a real solution for this problem, it'll save a lot of re-work for me.

~
Yogesh

Campbell Ritchie
Sheriff
Posts: 50245
79
If you want the number displayed as it is stored, then you could display its binary representation. How else do you expect it to be displayed other than as a String?

Yogesh Gandhi
Ranch Hand
Posts: 226
Campbell Ritchie wrote:If you want the number displayed as it is stored, then you could display its binary representation. How else do you expect it to be displayed other than as a String?

float a = 1234567890f; // In my case this value is coming from DB, where it was stored perfectly ok (as it was number(18,4) in the database).

Now, i read from DB and set this variable in my class and use JAXB to convert it to XML.

The resulting XML gives me something like

<amount>1.23456E10</amount>

I want the number to be displayed, what it actually was in decimal number system (not binary).

Winston Gutkowski
Bartender
Posts: 10527
64
Yogesh Gandhi wrote:float a = 1234567890f; // In my case this value is coming from DB, where it was stored perfectly ok (as it was number(18,4) in the database).
Now, i read from DB and set this variable in my class and use JAXB to convert it to XML.

The resulting XML gives me something like
<amount>1.23456E10</amount>
I want the number to be displayed, what it actually was in decimal number system (not binary).

Well, you could use something like String.format("%.4f", a), or a DecimalFormat object; but it doesn't solve your major problem, which is that
a float cannot hold the value you supplied.

On my machine, the above command displays:
1234567936.0000
because the 'a' field has lost precision of the value it was supplied with.

Winston

Jeff Verdegan
Bartender
Posts: 6109
6
Yogesh Gandhi wrote:
Actually, I need to store such number in a float variable only.

Even if that float cannot hold the number you want to store? Even if it's only accurate to within +/-8 in the integer portion?

And note that this is not a shortcoming of Java. It is due to the fact that you can only store so many different values in 32 bits. It is simply the inherent nature of fixed-width floating point number representation.

Jeff Verdegan
Bartender
Posts: 6109
6
Yogesh Gandhi wrote:
Campbell Ritchie wrote:If you want the number displayed as it is stored, then you could display its binary representation. How else do you expect it to be displayed other than as a String?

float a = 1234567890f; // In my case this value is coming from DB, where it was stored perfectly ok (as it was number(18,4) in the database).

Except that SQL's (18,4) cannot fit into a float. You will lose precision.

I want the number to be displayed, what it actually was in decimal number system

If you use floats, that's impossible. Float has 32 bits of precision, which is less than 10 decimal digits, which is less than SQL's (18,4).

Jeff Verdegan
Bartender
Posts: 6109
6
Yogesh Gandhi wrote:
float a = 1234567890f; // In my case this value is coming from DB, where it was stored perfectly ok (as it was number(18,4) in the database).

It is not possible to store 1234567890 in a float. It is also not possible to store 0.1 in a float or even in a double.

Yogesh Gandhi
Ranch Hand
Posts: 226
thankyou friends..

you guys are right.....now i need to see if our client wants us to change the xsd...

well this learning will help me visualize the problems due to float and double in advance...

Campbell Ritchie
Sheriff
Posts: 50245
79
Winston Gutkowski wrote: . . . On my machine, the above command displays:
1234567936.0000 . . .
Which is a display of the nearest float to the correct value. The display however is printed as a String on the screen. The % tags allow you to alter the format of the display, not the value of the number.

Jeff Verdegan
Bartender
Posts: 6109
6
Campbell Ritchie wrote:The % tags allow you to alter the format of the display, not the value of the number.

I think one of the most common beginner mistakes has got to be the erroneous assumption that numbers and dates have a format and that SimpleDateFormat, DecimalFormat, and printf-style formatting strings affect the stored numerical or date value, changing its (quite nonexistent) "format".

Paul Clapham
Sheriff
Posts: 21416
33
Yogesh Gandhi wrote:you guys are right.....now i need to see if our client wants us to change the xsd...

I'm no schema expert, but I didn't think that you could write a schema which specified that the implementing code should use floats or doubles or BigDecimal. I would be very interested to see the part of the schema where it specifies the use of float values. Do you think you could show us that?

Yogesh Gandhi
Ranch Hand
Posts: 226
when it says type to be xs:float, the xjc command that comes with java webservices developer pack generates classes which has float as the corresponding data type in java and if it is xs:unsignedLong then the corresponding data type in generated class is BigInteger.

Yogesh Gandhi
Ranch Hand
Posts: 226
Yogesh Gandhi wrote:when it says type to be xs:float, the xjc command that comes with java webservices developer pack generates classes which has float as the corresponding data type in java and if it is xs:unsignedLong then the corresponding data type in generated class is BigInteger.

Here is the example I was talking about

XSD:

Here are the classes generated:
Amount.java

Counter.java

The command I used for generating Java classes was

D:\Yogesh\Projects\test>xjc -p testPackage test.xsd
parsing a schema...
compiling a schema...
testPackage\Amount.java
testPackage\Counter.java
testPackage\ObjectFactory.java
testPackage\jaxb.properties
testPackage\bgm.ser
testPackage\impl\AmountImpl.java
testPackage\impl\CounterImpl.java
testPackage\impl\JAXBVersion.java
testPackage\impl\runtime\AbstractUnmarshallingEventHandlerImpl.java
testPackage\impl\runtime\NamespaceContext2.java
testPackage\impl\runtime\Util.java
testPackage\impl\runtime\UnmarshallingContext.java
testPackage\impl\runtime\ValidationContext.java
testPackage\impl\runtime\PrefixCallback.java
testPackage\impl\runtime\ValidatorImpl.java
testPackage\impl\runtime\UnmarshallableObject.java
testPackage\impl\runtime\NamespaceContextImpl.java
testPackage\impl\runtime\DefaultJAXBContextImpl.java
testPackage\impl\runtime\UnmarshallerImpl.java
testPackage\impl\runtime\GrammarInfoImpl.java
testPackage\impl\runtime\SAXMarshaller.java
testPackage\impl\runtime\SAXUnmarshallerHandlerImpl.java
testPackage\impl\runtime\UnmarshallingEventHandler.java
testPackage\impl\runtime\InterningUnmarshallerHandler.java
testPackage\impl\runtime\GrammarInfo.java
testPackage\impl\runtime\SAXUnmarshallerHandler.java
testPackage\impl\runtime\XMLSerializer.java
testPackage\impl\runtime\XMLSerializable.java
testPackage\impl\runtime\ValidatableObject.java
testPackage\impl\runtime\MSVValidator.java
testPackage\impl\runtime\MarshallerImpl.java
testPackage\impl\runtime\ValidatingUnmarshaller.java

Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15490
43
According to this, the XML schema type xs:decimal would map to BigDecimal.

Yogesh Gandhi
Ranch Hand
Posts: 226
Jesper de Jong,

Thanks a lot for the list and the information. This would be pretty useful for me.

Yogesh Gandhi
Ranch Hand
Posts: 226
Finally client agreed for changing the data type to xsd:string

Campbell Ritchie
Sheriff
Posts: 50245
79
Yogesh Gandhi,
Your post was moved to a new topic.