数值金额计算js封装包含加减乘除四个方法,能确保浮点数运算不丢失精度

项目场景:

商城类项目中大多需要金额计算,我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差),其根本原因是二进制和实现位数限制有些数无法有限表示

以下是十进制小数对应的二进制表示:
0.1 >> 0.0001 1001 1001 1001…(1001无限循环)
0.2 >> 0.0011 0011 0011 0011…(0011无限循环)
计算机里每种数据类型的存储是一个有限宽度,比如 JavaScript 使用 64 位存储数字类型,因此超出的会舍去。舍去的部分就是精度丢失的部分。
如果直接加减乘除:
0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004)
0.2 + 0.4 == 0.6000000000000001 (多了 0.0000000000001)
19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002)
所以要精确计算需要进行处理,,实现加减乘除运算,确保不丢失精度

解决方案:

/*** 判断是否为一个整数* @param {object} obj 字符串* @return {boolean} true/false*/
export function isInteger(obj) {return Math.floor(obj) === obj;
}/*** 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100* @param {object} floatNum 小数* @return {object} {times:100, num: 314}*/
export function toInteger(floatNum) {var ret = { times: 1, num: 0 }var isNegative = floatNum < 0if (isInteger(floatNum)) {ret.num = floatNumreturn ret}var strfi = floatNum + ''var dotPos = strfi.indexOf('.')var len = strfi.substr(dotPos + 1).lengthvar times = Math.pow(10, len)var intNum = parseInt(Math.abs(floatNum) * times + 0.5, 10)ret.times = timesif (isNegative) {intNum = -intNum}ret.num = intNumreturn ret
}/*** 浮点型数字运算精度丢失修复* @param {object} num 小数* @param {number} s 小数位数* @return {object} s位小数*/
export function toFixed(num, s) {var times = Math.pow(10, s);var des = num * times + 0.5;des = (parseInt(des, 10) / times) + '';var pos_decimal = des.indexOf('.');if (pos_decimal > 0) {while (des.length <= pos_decimal + s) {des += '0';}}return des;
}/*** 浮点型数字运算精度丢失修复* 核心方法,实现加减乘除运算,确保不丢失精度* 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)* @param a {number} 运算数1* @param b {number} 运算数2* @param dig {number} 精度,保留的小数点数,比如 2, 即保留为两位小数* @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)* @return {object} dig位小数*/
function operation(a, b, dig, op) {var o1 = toInteger(a)var o2 = toInteger(b)var n1 = o1.numvar n2 = o2.numvar t1 = o1.timesvar t2 = o2.timesvar max = t1 > t2 ? t1 : t2var result = nullswitch (op) {case 'add':if (t1 === t2) { // 两个小数位数相同result = n1 + n2} else if (t1 > t2) { // o1 小数位 大于 o2result = n1 + n2 * (t1 / t2)} else { // o1 小数位 小于 o2result = n1 * (t2 / t1) + n2}return toFixed(result / max, dig)case 'subtract':if (t1 === t2) {result = n1 - n2} else if (t1 > t2) {result = n1 - n2 * (t1 / t2)} else {result = n1 * (t2 / t1) - n2}return toFixed(result / max, dig)case 'multiply':result = (n1 * n2) / (t1 * t2)return toFixed(result, dig)case 'divide':if (n2 === 0)result = 0elseresult = (n1 / n2) * (t2 / t1)return toFixed(result, dig)}
}/*** 加法* @param a {number} 运算数1* @param b {number} 运算数2* @return {object} s位小数*/
export function add(a, b, s) {return operation(a, b, (s | 2), 'add')
}/*** 减法* @param a {number} 运算数1* @param b {number} 运算数2* @return {object} s位小数*/
export function subtract(a, b, s) {return operation(a, b, (s | 2), 'subtract')
}/*** 乘法* @param a {number} 运算数1* @param b {number} 运算数2* @return {object} s位小数*/
export function multiply(a, b, s) {return operation(a, b, (s | 2), 'multiply')
}/*** 除法* @param a {number} 运算数1* @param b {number} 运算数2* @return {object} s位小数*/
export function divide(a, b, s) {return operation(a, b, (s | 2), 'divide')
}

上面的为math.js文件,封装到这里面然后引用
vue中引用使用方法:
main.js:
import * as math from ‘./utils/math’//引入js
Vue.prototype.math = math

使用:
this.math.add(this.numberCases, this.Number)

标签中引用:

{{math.multiply(item.Discount, item.Num)}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/787351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python笔记(8)Tuple(元组)

目录 创建元组 元组取数 不支持修改和删除元素 元组运算符 元组内置函数 创建元组 Tuple 元组的元素不能修改&#xff0c;元组使用小括号&#xff08;&#xff09;&#xff0c;创建元组在括号里添加元素用逗号隔开即可。 创建空元组 tup1() 创建一个元素的元组&#xff…

Golang 开发实战day06 - Boolean Conditional

Golang 教程06 - Boolean & Conditional 1. Boolean & Conditional 1.1 什么是布尔类型&#xff1f; 想象一下&#xff0c;你正在玩一个古老的游戏&#xff0c;只有两个选项&#xff1a;是或否。在 Golang 中&#xff0c;这就是布尔类型&#xff0c;用 bool 关键字表…

【Linux实验室】DNS域名解析服务——超详细实验操作!

DNS域名解析 DNS域名解析服务——超详细实验操作&#xff01;&#xff01;&#xff01;序言DNS 基本概述分布式、层次数据库DNS 层次结构DNS 查询步骤DNS 查询类型DNS服务器类型DNS 缓存反向 DNS 查询如何检查 DNS 记录是否生效 Bind解析服务Bind简介bind的服务类型 DNS域名解析…

深入解析实时数仓Doris:Rollup上卷表与查询

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 一、基本概念二、Aggregate 和 Unique 模型中的 ROLLUP三、Duplicate 模型中的 ROLLUP四、ROLLUP 调整前缀索引五、ROLLUP使…

【深耕 Python】Data Science with Python 数据科学(7)书352页练习题

写在前面 关于数据科学环境的建立&#xff0c;可以参考我的博客&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;1&#xff09;环境搭建 往期数据科学博文&#xff1a; 【深耕 Python】Data Science with Python 数据科学&#xff08;2&#xf…

Android 使用LeakCanary检测内存泄漏,分析原因

内存泄漏是指无用对象&#xff08;不再使用的对象&#xff09;持续占有内存或无用对象的内存得不到及时释放&#xff0c;从而造成内存空间的浪费称为内存泄漏。 平时我们在使用app时&#xff0c;少量的内存泄漏我们是发现不了的&#xff0c;但是当内存泄漏达到一定数量时&…

每日面经分享(pytest测试案例,接口断言,多并发断言)

pytest对用户登录接口进行自动化脚本设计 a. 创建一个名为"test_login.py"的测试文件&#xff0c;编写以下测试脚本 import pytest import requests# 测试用例1&#xff1a;验证登录成功的情况 # 第一个测试用例验证登录成功的情况&#xff0c;发送有效的用户名和密…

统计数码出现的个数

题目描述 输入一个数n&#xff0c;求出 [1, n] 中每个数码出现的次数&#xff0c;即0 - 9每个数出现的次数。 解题思路 首先是无情的暴力法&#xff0c;可以用于判断我们后续的优化代码是否正确。 import java.io.*; import java.util.*;public class Main1 {static int n;p…

iOS系统文件备份与还原:保护和管理手机中的关键数据

​ 目录 引言 用户登录工具和连接设备 查看设备信息&#xff0c;电池信息 查看硬盘信息 硬件信息 查看 基带信息 销售信息 电脑可对手机应用程序批量操作 运行APP和查看APP日志 IPA包安装测试 注意事项 引言 苹果手机与安卓手机不同&#xff0c;无法直接访问系统文件…

Chatgpt掘金之旅—有爱AI商业实战篇|文案写作|(三)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、前言 人工智能&#xff08;AI&#xff09;技术作为当今科技创新的前沿领域&#xff0c;为创业者提供了广阔的机会和挑战。随着AI技术的快速发展和应用领域的不断拓展&…

#设计模式#4.6 Flyweight(享元) 对象结构型模式

享元模式是一种结构型设计模式&#xff0c;其主要目标是通过共享大量细粒度的对象来节省内存。享元模式的关键在于区分内部状态&#xff08;Intrinsic State&#xff09;和外部状态&#xff08;Extrinsic State&#xff09;。 内部状态是对象可共享的部分&#xff0c;通常是对…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

Linux和Windows安装PHP依赖管理工具Composer

Composer 是 PHP 的一个依赖管理工具。它允许申明项目所依赖的代码库&#xff0c;会在项目中安装它们。 Composer 不是一个包管理器。是的&#xff0c;它涉及 "packages" 和 "libraries"&#xff0c;但它在每个项目的基础上进行管理&#xff0c;在你项目的…

【Springboot整合系列】SpringBoot整合WebService

目录 Web服务介绍Web服务的两种类型Web服务架构Web服务的主要特点Web服务使用场景Web服务标准和技术 WebService介绍WebService的作用适用场景不适用场景 WebService的原理三个角色相关概念 WebService开发框架代码实现服务端1.引入依赖2.实体类3.业务层接口接口实现类 4.配置类…

python对接百度云车牌识别

注册百度智能云&#xff0c;选择产品服务。 https://console.bce.baidu.com/ 每天赠送200次&#xff0c;做开发测试足够了。 在应用列表复制 AppID , API Key ,Secret Key 备用。 SDK下载地址 https://ai.baidu.com/sdk#ocr 下载SDK文件&#xff0c;解压&#xff0c;…

matlab中旋转矩阵函数

文章目录 matlab里的旋转矩阵、四元数、欧拉角四元数根据两向量计算向量之间的旋转矩阵和四元数欧拉角转旋转矩阵旋转矩阵转欧拉角旋转矩阵转四元数参考链接 matlab里的旋转矩阵、四元数、欧拉角 旋转矩阵dcmR四元数quatq[q0,q1,q2,q3]欧拉角angle[row,pitch,yaw] % 旋转矩阵…

前端跨页面通信方案介绍

在浏览器中&#xff0c;我们可以同时打开多个Tab页&#xff0c;每个Tab页可以粗略理解为一个“独立”的运行环境&#xff0c;即使是全局对象也不会在多个Tab间共享。然而有些时候&#xff0c;我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。这就是本文说说…

算法学习——LeetCode力扣动态规划篇2(343. 整数拆分、96. 不同的二叉搜索树、416. 分割等和子集、1049. 最后一块石头的重量 II)

算法学习——LeetCode力扣动态规划篇2 343. 整数拆分 343. 整数拆分 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得…

构建第一个JS应用(FA模型)

创建JS工程 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发&#xff08;本文以应用开发为例&#xff0c;Atomic Service对…

openGauss 分布式数据库能力

分布式数据库能力 可获得性 本特性自openGauss 2.1.0版本开始引入。 特性简介 基于分布式中间件shardingsphere使openGauss具备分布式数据库能力。使用32个鲲鹏920(128核)节点组网(1*shardingsphere-proxy ,11*shardingsphere-jdbc,20*openGauss)时&#xff0c;完美shardin…