js实现小数点四舍五入

其实这个问题,在之前的面试中被提问到了,由于笔者平时都是用原生的toFixed()的方法来保留小数点,所以当时并没有回答出来这个问题,呜呜呜.
现在突然想起了这个问题,就研究一下吧。

最简单的实现方法

可以使用Math对象的一些方法来实现,这个比较简单,主要用到了Math.round和一些简单的乘除法运算。例子
思路:
1. 先把数值转成只有一位小数点的数值
2. 利用Math.round方法四舍五入(关键)
3. 最后通过乘除法运算等到想要的小数点位数


function toFixed(num,decimal){
if(isNaN(num)){
return 0;
}
num = num-0;
var p1 = Math.pow(10, decimal + 1);
var p2 = Math.pow(10, decimal);
console.log(num * p1 / 10);
console.log(Math.round(num * p1 / 10));
return (Math.round(num * p1 / 10) / p2).toFixed(decimal); //思考一下,为什么要除10?
}

运行一下上面的代码,其实有隐藏的bug...


toFixed(2.555,2) //2.56 toFixed(4100.065,2) //4100.06 ??? console.log(4100065/10) //410006.49999999994 这就是bug的答案 0.1+0.2=? //0.30000000000000004

所谓的隐藏bug,就是js编程语言的小数点精度问题,所以上面那个除于10 只是在一定的范围内有效,过了这个范围,还是会出现精度问题...

用字符串处理

既然小数点进行运算会出现问题,那我们换一种思路,用字符串来处理。例子
思路:
1. 把数字转成字符串,然后把小数点移动到倒数第二位。(模拟只有一位小数点)
2. 还是用到Math.round来四舍五入
3. 重复第一个步骤,不过把小数点移动到(你要保留多少位小数点)


function toFixed(num,decimal){
if(isNaN(num)){
return 0;
}
var strnum = num+'';
var arr = strnum.split('.');
if(arr.length<2){
return num.toFixed(decimal);
} strnum = arr.join(''); var strnum2 = strnum.slice(0,-1)+'.'+strnum.slice(-1); var result = Math.round(strnum2-0)+''; if(arr[1].length==decimal){
result+='0'; //如果小数点的个数刚好等于要保留的小数点个数,要补0
} return result.slice(0,-decimal)+'.'+result.slice(-decimal)
}

2020-04 更新

上面的字符串处理不够好,下面补充个新的逻辑方式:

  1. 把数字转成字符,并记录.小数点的位置;如果没有小数点,则直接在后面补0;
  2. 通过小数点的位置,计算出原数字有多少位小数(oldPointNum);把小数点去掉并且把字符串转成数组;
  3. 通过比较oldPointNum和n(要保留的位数);如果oldPointNum<n,直接补0;否则下一步
  4. 比较数组倒数(i =oldPointNum-n)的数字是否>=5;是则进一位;i++;循环该步骤(核心),用这一步来模拟四舍五入。

const toFixed = (number, n) => {
let numberStr = number + "";
let reg = /^(-|\+)?(\d+(\.\d*)?|\.\d+)$/i;
if(!reg.test(numberStr)) {
console.error('输入的数字格式不对');
return;
}
let sign = numberStr.charAt(0) === '-' ? (numberStr=numberStr.slice(1),-1):1; // 判断是否是负数
let pointIndex = numberStr.indexOf("."); // 记录小数点的位置
if (pointIndex > -1) {
numberStr = numberStr.replace(".", "");
} else { // 没有小数点直接添加补0;
numberStr += ".";
numberStr+=new Array(n).join('0');
return numberStr;
}
let numberArray = numberStr.split(""); //转成数组
let len = numberArray.length;
let oldPointNum = len - pointIndex; // 获取原数据有多少位小数
if (oldPointNum < n) { // 要保留的小数点比原来的要大,直接补0
while (n - oldPointNum > 0) {
numberArray.push(0);
n--;
}
} else if (oldPointNum > n) { // 模拟四舍五入 let i = oldPointNum - n; // 从倒数第i个数字开始比较
let more = numberArray[len - i] >= 5 ? true : false;
while (more) {
i++;
more = +numberArray[len - i] + 1 === 10 ? true : false; // 进位后判断是否等于10,是则继续进位
numberArray[len - i] = more&&i!==(len+1) ? 0 : +numberArray[len - i] + 1; // 其他位置的数字进位直接变成0,第一位的例外
console.log(i, len);
}
numberArray.length = len- (oldPointNum-n); // 截取多余的小数
}
numberArray.splice(pointIndex, 0, ".");
return sign===-1?'-'+numberArray.join(""):numberArray.join("");
};

