`
yuanc00
  • 浏览: 29927 次
社区版块
存档分类
最新评论

Java浮点数使用小结

    博客分类:
  • java
 
阅读更多

1.    引子

    平常在代码中,从不缺少使用浮点数的地方。浮点数可以使用float和double类型进行定义。默认都是使用的double类型,如果需要声明为float类型,需要显示地加F或者f,比如Float fNumber = 1.234F。往常个人在使用的时候,使用float居多(在java的基本类型中,Float是32位,4个字节;Double是64位,8个字节;所以float相对来说节省内存),近来踩了两个坑,觉得还是double比较省心。记录如下。

 

2.    问题1 – 精度错误

2.1 表现形式问题一示例如下。

    需要将一组对象转换成json,使用的json包是json-lib 2.2版本。


图2.1 json-lib包引用

 

图2.2 问题1示例
 
图2.3 问题1结果


    可以看到在将浮点数转换成json数据的时候,Float类型的浮点数会出现精度错误的问题。

 

2.2 问题原因

    排查原因,发现在json-lib的库里面,对于Float类型的数据,是先将其转换成Double类型之后,然后再进行处理的。处理代码如下。

 

图2.4 json-lib对于Float的处理


    Float的doubleValue方法是直接进行类型转换,即return (double)value。
    Float和Double在内存中的存储长度不同,将Float转换成Double类型的时候,如果直接取Float的doubleVlaue方法,会进行位数的补全;特别是在有小数部分的时候,这样是不能保证精度的,这样就引起了我们现在的问题。

 
2.3 解决方法

 

    解决问题的方法有两个思路。

  • 在整个系统中以double类型存储,替换掉现有的以float类型存储的方式;
  • 找到float类型转换成double类型的安全的方法。

    第一个思路,可以彻底的解决这个问题,但是对于一个系统来说,进行全局替换需要慎重,所以暂时不进行这样的修复;
    第二个思路,可以有以下几种方案。

  • 因为我们的精度要求保留到小数点之后的两位即可,所以可以将原值value乘以100,然后取long值,将结果再除以100.0转换成double类型;
  • 使用BigDecimal;
  • 先将float类型的数值转换成String,然后将String转换成Double类型的即可。比较了一下,调用Double.valueOf(String value)方法和直接新建Double对象(new Double(String value))都是可以的;但是前者只需要创建对象一次,后者需要新建两个Double对象,为了节省开销,使用了第一个方法进行了处理。

    解决问题的代码如下。
 

图2.5 问题解决


    先判断要处理的值是float类型,然后调用Double的valueOf方法进行处理。


3.    问题2 – 大数表示问题

3.1 表现形式


    解决了上面这个json输出的问题之后,又发现了一个问题。对于一些较大的数值,比如9999999.99;最终的输出结果为1.0E7,而不是预期的数值。


3.2 原因分析


    按理来说,float存储的范围应该远大于这个数值,经过一系列的调试,发现是float类型转换成String的时候出现的问题。进一步深入,发现是float类型的存储结构导致的。
    在java中,float类型存储的长度是32bit,double类型的存储长度是64bit。如下表所示。


表3.1 float和double在java中的存储

  符号位(bit) 指数位(bit) 尾数位(bit)
Float(32bit) 1 8 23
Double(64bit) 1 11 52


    其中:

  • 符号位表示数值的正负;
  • 指数位表示数值的取值范围,以补码形式存储;
  • 尾数位表示数值的精度。

    对于float来说,2^23=8388608;所以float类型的数值,如果有效数字的数值超过了8388608这个值,系统会自动找一个近似的结果进行代替。这也是我们这里存储9999999.99的时候,结果异常的原因。这个值在存储的时候就已经被处理成了1.0E7,所以不论采用什么方式进行处理,都不会有改善的。这里也说明,float类型,可以保证6-7位的有效数字(6位及以下是绝对可以保证的,但是7位的时候,这个有效数字的数值如果超过了8388608,就无法进行表示了)。
    对于double类型,2^52=4503599627370496;所以double类型的有效数字在15-16位。
    所以我们遇到的问题2,目前是没有办法进行解决的。后续还是安排使用double类型替换float类型。

 

4.    小结

     本文从两个问题说明了float类型的“坑爹”之处,如果不是对业务以及业务的发展特别有把握,还是建议使用double类型。

  • 大小: 9.6 KB
  • 大小: 55.6 KB
  • 大小: 5.3 KB
  • 大小: 9.6 KB
  • 大小: 11.7 KB
  • 大小: 11.7 KB
分享到:
评论

相关推荐

    Java编程开发 Java输入语句小结.doc

    在Java编程中,输入语句是程序与用户交互的关键部分,允许用户向程序提供数据。以下是对Java输入语句的详细总结,主要介绍两种常用的方法:`Scanner`类和`BufferedReader`类。 1. 使用`Scanner`类: `Scanner`类是...

    java小结

    #### 小结 通过以上内容,我们对Java的基础知识有了更深入的理解。了解这些基础知识对于编程非常重要,特别是对于初学者来说。掌握了这些概念后,你可以更好地理解和编写Java代码,同时也能避免一些常见的错误和...

    core java 小结

    Java是一种强类型语言,这意味着在使用任何变量前必须明确其类型。这不仅帮助程序员管理数据,也确保了程序的安全性和稳定性。以下是Java中8种基本数据类型及其占用的空间大小: - `byte`:1字节(8位) - `short`...

    十分有用的java小结

    十分有用的 Java 小结 在这篇文章中,我们将讨论 Java 编程语言中的一些基础知识和输入输出处理技巧,这些技巧对于 ACM 竞赛和OI竞赛尤其重要。 一、Java 之 ACM 注意点 在 ACM 竞赛中,Java 程序员需要注意以下...

    java数组与字符串用法小结

    ### Java数组与字符串用法小结 在Java编程语言中,数组和字符串是两种非常重要的数据类型,它们在处理大量数据或文本时扮演着至关重要的角色。本文将围绕标题“java数组与字符串用法小结”及描述中的知识点进行详细...

    java的输入语句小结.pdf

    这里需要注意的是,当读取整数和浮点数时,需要使用 `Integer.parseInt()` 和 `Float.parseFloat()` 将字符串转换为对应的数值类型。 在使用 `BufferedReader` 时,一个重要的注意事项是,如果需要读取多行,需要...

    湖北汽车工业学院Java实验一 Java编程环境使用

    #### 小结 本实验旨在帮助学生掌握Java开发环境的搭建与使用,理解Java语言的基础知识和String类的使用技巧。通过实践操作,学生不仅能够熟悉Java的开发流程,还能加深对面向对象编程的理解。这对于进一步学习更复杂...

    java的输入语句小结.docx

    `Scanner`类是Java的标准输入处理工具,它提供了多种方法来读取不同类型的数据,如整数、浮点数、字符串等。首先,我们需要导入`java.util.Scanner`包。以下是一个简单的示例: ```java import java.util.Scanner; ...

    java试题小结可以下载的

    【Java试题小结】 1. **Applet生命周期与方法**: - 在Java中,Applet的生命周期包括初始化、启动、绘画、停止和销毁几个阶段。`init()`方法用于初始化Applet所需资源,`paint()`方法负责在屏幕上绘制图形,如线条...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    3.4 小结:基本数据类型—— Java中一切数据和运算的基础 63 3.5 习题 65 第4章 Java中的程序执行流程 67 教学视频:1小时57分钟 4.1 顺序执行 67 4.2 使用if-else让程序懂得判断 68 4.2.1 if语句 68 4.2.2 ...

    java输入语句scanner 使用方式

    #### 五、小结 通过上述介绍,我们可以看出 `Scanner` 类是 Java 中处理输入的一个强大工具。无论是从控制台还是从文件读取数据,`Scanner` 类都能提供简便且灵活的方法来处理各种类型的数据。掌握 `Scanner` 类的...

    java实验报告

    【Java实验报告】 Java实验报告主要涵盖了两个核心实验:JDK的安装与配置以及简单的程序编写,以及理解和使用Java的类型、变量和表达式。...实验后的分析和小结对于巩固知识和提高编程技能至关重要。

    Java大学实用教程 实验二 基本数据类型和数组 实验报告

    7. **实验小结**: - 显式类型转换:在Java中,当需要改变数据类型的表示范围时,需要使用强制类型转换(例如`(char)`或`(int)`)。 - `Scanner`类的使用:通过`Scanner`的`nextDouble()`方法可以获取用户输入的...

    详解Java判断是否是整数,小数或实数的正则表达式

    ### 小结 在Java中使用正则表达式进行数值判断是高效且实用的方法。通过正则表达式,我们可以精确地定义并匹配字符串的格式,从而有效地完成输入验证。该方法适用于各种需要对输入数据进行格式化验证的场景,例如...

    Java中Scanner类的用法

    #### 四、小结 通过上述介绍可以看出,`Scanner`类提供了一种非常简便的方式来处理输入输出操作,尤其适合于需要读取不同数据类型的情况。无论是从控制台还是文件读取数据,`Scanner`都能提供有效的支持。此外,`...

    java程序设计项目化教程\技术文章\java基本数据类型

    ### 小结 以上介绍了 Java 中五种基本数据类型 (`boolean`, `byte`, `char`, `double`, `float`) 与它们的封装类 (`Boolean`, `Byte`, `Character`, `Double`, `Float`)。这些封装类不仅提供了一种将基本类型值包装...

    事件编程小结

    ### 事件编程小结 在Java中,事件处理机制是一种非常重要的编程模型,尤其是在图形用户界面(GUI)设计中。事件编程允许程序响应用户的输入,如点击按钮、移动鼠标等。本文将详细介绍Java中的事件处理机制,特别是...

Global site tag (gtag.js) - Google Analytics