问题的提出:
如果我们编译运行下面这个程序会看到什么?
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中的简单浮点数类型float和double不能够进行运算。不光是Java,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上面的错误。现在终于理解为什么要有BCD码了。
这个问题相当严重,如果你有9.999999999999元,你的计算机是不会认为你可以购买10元的商品的。
在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。现在让我们看看如何解决这个问题。
四舍五入
我们的第一个反应是做四舍五入。Math类中的round方法不能设置保留几位小数,我们只能象这样(保留两位):
public double round(double value){
return Math.round(value*100)/100.0;
}
非常不幸,上面的代码并不能正常工作,给这个方法传入4.015它将返回4.01而不是4.02,如我们在上面看到的
4.015*100=401.49999999999994
因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算
java.text.DecimalFormat也不能解决这个问题:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
输出是4.02
在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal
使用BigDecimal并且一定要用String来够造。
但是想像一下吧,如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。你能够忍受这么烦琐的过程吗?下面我们提供一个工具类Arith来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:
public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)
附录
源文件Arith.java:
import java.math.BigDecimal;
/**
* 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精
* 确的浮点数运算,包括加减乘除和四舍五入。
*/
public class Arith{
//默认除法运算精度
private static final int DEF_DIV_SCALE = 10;
//这个类不能实例化
private Arith(){
}
/**
* 提供精确的加法运算。
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算。
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算。
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1,double v2){
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位,以后的数字四舍五入。
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入。
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理。
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
};
分享到:
相关推荐
Java的大数类BigDecimal是用于处理高精度数值计算的工具,尤其在金融、会计等领域,对数值的精度要求非常高,因此避免使用常规的整型和浮点型数据类型。BigDecimal类位于`java.math`包中,它能精确表示任意长度的...
总的来说,掌握BigDecimal的使用对于Java开发者来说至关重要,尤其是在处理涉及金钱计算的项目时。这个简单的复利计算程序是一个很好的实践案例,可以帮助你更好地理解和运用BigDecimal类。通过实践和调试这个程序,...
在前端实际开发中,进行前端计算会出现丢失精度的问题,项目中需要对金钱进行运算,为了使计算结果更准确,故使用bigDecimal工具来实现
综上所述,Java中的金钱处理方法主要包括使用BigDecimal进行精确计算,以及避免精度问题。在实际应用中,还需要考虑货币的格式化、货币转换等问题,确保财务计算的准确性和一致性。对于进一步的复杂计算,可以利用...
在处理金钱和贷款计算时,由于浮点数运算可能存在精度问题,使用`BigDecimal`可以避免因四舍五入导致的误差,确保计算结果的准确性。例如,在计算贷款利息和还款金额时,`BigDecimal`的`add`、`subtract`、`multiply...
在Java中,处理货币通常使用`java.math.BigDecimal`类,因为它能提供高精度的浮点运算,避免因浮点数运算带来的精度问题。这个文件可能包含一个`HalfDollars`类,演示如何进行美元和半美元的计算。 `HalfLoop.java`...
5. **BigDecimal类**:在处理金钱计算时,由于浮点数运算的精度问题,通常不会直接使用`float`或`double`类型,而是选择`BigDecimal`。`BigDecimal`提供了精确的十进制算术操作,确保在红包金额分配时不会出现精度...
为了避免这种误差,我们使用 BigInteger 和 BigDecimal 类来计算高精度整数和高精度小数。 结论: 本文主要介绍了 Java 中的高精度整数和高精度小数,以及如何使用 BigInteger 和 BigDecimal 类来处理高精度整数和...
在财务计算中,由于涉及到金钱的精确计算,通常需要使用固定精度的数字类型,如Java中的`BigDecimal`或Python中的`decimal`模块。`rust-decimal`正是提供了这样的功能,确保了金融交易中的每一笔数额都能精确无误地...
在Java中,`BigDecimal`类是用来处理大数值和高精度计算的,同样适用于四舍五入: ```java BigDecimal bd = new BigDecimal("12345.6789"); BigDecimal rounded = bd.setScale(2, RoundingMode.HALF_UP); System....
16. **money** - 金钱:在财务相关的应用程序中,可能用`double`或`BigDecimal`来表示。 17. **before** - 在……之前:在时间顺序或逻辑顺序中,表示先于某个点。 18. **now** - 现在:常用于表示当前时间,例如...
在前端实际开发中,进行前端计算会出现丢失精度的问题,项目中需要对金钱进行运算,为了使计算结果更准确,故使用bigDecimal工具来实现。
1. **货币数据类型**:在编程中,为了精确处理货币计算,通常会使用特殊的数据类型,比如Java中的`BigDecimal`,它可以避免浮点数运算带来的精度问题。 2. **货币转换**:涉及到不同国家或地区的货币之间汇率的转换...
Java标准库并不提供专门的货币类型,但我们通常使用`BigDecimal`类来处理精确的货币计算,避免浮点数计算时可能出现的精度问题。`BigDecimal`提供了丰富的算术运算方法,如加减乘除,以及比较和格式化等。 2. **...
在Java与MySQL交互时,DECIMAL类型通常与Java的BigDecimal类配合使用,以确保数据在传输过程中的精度不受损失。例如,定义一个名为`TestEntity`的实体类,其中有一个`price`属性,类型为BigDecimal,并在数据库中...
总之,Monetário是一个值得信赖的开源工具,它解决了金融计算中的精度和性能问题,为开发者提供了强大而可靠的货币值处理解决方案。通过拥抱开源社区的力量,Monetário将持续进化,满足日益增长的金融计算需求。...
这两个类在处理金钱计算时非常关键,能防止因浮点数运算产生的精度问题。 5. **设计模式**:为了处理复杂的金融业务逻辑,开发者可能采用了单例、工厂、策略等设计模式。例如,使用单例模式创建唯一的货币服务,...
10. **日志记录**:通过使用如Log4j或java.util.logging,可以记录程序运行过程中的事件和错误,便于调试和问题排查。 综上所述,"Money-Accounting"项目涉及的Java技术涵盖了从数据处理、并发到数据库操作等多个...
业务逻辑模式目的和方法在业务应用程序领域中为领域对象提供设计模式提供作为学习材料和设计技巧以提高类型(值类型)设计技能我们不提供重复使用的通用零件作为基本级别,我们为价值对象提供设计模式,以处理业务中...