js处理浮点数计算误差
众所周知,浮点计算会产生舍入误差的问题,比如,0.1+0.2,结果应该是0.3,但是计算的结果并不是如此,而是0.30000000000000004,这是使用基于IEEE754数值的浮点计算的通病,js并非独此一家,今天我们就来看看js怎么解决这个误差的。
以下是针对加减乘除的解决方法:
加法:
function accAdd(arg1, arg2) {
var r1, r2, m, c;
try {
r1 = arg1.toString().split(".")[1].length;
}
catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
}
catch (e) {
r2 = 0;
}
c = Math.abs(r1 - r2); //位数差的绝对值
m = Math.pow(10, Math.max(r1, r2)); //较大数的幂
if (c > 0) { //位数相差
var cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", "")); //转化成数字
arg2 = Number(arg2.toString().replace(".", "")) * cm;
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else { //位数相等
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 + arg2) / m;
}
减法:
function accSub(arg1, arg2) {
var r1, r2, m, n;
try {
r1 = arg1.toString().split(".")[1].length;
}
catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
}
catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
n = (r1 >= r2) ? r1 : r2; //取位数大的
// n = Math.max(r1, r2);
return ((arg1 * m - arg2 * m) / m).toFixed(n);
}
乘法:
function accMul(arg1, arg2) { //去小数点扩大后,再除以相应倍数
var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
try {
m += s1.split(".")[1].length;
}
catch (e) {
}
try {
m += s2.split(".")[1].length;
}
catch (e) {
}
return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
}
除法:
function accDiv(arg1, arg2) { //去小数点,扩大倍数,再乘以相应倍数
var t1 = 0, t2 = 0, r1, r2;
try {
t1 = arg1.toString().split(".")[1].length;
}
catch (e) {
}
try {
t2 = arg2.toString().split(".")[1].length;
}
catch (e) {
}
with (Math) {
r1 = Number(arg1.toString().replace(".", ""));
r2 = Number(arg2.toString().replace(".", ""));
return (r1 / r2) * pow(10, t2 - t1);
}
}
用以上4个方法进行计算的话,就能够规避浮点数计算误差问题了,他们的原理大多是,通过去掉小数点,将浮点数变为整数,再进行计算。比如加法:
var r1, r2, m, c; //r1为arg1的小数位数,r2为arg2的小数位数,m为arg1和arg2较大数的幂,c是位数差
try {
r1 = arg1.toString().split(".")[1].length; //计算arg1的位数
}
catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length; //计算arg2的位数
}
catch (e) {
r2 = 0;
}
c = Math.abs(r1 - r2); //位数差的绝对值
m = Math.pow(10, Math.max(r1, r2)); //较大数的幂
if (c > 0) { //位数相差
var cm = Math.pow(10, c); //位数差的幂
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", "")); //转化成数字
arg2 = Number(arg2.toString().replace(".", "")) * cm; //较小数乘以位数差的幂
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else { //位数相等
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 + arg2) / m; //将扩大了的数相加,再除以较大数的幂,将结果还原
}
从上面可以看出,为了的到两个小数扩大后的整数,使用的是现将他们转换成字符串,再用空去替换点号,这个方法得到的数字就是扩大后的数字,而网上流行另一种写法,就是先乘以一个倍数,将其变为整数,再相加,再除以倍数的方法,这个方法乍一看,是行的通的,但是经过测试,此方法也会存在bug。
function add(a, b) {
var c, d, e, h;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
e = Math.pow(10, Math.max(c, d));
return (a * e + b * e) / e;
//h = Math.max(c, d);
//return ((mul(a, e) + mul(b, e)) / e).toFixed(h);
}
此方法e指的是两个数中较大数的幂,错就错在,ae,和be在计算的时候会出现计算误差,由于wiki不能上传图片,就不展示了,综上所述,我推荐第一种的解决方案。当然第二种也是有不就措施的,就是将我上面代码的两行注释放开,我们运用了toFixed将误差给截取,从而得到正确的结果。
这里,我在提供一个测试的方法:
function test() {
var a = (Math.random() * 100).toFixed(2) - 0;
var b = (Math.random() * 1000).toFixed(2) - 0;
var result = add(a, b);
if ((result + '').length > 10) {
console.error('被加数:' + a, '加数:' + b, '结果:' + result);
return;
}
setTimeout(function () {
test();
}, 10);
}
js处理浮点数计算误差的更多相关文章
- 实现js浮点数加、减、乘、除的精确计算(网上很多文章里的方法是不能解决所有js浮点数计算误差的)
最近做项目,要用到js的加.减.乘.除的计算,发现js浮点数计算会有一些误差. 网上有很多文章都有js浮点数计算误差的解决方法,说能解决这个问题,But…….比如一个加法函数,如下: function ...
- js,java,浮点数运算错误及应对方法
js,java浮点数运算错误及应对方法 一,浮点数为什么会有运算错误 IEEE 754 标准规定了计算机程序设计环境中的二进制和十进制的浮点数自述的交换.算术格式以及方法. 现有存储介质都是2进制.2 ...
- js运算浮点数
在js中做小数:9.3+0.3会发现,得到的结果并不是9.6,而是9.600000000000001.这是为什么? Javascript采用了IEEE-745浮点数表示法,这是一种二进制表示法,可以精 ...
- JS/PHP 浮点数精确运算
php浮点数精确运算 bc是Binary Calculator的缩写.bc*函数的参数都是操作数加上一个可选的 [int scale],比如string bcadd(string $left_oper ...
- js 计算浮点数
JS的浮点计算 最近遇到了数值计算的时候,计算结果出现了类似于199.9999999999999999999的情况,但是被用来计算的两个数值都只是两位数. 就像这样 --------> ...
- js如何计算浮点数
js中浮点型是如何运算的呢? 例如:var a=0.69; 我想得到6.9 直接这样写 var c=a*10; alert(c); 得到结果是:6.8999999999999995 到网上一搜,有 ...
- Js 与浮点数
同步发表在我的博客:jmingzi 当你学习一个知识点没有方向时,可以尝试以解决问题的角度来理解它. 例如这个知识点我们可以从以下问题开始: 你看的到 1 真的是整数 1 吗? 为什么0.1 + 0. ...
- js浮点数精度丢失问题及如何解决js中浮点数计算不精准
js中进行数字计算时候,会出现精度误差的问题.先来看一个实例: console.log(0.1+0.2===0.3);//false console.log(0.1+0.1===0.2);//true ...
- js处理浮点数一点思考
作为一名web开发人员,如果我们做到了涉及到费用加加减减的需求 难免会遇到浮点数的计算,就会遇到浮点数精度误差的问题 假设场景: 1.接口给你的金额单位是分,页面需要展示的金额单位为元. 最后落档金额 ...
随机推荐
- JS判断单、多张图片加载完成
转:http://www.daqianduan.com/6419.html 试想,如果模板中有图片,此时如何判断图片是否加载完成? 在此之前来了解一下jquery的ready与window.onloa ...
- 记Tea使用中遇到的问题及解决过程
学习Markdown时,在小众软件看到一个叫Tea的软件.UI设计是简约风格:"所见即所得"的Markdown:支持插件等原因让我选择去尝试这杯"茶". 最近一 ...
- SAP 日志管理
现在项目上自开发的dialog程序越来越多,有很多敏感数据需要像SAP标准的业务一样,能看到所有的修改日志,要想实现日志的功能,有以下几个办法: 办法一.建一个日志表,在原有表的基础上,加上日期和时间 ...
- 【前端_js】Chrome禁止缓存的方法
在前端开发中,浏览器缓存使得我们改了代码后页面不变,得经常手动清理缓存. 1.按如下操作即可禁用浏览器缓存, 这种方法基本能够做到完全禁止缓存,然而缺点是必须要将开发模式一直打开,占用屏幕空间.而且, ...
- JZOJ 3385. 【NOIP2013模拟】黑魔法师之门
3385. [NOIP2013模拟]黑魔法师之门 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limi ...
- HDU1505-City Game(记忆化搜索)
City Game http://acm.hdu.edu.cn/showproblem.php?pid=1505 Problem Description Bob is a strategy game ...
- [BZOJ1208]宠物收养所(Splay)
Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特 ...
- 如何使用DroidPlugin——DroidPlugin初体验
最近研究了下360的黑科技--DroidPlugin 刚开始不知道怎么用,于是看了这篇博客:http://www.jianshu.com/p/f1217cce93ef 算是引导了我,于是开始自己写写 ...
- 80C51单片机指令的取指、执行时序
80C51单片机指令的取指.执行时序 现按4类指令介绍CPU时序.因为CPU工作的过程就是取指令与执行指令的过程,所以CPU必须先取出指令,然后才能执行指令. 1.双字节单周期指令 由于双字节单周期指 ...
- 2612. [FHZOI 2017]被窃的项链
2612. [FHZOI 2017]被窃的项链 ★★★ 输入文件:stolen_necklace.in 输出文件:stolen_necklace.out 简单对比时间限制:1 s 内存 ...