js加减乘除--科学计数法-解决精度丢失
JS 解决 -- 科学 丢失 精度 加减乘除 计数法
2023-09-11 14:18:36 时间
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /** * @desc 解决浮动运算问题,避免小数点后产生多位数和计算精度损失。 * 问题示例:2.3 + 2.4 = 4.699999999999999,1.0 - 0.9 = 0.09999999999999998 */ /** * 把错误的数据转正 * strip(0.09999999999999998)=0.1 */ function strip(num, precision) { if (precision === void 0) { precision = 12; } return +parseFloat(num.toPrecision(precision)); } /** * Return digits length of a number * @param {*number} num Input number */ function digitLength(num) { // Get digit length of e var eSplit = num.toString().split(/[eE]/); var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0)); return len > 0 ? len : 0; } /** * 把小数转成整数,支持科学计数法。如果是小数则放大成整数 * @param {*number} num 输入数 */ function float2Fixed(num) { if (num.toString().indexOf('e') === -1) { return Number(num.toString().replace('.', '')); } var dLen = digitLength(num); return dLen > 0 ? strip(num * Math.pow(10, dLen)) : num; } /** * 检测数字是否越界,如果越界给出提示 * @param {*number} num 输入数 */ function checkBoundary(num) { if (_boundaryCheckingState) { if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) { // console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate"); } } } /** * 精确乘法 */ function times(num1, num2) { var others = []; for (var _i = 2; _i < arguments.length; _i++) { others[_i - 2] = arguments[_i]; } if (others.length > 0) { return times.apply(void 0, [times(num1, num2), others[0]].concat(others.slice(1))); } var num1Changed = float2Fixed(num1); var num2Changed = float2Fixed(num2); var baseNum = digitLength(num1) + digitLength(num2); var leftValue = num1Changed * num2Changed; checkBoundary(leftValue); return leftValue / Math.pow(10, baseNum); } /** * 精确加法 */ function plus(num1, num2) { var others = []; for (var _i = 2; _i < arguments.length; _i++) { others[_i - 2] = arguments[_i]; } if (others.length > 0) { return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1))); } var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2))); return (times(num1, baseNum) + times(num2, baseNum)) / baseNum; } /** * 精确减法 */ function minus(num1, num2) { var others = []; for (var _i = 2; _i < arguments.length; _i++) { others[_i - 2] = arguments[_i]; } if (others.length > 0) { return minus.apply(void 0, [minus(num1, num2), others[0]].concat(others.slice(1))); } var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2))); return (times(num1, baseNum) - times(num2, baseNum)) / baseNum; } /** * 精确除法 */ function divide(num1, num2) { var others = []; for (var _i = 2; _i < arguments.length; _i++) { others[_i - 2] = arguments[_i]; } if (others.length > 0) { return divide.apply(void 0, [divide(num1, num2), others[0]].concat(others.slice(1))); } var num1Changed = float2Fixed(num1); var num2Changed = float2Fixed(num2); checkBoundary(num1Changed); checkBoundary(num2Changed); // fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正 return times((num1Changed / num2Changed), strip(Math.pow(10, digitLength(num2) - digitLength(num1)))); } /** * 四舍五入 */ function round(num, ratio) { var base = Math.pow(10, ratio); return divide(Math.round(times(num, base)), base); } var _boundaryCheckingState = true; /** * 是否进行边界检查,默认开启 * @param flag 标记开关,true 为开启,false 为关闭,默认为 true */ function enableBoundaryChecking(flag) { if (flag === void 0) { flag = true; } _boundaryCheckingState = flag; } //定义一个加法函数(小数相加) function floatCalc(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; return ((arg1 * m - arg2 * m) / m).toFixed(n); } var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking, floatCalc: floatCalc }; exports.strip = strip; exports.plus = plus; exports.minus = minus; exports.times = times; exports.divide = divide; exports.round = round; exports.digitLength = digitLength; exports.float2Fixed = float2Fixed; exports.enableBoundaryChecking = enableBoundaryChecking; exports.floatCalc = floatCalc; exports['default'] = index;
相关文章
- jQuery验证控件jquery.validate.js使用说明+中文API
- js 后台异步执行
- [转] JS中的call()方法和apply()方法用法总结
- JS实现点击网页判断是否安装App
- 优化 html 标签 为何能用HTML/CSS解决的问题就不要使用JS?
- js,jq滚动监听,切换等常用JS代码
- 【Vue/Js】如何解决谷歌浏览器(chrome)扩展插件安装后,再打开自动消失问题(两种解决方案)
- 【JS】js创建Object对象和构造函数的多种方法(综合示例)
- 【Vue/js】Js中执行变量中的命令语句,也就是所谓的宏替换(很实用的例子)
- 如何在Vue3+js项目(脚手架)中使用(下载安装及运行)element-plus以及解决使用过程中遇到的问题
- js 验证 输入值 全是数字
- Vue - 下载后端接口返回的文件流(js-file-download)
- Vue - 在纯 JS 文件中调用自定义组件 / 类似 ElementUI 弹框组件 Message、Modal(在纯 js 文件中通过 import 方式引入并调用弹框模态框组件显示出来,)
- JS同名方法,
- 小程序开发 绑定自定义数据data- 及JS获取
- 《Node.js入门经典》一导读
- Jquery方法load之后导致js失效解决方法
- ext.js学习
- JS里==和===区别
- javascript js date ios手机浏览器出现 NAN的问题解决方法
- JS: javascript 点击事件执行两次js问题 ,解决jquery绑定click事件出现点击一次执行两次问题
- [js高手之路] html5 canvas教程 - 绘制七巧板
- [js高手之路] es6系列教程 - 函数的默认参数详解
- JS IOS/iPhone的Safari浏览器不兼容Javascript中的Date()问题的解决方法
- JS魔法堂:关于元素位置和鼠标位置的属性
- JS框架设计之对象扩展一种子模块
- js解决浏览器兼容性问题的原理
- js判断当前页面是否有父页面,页面部分跳转解决办法,子页面跳转父页面不跳转解决 (原)