`

浮点数运算的陷阱

    博客分类:
  • JAVA
F# 
阅读更多
    浮点数的运算不能说是精确的,因为某些数字不能准确表示为二进制(例如: 0.1),以下是一个用浮点数运算的例子,例子证明了我们应该慎用浮点数运算。

/**
 * @author crane.ding
 */
public class Test {

	public static void main(String[] args) {
		final float ff = 0.6f + 0.1f;
		final double fd = 0.6f + 0.1d;
		final double df = 0.6d + 0.1f;
		final double dd = 0.6d + 0.1d;
		
		System.out.println(ff + " : " +(ff == 0.7f));
		System.out.println(fd + " : " +(fd == 0.7d));
		System.out.println(df + " : " +(df == 0.7d));
		System.out.println(dd + " : " +(dd == 0.7d));

		System.out.println("\nfloat");
		for (float f = 0; f < 1; f = f + 0.1f)
			System.out.println(f);
		
		System.out.println("\ndouble");
		for (double d = 0; d < 1; d = d + 0.1)
			System.out.println(d);
	}

}

运行结果如下:
0.70000005 : false
0.7000000238418579 : false
0.7000000014901161 : false
0.7 : true

float
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001

double
0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999

从以上的运行结果我们不难看出,浮点数的运算是有误差的,例如0.2加0.1就不等于0.3;对于金额的运行如果采用浮点数,那计算出来的金额就不一定是准确的;这也是许多程序开发人员经常接触,而未考虑到的一个小陷阱。
分享到:
评论
4 楼 miaow 2010-04-08  
如果能确保一些前提的话,用double也是可行的。
至少应该确认数字的精度要求在一定数量内、总位数在一定数量内。
这时候所谓的陷阱根本不是问题,完全可以用其他方式搞定。
比较时用差数小于一定值。比如人民币用0.001。
再比如说数据库指定长度而不是傻乎乎的Number/Decimal,输出加format等等。

但保证累计误差问题就麻烦了,呵呵,碰上来回加减的就知道厉害了。
比如说一系列成本按比例拆分到若干部门/业务,有些钱数很大,累计拆下来累计误差可能就够收支对不齐了。
在财务眼里这属于对他们的屠杀兼IT自杀。

再举个例子,对人民币可以用0.001以内当相等。
但有带三位小数的钱,比如说突尼斯。得改成四位小数判等。
又有钱超级不值钱数额很大的,考虑钱数上线的时候可能要按10以内算相等。
虽然说用BigDecimal类似问题也偶尔需要考虑,但总归少多了。

如果用double,等修改钱数范围的时候就知道想撞墙是什么意思了。
大家都知道,能在变更的时候把这么细节的修改涉及的所有地方都想到的是超人。
所以没明确证据表明确实是BigDecimal影响性能到不可用、且其他修改更困难之前,还是用BigDecimal吧。
3 楼 shuiguozheng 2010-04-06  
那最好的方式应该怎么处理呢!
2 楼 crane.ding 2010-04-04  
呵呵! 是啊,昨天突然想到就在博客上做一下笔记记下来! BigDecimal的目的就是精确的表示小数,但是其开销也是挺大的。BigDecimal对象是不可变的,每一次操作都会产生新的BigDecimal对象,显然BigDecimal不太适合大量的数据运算。
1 楼 phenom 2010-04-04  
不是未考虑,用BigDecimal,而且这样的文章这里也有不少的.

相关推荐

    第2章 Ⅱ:浮点数-v11

    本章主要探讨的是IEEE浮点数标准,即IEEE 754,它是现代计算机系统中浮点数运算的基础。 首先,我们要了解浮点数的基本构成。浮点数由三部分组成:符号位(sign),阶码(exponent)和尾数(fraction)。符号位决定...

    C语言浮点数探析

    浮点数运算中不可避免会出现舍入误差,这是由于浮点数表示上的限制造成的。例如,0.1在二进制中是一个无限循环小数,无法完全精确表示,这会导致在累加过程中产生累积误差。 #### 五、结论 通过对C语言中浮点数的...

    浮点数的数据结构.pdf

    5. **浮点数比较的陷阱**: 在Java中,直接比较浮点数可能会导致意外的结果,因为它们在内存中存储的方式可能导致微小的精度差异。例如,`float`类型的20.3f与`double`类型的20.3d比较时可能会得到false,这是因为在...

    c语言编程中常见的陷阱和漏洞

    6. **浮点数精度问题**:C语言中的浮点数运算不是精确的,可能导致预期之外的结果。在比较浮点数时,不要直接使用等号,而是设定一个微小的容差值。 7. **逻辑错误**:比如条件判断错误、循环控制不当、逻辑与或...

    1222-张国旗-JAVA陷阱.rar

    10. **浮点数精度问题**:Java中的浮点数运算可能出现精度丢失,不适用于需要精确计算的场景。对于金融计算等高精度需求,可以使用BigDecimal类。 以上只是Java编程中可能遇到的部分陷阱,实际的PPT可能还涵盖了更...

    java解惑.pdf

    ### Java解惑:深入理解Java中的奇数检测与浮点数运算 #### 奇数检测的陷阱 在Java编程中,我们经常会遇到需要判断一个整数是否为奇数的情况。一个直观的想法是通过模运算 `%` 来实现这一点。然而,在实际应用中,...

    JAVA编程指南.pdf

    2. **浮点数相减陷阱**:浮点数运算由于精度问题可能会导致非预期的结果,需要谨慎处理。 3. **长整除陷阱**:使用整数除法时,除数和被除数都是长整型,结果可能会丢失小数部分。 4. **互换内容陷阱**:在交换两...

    程序设计-小数的存储.pptx

    此外,不同的浮点数运算顺序也可能导致结果的微小差异,这在进行比较运算时需要特别注意。 4. 实型常量: 在程序中,浮点数可以直接作为常量出现,称为实型常量。例如,3.14159就是浮点数常量。在不同编程语言中,...

    解决JS浮点数(小数)计算加减乘除的BUG

    1. **四舍五入**:在进行浮点数运算后,通过使用`toFixed()`方法对结果进行四舍五入。例如,`Math.round((0.1 + 0.2).toFixed(2))`将得到`0.30`,然后再转换回数字。 2. **使用库**:有些库如`decimal.js`或`big.js...

    JAVA面试谜题解惑.pdf

    #### 找零时刻谜题:浮点数运算的陷阱 **题目背景:** 本题旨在考察面试者对Java中浮点数运算的理解,特别是对于浮点数表示不精确性的认识。 **题目描述:** 题目给出了一段代码,用于模拟一个简单的找零场景。...

    c语言陷阱.docx

    是一个返回类型为浮点数指针的函数,float (*h)(); 是一个函数指针,h 指向函数的返回值为浮点类型。 2.2 对表达式的是否为 0 的判断要显式说明,如 if(flag != 0)。 2.3 struct 声明要加分号,如果函数没有指定...

    计算机与信息科学类试题(事业单位考试适用).pdf

    17. 浮点数运算:问题17显示了浮点数运算的陷阱,其中`(1/2)*(a+b)*h`的结果可能与代数计算不符,因为整数除法会丢失小数部分。 18. C语言输出:问题18涉及到整数和八进制数的输出,`printf`会按照整数格式打印`x`...

    JAVA解惑.pdf

    2. 浮点数运算可能会因精度限制导致不精确的结果,特别是在涉及金融计算时,应避免直接使用`double`或`float`类型,转而使用`BigDecimal`以获得精确结果。 3. 在编程实践中,深入理解Java类库中的各种操作符和类的...

    java面试中的陷阱java面试中的陷阱

    这是因为`Math.round()`方法将浮点数四舍五入到最接近的整数,对于负数采用向下取整。 #### 七、类型转换与短路运算 - `short s1 = 1; s1 = s1 + 1;` 这段代码会导致编译错误,因为`s1 + 1`的结果是一个int类型的...

    c缺陷与陷阱(笔记2)

    - 构造函数声明:函数声明的方式应与其使用方式一致,理解声明符(declarator)的作用很重要,如`float *g()`表示返回浮点数指针的函数。 - 运算符优先级:条件运算符(?:)的优先级高于赋值运算符,而`&`、`^`和`...

    BasmForBeginners-cn

    - 进一步深化对浮点数运算的理解,包括更复杂的数学函数如三角函数、指数函数等。 - 探讨如何使用BASM来实现这些函数,同时考虑到性能和精度的平衡。 - 讨论了一些高级优化技巧,如使用FPU寄存器来减少内存访问...

    c_traps_and_pitfalls.zip

    8. **浮点数精度**:C语言的浮点数运算不是精确的,因此比较浮点数时需要特别注意,通常使用一个很小的误差范围来判断是否相等。 9. **函数调用约定**:不同的编译器和平台可能使用不同的函数调用约定,不兼容的...

    Java理论与实践:您的小数点到哪里去了?

    使用BigDecimal时,需要特别注意性能,因为它比浮点数运算慢得多,但可以避免因为浮点数不精确性引起的潜在问题。 在实际编程中,理解这些差异和陷阱是非常关键的。浮点数应主要用于近似计算,而BigDecimal适合于...

    c语言的陷阱与学习笔记

    此外,C语言的可移植性问题主要源于标准的模糊性和不同实现的差异,如内存管理、浮点数处理等,编写可移植的代码需要对这些差异有深入理解。 6. **类型转换与函数指针** 类型转换在C语言中广泛使用,尤其是在涉及...

    JavaScript语言教程&案例&相关项目资源

    - **问题描述**:在使用JavaScript进行浮点数运算时,可能会遇到精度丢失的问题,例如`0.1 + 0.2 !== 0.3`。 - **解决方案**: - 使用`toFixed()`方法将结果四舍五入到特定的小数位数。 - 对于金额处理等精确度...

Global site tag (gtag.js) - Google Analytics