Performance Zone is brought to you in partnership with:

With nearly two decades of experience working in the IT industry in various roles as Enterprise technology consultant, Java Architect, project leader, Engineer, Designer and Developer, Mr. Knutson has gained a wide variety of experience in disciplines including JavaEE, Web Services, Mobile Computing and Enterprise Integration Solutions. Over the course of his career, Mr. Knutson has enjoyed long lasting partnerships with many of the most recognizable names in the Health Care, Financial, Banking, Insurance, Manufacturing, Telecommunications, Utilities, Product Distribution, Industrial and Electronics industries employing industry standard full software life cycle methodologies including the Rational Unified Process (RUP), Agile, SCRUM, and Extreme Programming (XP). Mr. Knutson has also undertaken speaking engagements, training seminars, white paper and book publishing engagements world-wide. As an active Blogger and tweeter, Mr. Knutson has also been inducted in the prestigious DZone.com Most Valuable Blogger (MVB) group and can be followed at http://www.dzone.com/page/mvbs and twitter at http://twitter.com/mickknutson. Able to quickly and effectively adapt to any phase of an existing project from Business Modeling to Production Support, Mr. Knutson’s wide array of technical expertise in OOA / OOD / OOP, Java, J2EE, Internet, Oracle, Enterprise Integration and Message Oriented Middleware allow him to seamlessly integrate into your Information Systems project at any phase and provide immediate productivity. Mr. Knutson is exceptional at team building and motivating either at a peer-to-peer level, or in a leadership role with excellent communications skills and the ability to adapt to all environments and cultures with ease. Mick is a DZone MVB and is not an employee of DZone and has posted 18 posts at DZone. You can read more from them at their website. View Full User Profile

Unexpected Java Float Precision Changes

10.14.2012
| 5007 views |
  • submit to reddit

I ran across a little gotcha today where a float value being inserted into another object container (JSONObject) was not holding the precision of the original value. The JSONObject actually takes a double not a float, and I overlooked the up-casting initially until I started unit testing. (have to love unit tests!)

here is a print of the values I started with:

07:46:15.108 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - ===== abv:: calculateAbv =====
07:46:15.117 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - volume: 16
07:46:15.118 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - abv: 3.2
07:46:15.118 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - price: 5.99
07:46:15.118 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - value_r: 0.117
07:46:15.118 [http-apr-8080-exec-49] INFO c.b.javaee6.service.AbvResource - score_r: 12.0

Here is how I was creating my JSONObject:

JSONObject json = new JSONObject();
json.put("abv_r", valueObject.getAbv());
json.put("volume_r", valueObject.getVolume());
json.put("price_r", valueObject.getPrice());
json.put("value_r", valueObject.getValue());
json.put("score", valueObject.getScore());
result = json.toString();

result:
{“abv_r”:3.200000047683716,”volume_r”:16,”price_r”:5.989999771118164,”value_r”:0.11699999868869781,”score”:12}

The JSONObject.put method does not take a float, but takes a double:

/**
* Put a key/double pair in the JSONObject.
*
* @param key A key string.
* @param value A double which is the value.
* @return this.
* @throws JSONException If the key is null or if the number is invalid.
*/
public JSONObject put(String key, double value)
throws JSONException {
    put(key, new Double(value));
    return this;
}

@see org.codehaus.jettison.json.JSONObject

Now when I cast the values to String’s such as

“”+valueObject.getAbv()

The precision of the values are not cast to doubles:

JSONObject json = new JSONObject();
json.put("abv_r", ""+valueObject.getAbv());
json.put("volume_r", ""+valueObject.getVolume());
json.put("price_r", ""+valueObject.getPrice());
json.put("value_r", ""+valueObject.getValue());
json.put("score", ""+valueObject.getScore());
result = json.toString();

result:

{“abv_r”:”3.2“,”volume_r”:”16″,”price_r”:”5.99“,”value_r”:”0.117“,”score”:”12.0“}

Conclusion

So care needs to be taken to remember other Objects can cast your objects to have undesirable affects.

Another solution is to ensure the valueObject uses double’s then no casting is performed when putting the values into the JSONObject.

 

 

Published at DZone with permission of Mick Knutson, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Dapeng Liu replied on Mon, 2012/10/15 - 12:07am

if you want to be precise, use BigDecimal

Andreas Haufler replied on Mon, 2012/10/15 - 1:39am

I'd like to agree with the previous comment. Actually I'd put it that way: If you work with money / prices (price_r) you HAVE TO use BigDecimal. There are some good "Money" implementations based on BigDecimal around which take care of rounding, scale and formatting.

 Nevertheless, thanks putting up an article and for warning about unintentional casts and the "danger" of floating point values.

 regards Andy

Alejandro Dobniewski replied on Mon, 2012/10/15 - 12:34pm

You Shall Not use floating point data types for money data. Never.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.