问题:

最近在做Java web项目中需要计算金额总和,在这里出现了一个问题是我以前没有关注到的:

System.out.println(2.0-1.1);

执行时候的console中打印输出的是

0.8999999999999999

而不是正常计算出2.0-1.1=0.9这个答案,

原因:

对此我找了一些解答,主要是二进制机器在处理十分之一(0.1)上出现的问题。

主要问题出在小数的二进制表示上:

这里参考了这篇博客所讲的:http://hxraid.iteye.com/blog/504293

(1)  十进制整数如何转化为二进制数

算法很简单。举个例子,11表示成二进制数:

11/2=5   余   1

5/2=2   余   1

2/2=1   余   0

1/2=0   余   1

0结束         11二进制表示为(从下往上):1011

这里提一点:只要遇到除以后的结果为0了就结束了,所有的整数除以2是不是一定能够最终得到0。换句话说,所有的整数转变为二进制数的算法会不会无限循环下去呢?绝对不会,整数永远可以用二进制精确表示 ,但小数就不一定了。

(2) 十进制小数如何转化为二进制数

算法是乘以2直到没有了小数为止。举个例子,0.9表示成二进制数

0.9*2=1.8   取整数部分  1

0.8(1.8的小数部分)*2=1.6    取整数部分  1

0.6*2=1.2   取整数部分  1

0.2*2=0.4   取整数部分  0

0.4*2=0.8   取整数部分  0

0.8*2=1.6   取整数部分  1

0.6*2=1.2   取整数部分  0

.........      0.9二进制表示为(从上往下): 1100100100100......

注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。

这也就解释了这个问题出现的原因。

解决:

知道原因之后我们应该怎么做呢?其实可以用Java中提供的

BigDecimal实现精确加减乘除运算

BigDecimal提供的BigDecimal(String val)构造方法,使用BigDecimal要用String来够造,要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。

加减乘除操作:

public BigDecimal add(BigDecimal value);
public BigDecimal subtract(BigDecimal value);
public BigDecimal multiply(BigDecimal value);
public BigDecimal divide(BigDecimal value);

在计算完之后,利用doubleValue()方法将BigDecimal转换成Double类型就可以避免上述的错误了。

Java中的二进制运算出错问题的更多相关文章

  1. java中的二进制运算简单理解

    package test9; public class StreamTest { public static void main(String[] args) { int a = 15;// 0b11 ...

  2. java中关键字this的使用

    在团队代码中看到对于当前类中的方法,使用了this关键字.经过测试发现,在此种情况下,this关键字的使用可有可无.因此,对java中this的使用做下总结: package testTHIS; pu ...

  3. 【实战Java高并发程序设计 1】Java中的指针:Unsafe类

    是<实战Java高并发程序设计>第4章的几点. 如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现.现在,就让我 ...

  4. 【Java心得总结二】浅谈Java中的异常

    作为一个面向对象编程的程序员对于 下面的一句一定非常熟悉: try { // 代码块 } catch(Exception e) { // 异常处理 } finally { // 清理工作 } 就是面向 ...

  5. java中的equals()方法重写

    如何java中默认的equals方法跟实际不符的话,需要重写equals方法.例如: public class TestEquals { public static void main(String[ ...

  6. java 中构造函数 的理解

    构造方法就是与类同名的那个方法,它的作用是可以用来初始化 class Person{ public Person(String n,int a) {//构造方法 name = n; age = a; ...

  7. java中的23中设计模式(转)

    设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. Java中的构造代码块

    代码块 ----a静态代码块 ----b构造代码块 ----c普通代码块 执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. a.静态代码块: 静态代码块 ...

  9. 关于Java中null的十点详解

    对于每一个Java程序员来说,null肯定是一个让人头痛的东西,连Java的发明者都承认这是一项巨大的设计失误,今天就来总结一下Java中关于null的知识. 1.null不属于任何类型,可以被转换成 ...

随机推荐

  1. BZOJ1563: [NOI2009]诗人小G(决策单调性 前缀和 dp)

    题意 题目链接 Sol 很显然的一个dp方程 \(f_i = min(f_j + (sum_i - sum_j - 1 - L)^P)\) 其中\(sum_i = \sum_{j = 1}^i len ...

  2. Spring文件下载

    package com.smbea.demo.controller; import java.io.BufferedInputStream; import java.io.BufferedOutput ...

  3. java实现一个简单的数学表达式分析器(加减乘除和括号)

    1.使用此分析器需要输入两个量: String str1=运算符号有前后有空格的数学表达式(如 1 + 2 *  ( 3+1)  - 5 #),并在最后添加‘#’字符作为结束标志: String st ...

  4. 如何使用Nunit进行测试

    如何使用Nunit进行测试(Visual Studio 2017 comminity) 原文:如何使用Nunit进行测试(Visual Studio 2017 comminity) 一.环境 操作系统 ...

  5. ChromiumFX

    序言 开发C#桌面应用程序有很多选择,比如WinForm或WPF. 这里我们用ChromiumFX. 目录 一.Centos7 从零编译Nginx+PHP+MySql 二.Centos7 从零配置Ng ...

  6. PHP switch分支语句中省略break后还会执行其他case的原因分析

    请分析以下PHP代码的输出结果: $a= 'dog'; switch($a) { case 'cat': echo "\$a is cat"; case 'dog': echo & ...

  7. Azure本月最新活动,速度Mark!

    桃花夭夭,渌水盈盈,就这样四月的脚步迫不及待地来了.为了帮助您能在第一时间了解 Azure 最新的活动,我们推出每月活动合集,你准备好了吗,一起来看吧! 立即访问http://market.azure ...

  8. java中将数组、对象、Map、List转换成JSON数据

    如果要将数组.对象.Map.List转换成JSON数据,那我们需要一些jar包: json-lib-2.4-jdk15.jar ezmorph-1.0.6.jar commons-logging.ja ...

  9. linux下使用iperf测试服务器带宽

    准备工具 1.2台Linux服务器(要求其中至少1台主机为腾讯云主机,另外一台任意主机均可,确保2台主机可以互相访问即可)2.Iperf软件为专业网络性能测试工具. 测试目标 上海地区主机外网带宽是否 ...

  10. FastRCNN 训练自己数据集 (1编译配置)

    http://www.cnblogs.com/louyihang-loves-baiyan/p/4885659.html 按照博客的教程配置,但自己在服务器上配置时,USE_CUDNN = 1会报错, ...