ps :上面的代码有点臃肿,其实可以通过正则来简化,以后有空修改。

js实现小数点四舍五入的更多相关文章

  1. JS保留小数点(四舍五入、四舍六入)实例

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  2. js 让小数四舍五入保留两位小数的函数是?

    js 让小数四舍五入保留两位小数的函数是? 例子:data.relations[i].data[j].toFixed(2) toFixed(2)这个函数就是保留两位小数的作用

  3. java四舍五入BigDecimal和js保留小数点两位

    java四舍五入BigDecimal保留两位小数的实现方法: // 四舍五入保留两位小数System.out.println("四舍五入取整:(3.856)="      + ne ...

  4. js判断小数点几位

    js如何判断小数点后有几位 <script> var n=3.143423423;alert(n.toString().split(".")[1].length); & ...

  5. js保留小数点后面几位的方法

    原文地址: http://www.jb51.net/article/45884.htm 四舍五入以下处理结果会四舍五入: ? 1 2 var num =2.446242342; num = num.t ...

  6. js 获取小数点位数方法及 字符串与数字之间相互转换方法

    1.获取小数点位数方法 a. 使用 js 中 subsrting,indexOf,parseFloat三个函数,代码如下: var s = "22.127456" ;//s 为 字 ...

  7. js 小数[非]四舍五入

    1.四舍五入 (2.678).toFixed(2) // 2.68 2.不需要四舍五入 (parseInt(2.678*100)/100.0).toFixed(2) // 2.67 3.字节单位转换 ...

  8. js数字格式化-四舍五入精简版

    搜索网上的,数字格式化过余复杂,自己想了个简单方法,欢迎吐槽. 简化说明: '123333' => 12.3万 parseInt('123333') 字符串转整型 parseInt('12333 ...

  9. js 加减乘除以及四舍五入 新写法

    1 四舍五入 eg: (1.23).round() = 1.2 (1.2456).round(3) = 1.246 Number.prototype.round = function (count) ...

随机推荐

  1. 部署 LAMP (CentOS 7.2)

    摘自:https://help.aliyun.com/document_detail/50774.html 简介 LAMP指Linux+Apache+Mysql/MariaDB+Perl/PHP/Py ...

  2. node.js对象数据类型

    在这里复习下前端JS的数据类型:前端JS中的数据类型: 1.基本/原生/值类型 string.number.boolean.null.undefined 2.引用/对象类型    ES对象类型:Str ...

  3. KDD2016,Accepted Papers

    RESEARCH TRACK PAPERS - ORAL Title & Authors NetCycle: Collective Evolution Inference in Heterog ...

  4. cocos2dX 之CCAnimation/CCAnimate

    我们今天来学习cocos2dX里面的动画的制作, 有人说, 不是前面CCAction已经学过了吗? 怎么还要学, CCAction是动作, 而我们今天要学的是动画哦, 是让一个东西动起来哦, 好了进入 ...

  5. Directx11教程41 纹理映射(11)

    原文:Directx11教程41 纹理映射(11)     1.第一副图我们采用各性异性的滤波方式,并设置最大各性异性值为8.     samplerDesc.Filter =  D3D11_FILT ...

  6. Directx11教程(33) 纹理映射(3)

    原文:Directx11教程(33) 纹理映射(3)       现在我们在myTutorialD3D11_5的基础上,来逐步编码实现纹理映射,之所以在myTutorialD3D11_5基础上改写,是 ...

  7. phpexcel使用说明2

      转自:http://serisboy.iteye.com/blog/1928139 首先到phpexcel官网上下载最新的phpexcel类,下周解压缩一个classes文件夹,里面包含了PHPE ...

  8. linux中$@,$*,$0,$$,$?参数的含义

    $# 是传给脚本的参数个数 $ 是脚本本身的名字 $ 是传递给该shell脚本的第一个参数 $ 是传递给该shell脚本的第二个参数 $@ 是传给脚本的所有参数的列表 $* 是以一个单字符串显示所有向 ...

  9. Calendar类实现当前日期的日历

    package com.sxt.home1; import java.text.DateFormat; import java.text.ParseException; import java.tex ...

  10. Python学习(四)cPickle的用法

    python中有两个类似的:pickle与cPickle:两者的关系:“cPickle – A faster pickle” pickle模块中的两个主要函数是dump()和load().dump() ...