Atea - Hero's Grave

面向对象,开源,框架,敏捷,云计算,NoSQL,商业智能,编程思想。

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  40 随笔 :: 0 文章 :: 28 评论 :: 0 Trackbacks
首先来预热一下
System.out.println(2.00 - 1.10);
System.out.println(2.00d - 1.10d);
System.out.println(2.00D - 1.10D);

答案
// 0.8999999999999999
// 0.8999999999999999
// 0.8999999999999999
PS:JAVA Puzzlers(Puzzle 2)

那么,问题是:
一个浮点数X,存到DB里是305.35,页面显示305.34
X = ?

DB用的是MySQL,字段类型是FLOAT(8,2)
后台框架用的是Hibernate
前台显示用的是JSTL tag

答案
X = 305.345

原因
首先把305.345用Hibernate存入DB,DB的保存值会四舍五入为305.35(附录1),而这时POJO里的值仍为305.345
而Java的Format默认规则是"4舍6入5奇偶"(附录2、附录3),所以显示为了305.34

解决办法
1、可以持久化后再从DB取一次值,然后再显示,可保证DB和页面的值保持一致
2、可以多设一位小数保留位,设为3。然后只用前2位
3(推荐)、不要用Float或Double,而用Decimal(Java、MySQL皆如此)

PS:
那这个问题又和预热的题目有什么关系呢?
浮点数的数值是不确定的,遇到了这个问题后,我首先就想到了".99999"这种情况。
附录是我亲自测试的样例,在测试过程中发现了不同版本MySQL在存储浮点数上处理不一致(附录1)。除去".99999"这种情况(限于本人能力有限就不深入研究下去了),可以确定MySQL用的是四舍五入,Java用的是4舍6入5奇偶。

附录1 - 不同版本MySQL在存储浮点数上的区别
MySQL 5.0.27
FLOAT(
8,2)

305.345 -> 305.35
1305.345 -> 1305.35

305.34499999999997 -> 305.35
1305.34499999999997 -> 1305.35

-----------------------------------
MySQL 
5.1.32
FLOAT(
8,2)

305.345 -> 305.35
1305.345 -> 1305.35

305.34499999999997 -> 305.34
1305.34499999999997 -> 1305.35

-----------------------------------
MySQL 
5.1.37
FLOAT(
8,2)

305.345 -> 305.35
1305.345 -> 1305.35

305.34499999999997 -> 305.34
1305.34499999999997 -> 1305.35

-----------------------------------
PS:
使用浮点数可能会遇到意想不到的问题,因为在MySQL中的所有计算用双精度完成。
http://dev.mysql.com/doc/refman/5.1/zh/problems.html#problems-with-float

附录2 - JSTL tag的Format
<!-- 56 -->
<fmt:formatNumber value="${56.5}" pattern="#,###,###,###"/><br>

<!-- 305.34 -->
<fmt:formatNumber value="${305.344}" pattern="###,##0.00"/><br>
<!-- 305.35 -->
<fmt:formatNumber value="${305.354}" pattern="###,##0.00"/><br>
<!-- 1,305.34 -->
<fmt:formatNumber value="${1305.344}" pattern="###,##0.00"/><br>
<!-- 1,305.35 -->
<fmt:formatNumber value="${1305.354}" pattern="###,##0.00"/><br>

<!-- 305.34 -->
<fmt:formatNumber value="${305.345}" pattern="###,##0.00"/><br>
<!-- 1,305.34 -->
<fmt:formatNumber value="${1305.345}" pattern="###,##0.00"/><br>

<!-- 305.36 -->
<fmt:formatNumber value="${305.355}" pattern="###,##0.00"/><br>
<!-- 305.36 -->
<fmt:formatNumber value="${305.365}" pattern="###,##0.00"/><br>

<!-- 305.34 -->
<fmt:formatNumber value="${305.34499999999997}" pattern="###,##0.00"/><br>
<!-- 305.35 -->
<fmt:formatNumber value="${305.35499999999997}" pattern="###,##0.00"/><br>
<!-- 1,305.34 -->
<fmt:formatNumber value="${1305.34499999999997}" pattern="###,##0.00"/><br>
<!-- 1,305.36 -->
<fmt:formatNumber value="${1305.35499999999997}" pattern="###,##0.00"/><br>

附录3 - Java的Format
    @Test
    
public void formatTest() {

        System.out.println(showFloat(
305.344));                                 // 305.34
        System.out.println(showFloat(305.354));                                 // 305.35
        System.out.println(showFloat(1305.344));                                // 1,305.34
        System.out.println(showFloat(1305.354));                                // 1,305.35

        System.out.println(showFloat(
305.345));                                 // 305.34
        System.out.println(showFloat(1305.345));                                // 1,305.34

        System.out.println(showFloat(
305.355));                                 // 305.36
        System.out.println(showFloat(305.365));                                 // 305.36

        BigDecimal decimal 
= new BigDecimal("305.345");
        System.out.println(decimal.setScale(
2, BigDecimal.ROUND_HALF_UP));      // 305.35(四舍五入)

        System.out.println(showFloat(
305.34499999999997));                      // 305.34
        System.out.println(showFloat(305.35499999999997));                      // 305.35
        System.out.println(showFloat(1305.34499999999997));                     // 1,305.34
        System.out.println(showFloat(1305.35499999999997));                     // 1,305.36

    }

    
private String showFloat(double d) {
        
return new DecimalFormat("###,###,###,##0.00").format(d);
    }

posted on 2010-01-18 12:58 Atea 阅读(1674) 评论(0)  编辑  收藏 所属分类: Java languageDatabase

只有注册用户登录后才能发表评论。


网站导航: