-
BigDecimal之性能问题10
我们知道浮点数存在精度丢失问题。(精度为什么会丢失,本人之前做过一个总结,可以参考:java 浮点数为什么精度会丢失
为了精度问题,我们常常不直接使用浮点数,常常是采用BigDecimal来替换浮点数。本文主要想探索一下BigDecimal相比于double性能上可能存在的一些问题。
先说一下现象:本人在实现一个算法的时候(算法运算量十分巨大),为了避免精度丢失,使用了BigDecimal,发现运算时间是几个小时。而换做double之后才花了将近10钟。这么大的差距难于置信!
于是写了一个简单的测试程序如下:(注:以下测试为了纯测试和比较!)import java.math.BigDecimal; public class BigDecimalEfficiency { public static int REPEAT_TIMES = 1000000; public static double computeByBigDecimal(double a, double b) { BigDecimal result = BigDecimal.valueOf(0); BigDecimal decimalA = BigDecimal.valueOf(a); BigDecimal decimalB = BigDecimal.valueOf(b); for (int i = 0; i < REPEAT_TIMES; i++) { result = result.add(decimalA.multiply(decimalB)); } return result.doubleValue(); } public static double computeByDouble(double a, double b) { double result = 0; for (int i = 0; i < REPEAT_TIMES; i++) { result += a * b; } return result; } public static void main(String[] args) { long test = System.nanoTime(); long start1 = System.nanoTime(); double result1 = computeByBigDecimal(0.120000000034, 11.22); long end1 = System.nanoTime(); long start2 = System.nanoTime(); double result2 = computeByDouble(0.120000000034, 11.22); long end2 = System.nanoTime(); long timeUsed1 = (end1 - start1); long timeUsed2 = (end2 - start2); System.out.println("result by BigDecimal:" + result1); System.out.println("time used:" + timeUsed1); System.out.println("result by Double:" + result2); System.out.println("time used:" + timeUsed2); System.out.println("timeUsed1/timeUsed2=" + timeUsed1 / timeUsed2); } }
运行结果如下:
result by BigDecimal:1346400.00038148
time used:365847335
result by Double:1346400.000387465
time used:5361855
timeUsed1/timeUsed2=68
从结果上来看BigDecimal给我们带来了精度上的提升,但是性能上的损耗是巨大的。同样的运算时间居然是double的68倍。
也难怪我的那个算法,double几分钟就搞定了,用BigDecimal花了几个小时。
不知道以上的测试结果靠谱吗????
还是我对BigDecimal使用有误?
问题补充yangyi 写道是不是应该取到double的max_value, 然后分块计算,再用bigdecimal合并比较好
分块计算 这个还不是很明白 没试过? 能否再说说?
问题补充半人马 写道我其实一直很好奇什么样的货币类计算需要使用BigDecimal。大部分跟钱相关的应用,最终都会指定一个舍入精度。在我接触到的一些消费型应用,支付型应用中,这个舍入精度都是“分”而已,所以我选择使用long来做计算。
货币用long是没错,我们目前项目里也是这么用的!
我这个场景不是货币,哈哈
问题补充CN_DOTA_HOPE 写道在慢能慢到那去...
实际应用中也不可能像LZ那样 一下计算那么多次吧
哈哈 看场景
一般应用是可以忽略的
但是这个性能差距一定要心里有数
问题补充coffeesweet 写道麻烦哪位能具体给举个double转long来计算的例子???
计算完成后的结果怎么处理呢??
谢谢!
应该不是说double就能用long来表示。
而是要看场景,比如或货币运算,如果精确到分,那最多只有2位小数。这个时候对double乘于100就能用long来表示了。只是数字的单位是分。
我们目前项目里关于金钱是这样来表示,都是以分为单位,用long来表示,数据库也是。前台展示的时候,再把分转换成元。这样为的是在系统内部避免了使用double来运算。
2011年4月13日 07:55
23个答案 按时间排序 按投票排序
-
1、如果使用long,那象利息计算等需要高精度数据时怎么处理?
2、别说数据量不大哦,现在大的银行有上亿个账户不算多吧
这个怎么办?2011年4月13日 07:55
-
魔力猫咪 写道4.8/6试试,出来的结果是0.7999999999999999。出现这种滑稽的计算结果是因为浮点数在计算机中的保存方式造成的。在特定的数值处理后就会出现这种误差。
BigDecimal主要是为了解决这类问题和舍入而设计的。而且精确计算必须使用String作为参数创建才可以。
对于要求精确,并且计算不复杂的情况下,使用BigDecimal是一个正确的选择。如果没有这种精确要求,或者计算非常庞大,那么就要考虑是否使用其他方式了。
在目前的Java应用系统开发中,大多数这种计算都是不是非常复杂的货币计算,所以大家都使用BigDecimal处理。
是,前一段java解惑就是这么说的,不过上面也说了可以用long来解决2011年4月13日 07:55
-
4.8/6试试,出来的结果是0.7999999999999999。出现这种滑稽的计算结果是因为浮点数在计算机中的保存方式造成的。在特定的数值处理后就会出现这种误差。
BigDecimal主要是为了解决这类问题和舍入而设计的。而且精确计算必须使用String作为参数创建才可以。
对于要求精确,并且计算不复杂的情况下,使用BigDecimal是一个正确的选择。如果没有这种精确要求,或者计算非常庞大,那么就要考虑是否使用其他方式了。
在目前的Java应用系统开发中,大多数这种计算都是不是非常复杂的货币计算,所以大家都使用BigDecimal处理。2011年4月13日 07:55
-
凤舞凰扬 写道mtnt2008 写道魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
+1
什么样的货币计算需要用到bigdecimal?而且还有人正解,支持......
其实在绝大多数的业务应用场景下,double完全足够,bigdecimal应用场景并不广泛。(当然了,用java做数值计算是另外一回事了,但似乎很少)精度有一个是累积精度问题,有一个是计算精度的问题。
精度在应用问题上很大一个原因是大家没有用好或者说没有分析好场景,或者说没有理解精度的适应性问题。举个简单例子,假如有一个工作,是计算一个人在一段时间范围内,挖土的工作量产生的费用。假设,计费单位是小数点3位,时间是小数点2为,工作量(比如土石方)是长,宽,高(小数点各3位),那么计算费用,大家会如何算?
不太动脑筋的人肯定是 费用×时间×长×宽×高,再一看,好像精度有丢失哦,double不行,直接用bigdecimal了。仔细动一下脑筋,有必要么?
结果值很简单,也就是费用,费用2位精度,3位有效数足以。极端点也就是4,5位了。那么这个计算方式,应该是体积=长×宽×高,然后保留3位精度(其实这个数值也是需要体现的),最后再计算费用了。
再回头看看我们实际的应用场景,真的精度一定要达到小数点后7,8位么?如果是,何不考虑把单位放小(那些采用long来处理货币的就是一个极端的放小例子了)。
我们计算银行的利润分配的时候基本用bigdecimal,精确到小数后6位,呵呵,不过确实用的很少,一般大部分都还是用long,显示的时候直接转换/1002011年4月13日 07:55
-
魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
汇率问题,还有一些金融类的交易询价都是需要高精度的地方2011年4月13日 07:55
-
linliangyi2007 写道大型科学计算貌似不使用java做主要语言吧,这个根本性问题请楼主注意啊。
Ada,FORTRAN语言视乎更适合高精度计算领域。
恩 是滴! BigDecimal做金融的钱币计算就够了!2011年4月13日 07:55
-
这么多人讨论这个精度问题,为啥不去买一本计算数学,到底误差是多少,大多数计算公式都可以算出误差范围的。在这讨论半天都是一鳞半爪,以偏概全。
2011年4月13日 07:55
-
凤舞凰扬 写道mtnt2008 写道魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
+1
什么样的货币计算需要用到bigdecimal?而且还有人正解,支持......
其实在绝大多数的业务应用场景下,double完全足够,bigdecimal应用场景并不广泛。(当然了,用java做数值计算是另外一回事了,但似乎很少)精度有一个是累积精度问题,有一个是计算精度的问题。
精度在应用问题上很大一个原因是大家没有用好或者说没有分析好场景,或者说没有理解精度的适应性问题。举个简单例子,假如有一个工作,是计算一个人在一段时间范围内,挖土的工作量产生的费用。假设,计费单位是小数点3位,时间是小数点2为,工作量(比如土石方)是长,宽,高(小数点各3位),那么计算费用,大家会如何算?
不太动脑筋的人肯定是 费用×时间×长×宽×高,再一看,好像精度有丢失哦,double不行,直接用bigdecimal了。仔细动一下脑筋,有必要么?
结果值很简单,也就是费用,费用2位精度,3位有效数足以。极端点也就是4,5位了。那么这个计算方式,应该是体积=长×宽×高,然后保留3位精度(其实这个数值也是需要体现的),最后再计算费用了。
再回头看看我们实际的应用场景,真的精度一定要达到小数点后7,8位么?如果是,何不考虑把单位放小(那些采用long来处理货币的就是一个极端的放小例子了)。
我们在实际项目应用中,为了保证中间计算的精确,一般都使用BigDecimal,数据库中也都是number(32,18)这样的存储,用double计算出来的值会存在尾差2011年4月13日 07:55
-
gtssgtss 写道比如:用通项公式计算斐波那契数列,用double很快就和递推公式的结果产生差异。。。。。
用double做数值计算,在作为证据说明Bigdecimal? 呵呵,不带这样的啊~~~~2011年4月13日 07:55
-
mtnt2008 写道魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
+1
什么样的货币计算需要用到bigdecimal?而且还有人正解,支持......
其实在绝大多数的业务应用场景下,double完全足够,bigdecimal应用场景并不广泛。(当然了,用java做数值计算是另外一回事了,但似乎很少)精度有一个是累积精度问题,有一个是计算精度的问题。
精度在应用问题上很大一个原因是大家没有用好或者说没有分析好场景,或者说没有理解精度的适应性问题。举个简单例子,假如有一个工作,是计算一个人在一段时间范围内,挖土的工作量产生的费用。假设,计费单位是小数点3位,时间是小数点2为,工作量(比如土石方)是长,宽,高(小数点各3位),那么计算费用,大家会如何算?
不太动脑筋的人肯定是 费用×时间×长×宽×高,再一看,好像精度有丢失哦,double不行,直接用bigdecimal了。仔细动一下脑筋,有必要么?
结果值很简单,也就是费用,费用2位精度,3位有效数足以。极端点也就是4,5位了。那么这个计算方式,应该是体积=长×宽×高,然后保留3位精度(其实这个数值也是需要体现的),最后再计算费用了。
再回头看看我们实际的应用场景,真的精度一定要达到小数点后7,8位么?如果是,何不考虑把单位放小(那些采用long来处理货币的就是一个极端的放小例子了)。
2011年4月13日 07:55
-
大型科学计算貌似不使用java做主要语言吧,这个根本性问题请楼主注意啊。
Ada,FORTRAN语言视乎更适合高精度计算领域。2011年4月13日 07:55
-
我其实一直很好奇什么样的货币类计算需要使用BigDecimal。大部分跟钱相关的应用,最终都会指定一个舍入精度。在我接触到的一些消费型应用,支付型应用中,这个舍入精度都是“分”而已,所以我选择使用long来做计算。
2011年4月13日 07:55
-
魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
+1
2011年4月13日 07:55
-
魔力猫咪 写道BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
正解。。2011年4月13日 07:55
-
BigDecimal解决的是精度问题,主要用于货币类的需要高精度的数值计算。快速科学计算应该使用double,BigDecimal本来就不是用来进行科学计算的。
2011年4月13日 07:55
-
yangyi 写道是不是应该取到double的max_value, 然后分块计算,再用bigdecimal合并比较好
这个只能解决大数问题,解决不了精度问题啊
2011年4月13日 07:55
-
由于以前项目用一个开源公式计算类库,里面使用BigDecimal装数据,效率的确很差
采取大量数据随机计算比对过,在数据类型这块带来的差距大约也是50倍左右,对象构造成本太大2011年4月13日 07:55
相关推荐
它或类似的东西稍后可能会返回以允许高性能的BigDecimal格式 删除了form私有变量; 数字现在与形式无关 更改了构造函数对Number参数的处理:它不再将比例设置为 10。您应该始终使用String / int参数而不是Number ...
Singulink.Numerics.BigDecimal BigDecimal是功能齐全的十进制类型,支持任意大的精度值。 它具有您希望从完整实现中获得的所有数学运算符,字符串转换和解析功能(具有完整的NumberStyles支持),并且针对所有大小...
这个程序展示了如何使用GMP来计算小整数的... 凭借GMP的高性能和牛顿迭代法,这个程序的性能非常好,在我的E8500CPU,计算sqrt(2)并输出(重定向到文件),当计算精度为10万/100万位有效数字时,仅需72毫秒和不到2秒。
在这里,easy-mapper除了一些不可变类型,如primitive、wrapper、String和BigDecimal等,大部分时间都使用by-reference字段映射策略。 当你不需要复制和克隆字段时,by-reference映射是有能力的处理您的业务逻辑并...
问题 在模拟课程中剩下要实现的最重要的用例是什么? 时间应该是Double还是BigDecimal? 与> =等进行比较时,浮点数很奇怪。但是BigDecimal可能太慢了。 在长时间的仿真中,时间增量对于精度而言可能太小。 有趣的...
这些工具的主要目的都是对JDBC进行包装,使开发人员能更容易的进行数据库开发,在代码的可读性、性能问题、移植问题上,这些工具都尽量做了权衡,达到了他们认为的完美。 dbking是鉴于我们的开发经验和考虑...
Kotlin理性 Kotlin的一个不变的,无限精度的FixedBigRational和FloatingBigRational (比率,分数)类。... 通常,此代码更喜欢表现力而不是性能。 第二个目标是为Kotlin标准库,Java的BigDecimal和BigInteg
表达式评估器(演示) 提供excel或Google电子表格(如公式/... assertEquals(BigDecimal.valueOf(11), evalExpr.eval()); //mathematical functions ExpressionsEvaluator evalExpr = ExpressionsFactory
可能的转换(到和从)是: Stringint long BigIntegerdouble BigDecimal此外,可以直接分配有理值。班级该软件包包含: 用于存储有理数的寄存器类。 它将始终保存存储在其中的确切有理数。 它不会溢出。 它是可变的...
但是,如果您想使用此方法的较低级别主要是为了提高性能,请在方法名称前添加下划线。 例如: emultiple -> _emultiple -> __emultiple -> ____emultiple -> ___emultiple 最高 -1 -2 最低 有时像 emultiple 它可以...
有很大的性能改进和一些错误修复。 功能列表 Java 和 Go 之间的 Hessian 类型映射 跨语言消息定义要小心,应避免以下情况: 定义只存在于特殊语言中的对象 使用各种 java 异常(使用错误代码/消息代替) 所以我们...
学生提问:为什么有栈内存和堆内存之分? 93 4.6.2 基本类型数组的初始化 95 4.6.3 引用类型数组的初始化 96 4.6.4 没有多维数组 99 学生提问:我是否可以让图4.13中灰色覆盖的数组元素再次指向另一个数组?这样...