一 如何做到精确的round运算?
今天在做一个demo的时候,因为生成随机数的关系,需要round一下数值,结果遇到了计算精度的问题:有些round结果是类似32.000004的值。以前在项目里曾经fix过类似的bug,所以今天花了一点功夫来研究如何做到精确的round,特别是在EMCA Script下。
借股沟之能,发现基本上就两种解决思路:
- 使用乘除法
这种做法基本思路就是如下代码:
function roundNumber(num, precision) {
var base = Math.pow(10, precision);
return Math.round(num * base ) / base ;
}
这种做法的优点是非常简洁;然而缺点也是显而易见的:不是100%准确。比如下面下面这种运算:
alert(3.27691*100/100); //display 3.2769099999999995
改进?
也许有人会想到这种不精确是由于除法,设计一个不用除法的算法也许就行了?的确,除法很多时候是精度问题的根源,但只是根源之一。比如下面这个例子:
alert(4.935*100); // still not inaccurate
看起来涉及到字符运算的,统统都是不可靠的。因此很多人想出了下面这个做法:
2. 字符串运算
这种做法基本思路就是将数值先转换到字符串,然后通过小数点拆分数字做比较。这种做法实现比较复杂,比如下面两个link:
这种做法,貌似是解决精度问题了。其实它也不能解决,比如:
alert(4.72352337135978971111); // display 4.723523371359789
如果你正好要round到15位(就是7897111),字符串运算也帮不了你,因为后面的711111统统被“自然”过滤了。
3. Number.toFixed()
这种方法比较好,特别是你需要显示数值的时候。不如还是有不少小缺点:
1. 需要人工在每个需要转换的地方写上parseInt(num.toFixed(3)).
2. 仍然不能避免如下的错误:
var num = 4.72352337135978971111;
alert(num.toFixed(15));
二 问题在哪里?
到这里,各位看官应该明白,在native的primitive number下似乎是不可能做到100%的round的。这可以推广到几乎所有运算。问题根源在哪里?其实很简单,就是数值在计算机中的表示形式。EMCA Script的number,在内部是用IEEE754的浮点数来表示的。这种格式无法避免精度问题,甚至连literal value都不能保证精度,更别提运算结果了。
三 出路?
其实精度问题也没必要杞人忧天,一般的数字,即使用第一种方法,你也不太会遇到精度问题。我之所以遇到,是因为用了很多随机数(通常小数点后都比较长)。不过你的需求里如果可能涉及到比较复杂的数字计算,就要好好考虑一下精度问题了。
- 优化计算过程。比如a/2+b/2+c/2,应该改成(a+b+c)/2。
- 明确精度需求。比如网上商城,一般也就是精确到小数点后2位,一般不太会遇到这种问题。但是小数点比较长的,就要特别注意,要澄清误差允许范围。
- 避免在前台计算。在设计的时候,可以考虑在后台计算。Java/C#之类的都内置了BigNumber,可以很好解决精度问题。
- 使用/实现前台的BigNumber。这个是极其费力的做法了,一方面你要寻找或者自己实现BigNumber,另外所有用到的数值,都必须用BigNumber封装。
分享到:
相关推荐
在本压缩包中,"商业编程-源码-高精度运算函数库(大整数运算)位运算和指针的运用.zip" 提供了一个专门用于高精度计算的函数库,它巧妙地利用了位运算和指针技术来优化性能。下面将详细介绍这两个关键概念以及它们...
在计算机科学中,高精度运算...通过学习和分析这个程序,你可以深入了解高精度运算的原理,并提升C++编程技巧。对于初次接触这个领域的学生,这是一个很好的实践项目,可以帮助他们巩固基础知识并提高问题解决能力。
1. 不同 Q 格式的转换设有定点数 Fixed1=Float1*2^Q1,如果把它用为 Q2 这个不同精度/表示范围的定点数来表示,则有 Fixed2=Float1*2^Q2。所以不同的 Q 格式直接的转换为:Fixed2=Fixed1*2^Q2/2^Q1=Fixed1*2^(Q2-Q1)...
位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用方法---位运算大师级使用...
Educoder题目:数据结构-栈基本运算的实现及其应用答案解析.md
5--[乘法运算].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码5--[乘法运算].zip源码scratch2.0 3.0编程项目源文件源码案例素材源代码5--[乘法运算].zip源码scratch2.0 3.0编程项目源文件源码案例素材源...
285-用右移运算流水点亮P1口8位LED(51单片机C语言实例Proteus仿真和代码)285-用右移运算流水点亮P1口8位LED(51单片机C语言实例Proteus仿真和代码)285-用右移运算流水点亮P1口8位LED(51单片机C语言实例Proteus仿真和...
本报告围绕基本运算器的构成与功能,详细分析了运算器的工作原理,以及如何通过实验来观察和理解其内部运作。 计算机组成原理不仅涵盖了计算机硬件系统的设计与结构,还包括对计算机如何执行指令、处理数据的基本...
279-用自增运算控制P0口8位LED流水花样(51单片机C语言实例Proteus仿真和代码)279-用自增运算控制P0口8位LED流水花样(51单片机C语言实例Proteus仿真和代码)279-用自增运算控制P0口8位LED流水花样(51单片机C语言实例...
计算机组成原理实验-数字逻辑---运算器设计(HUST)-11个题
4-EPI综合能力题库----数学运算、应用题题精选400道详解.pdf
该算法基于两个大素数的乘积,对于一般用户来说,这种大数的运算难以直观理解,因此需要专门的大数运算库来处理。在C语言中,大数运算库扮演着至关重要的角色,它们提供了高效且精确的大整数计算功能。 “BigNum ...
在当前的软件开发中,数学运算的精度问题是一个非常重要的考量点,特别是在需要高精度计算的场景下,如金融、科研等领域。传统的基本数据类型(如float和double)由于其自身的表示限制,在处理需要极高精度的计算时...
文档通过这些详细的程序段,展示了如何按照双精度到单精度的转换规则来操作和处理数据。这些操作通常涉及到位操作、逻辑运算以及条件判断等基础编程技能。 总结来说,S7-200 SMART PLC中的双精度浮点型数据转换为单...
### DecimalFormat精度解决与商业运算精度问题 在进行财务计算或者商业运算时,精度问题往往成为影响最终结果准确性的关键因素之一。特别是在Java这样的语言环境中,由于其内部采用二进制浮点数表示小数的方式,这...
本示例中的“C#计算器”项目专注于实现连续运算以及加减乘除的混合运算功能。这些功能是计算器的基本需求,允许用户进行一系列数学操作而不必在每次运算后获取结果。以下是关于这个项目的一些关键知识点和实现细节:...
实现3-9圈乘运算问题.cpp
小学六年级奥数--简便运算专题.doc
数据结构----稀疏矩阵运算器课程设计.doc