Java中使用BigDecimal进行浮点数运算_java

最近研究了一下Java的浮点数计算问题,从网上查询了相关的资料,汇总并经过了一些整理和调试,最后完成此文,欢迎大家指出其中的错误和问题。
在Java中,float声明的变量是单精度浮点数,double声明的变量是双精度浮点数,顾名思义就是double型的实体占用内存空间是float的两倍。float是4个字节而double是8个字节。float和double类型的数据,无法精确表示计算结果,这是由于float和double是不精确的计算。大家可以通过下面代码可以看出来:

复制代码 代码如下:

public class Test
{
public static void main(String[] args)
{
System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);
}
}

运行的结果为:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

要想获得理想的效果,我们可以尝试使用java.text.DecimalFormat格式化浮点数:
DecimalFormat可以按照一定的格式格式化数字,常用的格式化字符是#、0等。例:

复制代码 代码如下:

System.out.println(new java.text.DecimalFormat("0.00").format(3.125));
System.out.println(new java.text.DecimalFormat("0.00").format(3.135));

但是得到的结果是:
3.12
3.14

这是因为DecimalFormat是使用half-even 舍入(ROUND_HALF_EVEN),简单的说就是向当四舍五入的5的时候向最近的偶数靠。所以使用DecimalForamt也无法得到可靠的浮点数。最后我们可以考虑使用BigDecimal来获得更精确的计算:

BigDecimal提供了多个构造函数,和浮点数有关的有:

复制代码 代码如下:

BigDecimal(double val)  Translates a double into a BigDecimal.
BigDecimal(String val)  Translates the String repre sentation of a BigDecimal into a BigDecimal.

但是用double参数来创建对象得到不精确的值,只有通过String来创建对象才是最准确的。

例如:

复制代码 代码如下:

BigDecimal bd1=new BigDecimal(0.05);
System.out.println(bd1.toString());
BigDecimal bd2=new BigDecimal("0.05");
System.out.println(bd2.toString());

得到结果:

0.05000000000000000277555756156289135105907917022705078125
0.05

所以,我们最终需要使用String来创建对象,这样得到的结果才是最精确的。另外,如果是double数,我们还可以使用:BigDecimal.valueOf(double val),原因很简单,其JDK源码如下所示:

复制代码 代码如下:

public static BigDecimal valueOf(double val)
{
return new BigDecimal(Double.toString(val));
}

最后需要说明的是:BigDecimal的加减乘除其实最终都返回的是一个新的BigDecimal对象,因为BigDecimal是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以a.add(b);虽然做了加法操作,但是a并没有保存加操作后的值,正确的用法应该是a=a.add(b)。

时间: 2024-09-20 01:06:09

Java中使用BigDecimal进行浮点数运算_java的相关文章

Java简单类型进行精确浮点数运算

运算 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入. 以下为代码: import java.math.BigDecimal; public class Arith { //默认除法运算精度 private static final int DEF_DIV_SCALE = 10; //这个类不能实例化 private Arith(){ } /** * 提供精确的加法运算. * @param v1 被加数 * @param v2 加数 *

java中的移位运算符心得总结_java

java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >> 1,相当于num除以2 >>>    :     无符号右移,忽略符号位,空位都以0补齐 下面来看看这些移位运算都是怎样使用的 复制代码 代码如下: /** *  */package com.b510.test; /** * @author Jone Hongten * @creat

深入讲解Java中的流程控制与运算符_java

Java流程控制 Java流程控制的语法与 C/C++ 类似,也有 if...else.while.do...while.for.switch...case等,这里不再讲述具体语法,仅举例说明. 输出九九乘法表(右上三角): public class Demo { public static void main(String[] args){ int i, j; for(i=1; i<=9; i++){ for(j=1; j<=9; j++){ if(j<i){ //打印八个空格,去掉空

对Java中传值调用的理解分析_java

本文实例分析了Java中的传值调用.分享给大家供大家参考.具体分析如下: Java以引用的方式操作对象实例 可以确认的是Java中操作对象的方式是以引用的方式操作对象.为了更深刻的了解这点我写了如下代码: 首先定义一个自定义类型 复制代码 代码如下: public class Person {            String name;            Person(String name){          this.name = name;      }  } 这里name默认是

java中的hashCode方法小例子_java

在java中,有一个这样的规定,就是两个相同的对象(即equals运算为true),它们的hash code也必须相同.在Object类中有一个hashCode方法,可以调用它来查看对象的hash code.下面举例说明. 复制代码 代码如下: package test; public class Test {  public static void main(String args[]){  String str1 = "aaa";  String str2 = str1;  Str

java中lambda表达式简单用例_java

我对java中lambda表达式的看法是相当纠结的: 一个我这么想:lambda表达式降低了java程序的阅读体验.java程序一直不以表现力出众,正相反使Java流行的一个因素正是它的安全和保守--即使是初学者只要注意些也能写出健壮且容易维护的代码来.lambda表达式对开发人员的要求相对来说高了一层,因此也增加了一些维护难度. 另一个我这么想:作为一个码代码的,有必要学习并接受语言的新特性.如果只是因为它的阅读体验差就放弃它在表现力方面的长处,那么即使是三目表达式也有人觉得理解起来困难呢.语

关于JAVA中this的使用方法小结_java

我知道很多朋友都和我一样:在JAVA程序中似乎经常见到"this",自己也偶尔用到它,但是到底"this"该怎么用,却心中无数!很多人一提起它,就说"当前对象",可到底什么是当前对象,是什么当前对象,他自己也不清楚.现在让大家看一个小例子,给你分享一下JAVA中"this"的用法! 复制代码 代码如下: /**  * @author fengzhi-neusoft  *  * 本示例为了说明this的三种用法!  */ pac

Java中的深拷贝和浅拷贝介绍_java

一.引言   对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去.在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部 数据.Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy).深拷贝(Deep Copy).延迟拷贝(Lazy Copy). 二.浅拷贝 1.什么是浅拷贝   浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝.如果属性是基本类型,拷贝的就是基本类型的值:如果属性是内存地

Java中的static的使用指南_java

一.Java中的static使用之静态变量 1.Java 中被static修饰的成员称为静态成员或类成员.它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享.且优先于对象存在.静态成员可以使用类名直接访问,也可以使用对象名进行访问.使用 static 可以修饰变量.方法和代码块. 2.public 修饰符表示公开的.公有的,静态变量使用static修饰 3.静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员. public class HellWorld{ String