首页 > 其他分享 >如何完美解决前端数字计算精度丢失与数字格式化问题?

如何完美解决前端数字计算精度丢失与数字格式化问题?

时间:2023-07-14 14:56:29浏览次数:36  
标签:返回 格式化 数字 计算 计算精度 calc string

大家好,我是木瓜太香,做前端开发经常会遇到数字计算精度丢失的问题,和数字格式化的麻烦问题,好不容易找到了可以解决这些问题的库结果用起来不够方便,例如 bignumber.js decimal.js 等编写体验不好,这篇文章来帮助你完美解决这些问题

接下来我们根据以下两个问题展开说说:

  • 只有前端会数字运算不准确吗?后端为什么不会这样?
  • 怎样完美解决数字计算精度问题和数字格式化问题?

只有前端会数字运算不准确吗?后端为什么不会这样?

实际上并非只有前端的 javascript 有数字计算的精度问题,其他的常见语言默认都有这个问题,大家可以自己去试一试,只不过其他的语言都自带了精准计算的库,所以后端在处理数字的时候会使用语言自带的模块来保证数字计算的精准,而javascript目前还没有自带相关模块,只有第三方的模块,不过未来的javascript是可能自带精准计算模块的,这里有一个相关提案,目前处于 Stage 1 阶段,目前提案的语法如下:

function calculateBill(items, tax) 
{
    let total = 0m;
    for (let {price, count} of items)
    {
        total += price * BigDecimal(count);
    }
    return BigDecimal.round( total * (1m + tax), {maximumFractionDigits: 2, round: "up"} );
}

let items = [{price: 1.25m, count: 5}, {price: 5m, count: 1}];
let tax = .0735m;
console.log(calculateBill(items, tax));

当然上面的代码现在是无法使用的,只是提案的一个语法展示例子,而且即便支持了这个语法,从易用性上来说也不如我们接下来介绍的方法。

怎样完美解决数字计算精度问题和数字格式化问题?

答案就是 a-calc 库,这个库具备精准计算需求也兼顾了数字格式化和易用性的需求,我们都知道 bignumber.js 这类库最大的问题就是操作数一旦多起来那么就非常不直观,我们来看看 a-calc 是怎么使用的。

基础的运算:

import { calc } from "a-calc"

calc("0.1 + 0.2") // 0.3

变量运算:

calc(" (a + b) / 2 ", {a: 2, b: 6}) // 4

你没看错就是这么简单,编写方式非常符合直觉,接下来我们再来看看一个复杂一点的计算式。

calc("1 + o.a / arr[0].d",{
    o: { a: 2 },
    arr: [{ d: 8 }]
}) // 1.25

到这里你可能有一个疑问,如果变量没取到,或者因为某些原因导致计算式非法怎么办?默认当然是报错了,不过贴心的 a-calc 自然也给了你更方便的功能,错误返回默认值。

calc(" a + 1 ", {a: undefined, _error: 0}) // 0

上面的 a是undefined那么计算式就不会成立,无法计算,但是一旦你传入了 _error 参数,在即将报错的时候他会返回给你 0,这样你就不用自己做错误处理了,慢着,这就完了吗?当然不是,都说了要完美了,这些功能自然还不够!接下来我们说说数字格式化。

我们实际开发中可能在计算完成之后做常规的数字格式化或者就单纯需要数字格式化,例如千分位,保留小数位,转换成百分比,禁止输出科学计数法,转换成分数,等等,放心,这些全部支持,而且更强大 a-calc 除了支持上面的格式化还支持动态保留小数位,保留正负号,带单位计算等等,下面直接上代码。

// 注意格式化部分使用 | 与表达式部分分隔开,写在右边即可
calc("1 + 1 | =2") // 2.00  =2的意思就是小数点位数保留2位,既然有等于那么你也应该想到了,大于 小于 大于等于和小于等于也是支持的
calc("132424232423423 + 2132243242 | ,") // 132,426,364,666,665 这里一个逗号就表示千分位了
calc("0.025 + 0.2 | /") // 9/40 分数输出也很直观!到这里百分比输出还用演示吗?想必大家应该已经知道了就是一个百分号就行了。
calc("1 + 2%", {_unit: true}) // 3% 带单位计算依然不在话下

良好的typescript支持

如果你使用了typescript,那么依然可以等到良好的ts类型提醒,正常情况下你可以使用 calc 一把梭哈,但是 a-calc 依然提供了一个更加强大智能的 calc_wrap 函数:

// 注意这里将 calc_wrap 重命名为 calc, 因为如果你需要使用 calc_wrap 函数的时候,基本用不到核心的 calc 函数,那么有这个闲置好名字就应该拿来用
import { calc_wrap as calc } from "a-calc";

const state = {
    a: 1,
    b: 2,
    c: 3
};

// 当传入的参数是一个不含变量名的计算式将会直接返回计算结果
calc( "(1 + 2) * 3" ); // 返回类型: string

// 当传入的参数是一个疑似包含变量名的计算式且没有第二个数据源参数时,会返回一个等待传入数据源的函数,没错这个功能通过静态类型的推导做到了
calc( "(a + b) * c" ); // 返回类型: ( data: any ) => string
calc( "(a + b) * c" )( state ); // 返回类型: string

// 也许你希望先注入状态然后在输入表达式,这也是可以的
calc( state ); // 返回类型: ( expr: string | number ) => string
calc( state )( "(a + b) * c" ); // 返回类型: string

// 原本的用法自然也是支持的
calc( "a + b + c", state ); // 返回类型: string

// 你依然可以将配置与数据源混合在一起,这是非常方便的
calc( "a + b + c" )( { ...state, _error: 0 } ); // 返回类型: string | 0

好了到这里你应该也了解了 a-calc 大部分的使用方式,更具体的内容可以查看官方文档:https://www.npmjs.com/package/a-calc
如果你觉得我的内容对你有帮助可以点赞加关注,永远不迷路。
你也可以关注我的油管和b站账号:木瓜太香

有前端问题需要讨论的可以加我的qun:237871108。也可以通过哔哩哔哩搜索木瓜太香找到我。

标签:返回,格式化,数字,计算,计算精度,calc,string
From: https://www.cnblogs.com/o00o/p/17553705.html

相关文章

  • dede列表页输入数字跳转到指定分页代码
    编辑打开列表页模板,默认路径为empletsdefaultlist_article.htm,将下列代码插入之间,也可以做JS调用。<scripttype="text/javascript">//<![CDATA[functiononCheckPage(){varbeginPage=parseInt(document.beginPagefrm.beginPage.value);if(isNaN(beginPage)){alert("请输......
  • Excel-批量填充数字
    1、一般情况下,都是使用鼠标左右键拖动来实现数据的填充的2、但是填充1200列,下拉拖动就非常麻烦,可以首先定位到A200。在屏幕左侧中央处找到剪切板下方的“A1”字样,鼠标单击A1文字,输入想要跳转的单元格,如A200,输入完成之后,点击回车即可。3、将要填充数据的单元格全部选中,选择的......
  • dede tag不以关键词作为url以数字作为url方法修改
    dedetag不以关键词作为url以数字作为url方法修改打开/include/taglib/tag.lib.php查找以下代码:$row['link']=$cfg_cmsurl."/tags.php?/".urlencode($row['keyword'])."/";替换为:$row['link']=$cfg_cmsurl."/tags.php?/".urlen......
  • AIGC:新AI时代,推动数字人进化的引擎
    摘要:CV、NLP、大模型...AI技术的加持下,让数字人内外在更加生动真实。在未来的发展中,数字人的应用场景越来越广泛,并将发挥出重要的作用,让美好照进生活。本文分享自华为云社区《AIGC:新AI时代,推动数字人进化的引擎》,作者:华为云社区精选。现在我们在手机视频里经常看到,几百平方米的......
  • 在集合中加入随机的数字(1-20)
    publicvoidnums(){ArrayListlist=newArrayList();Randomr=newRandom();list.Add(r.Next(20));while(true){if(list.Count==20)break;intnum=r.N......
  • 2023全球数字经济大会召开,天翼云携手产业链共建开放共赢云生态
    近日,由北京市人民政府、国家发展和改革委员会、工业和信息化部、商务部、国家互联网信息办公室、中国科学技术协会共同主办,中国云产业联盟暨中关村云计算产业联盟(简称“云联盟”)承办的“2023全球数字经济大会·云融技术创新引领论坛”在国家会议中心隆重召开。天翼云科技有限公司......
  • 华为云MetaStudio全新升级,盘古数字人大模型助力数字人自由
    摘要:基于盘古大模型能力,华为云MetaStudio数字内容生产线全新升级,推出数字人模型生成服务和模型驱动服务。近日,华为开发者大会2023(Cloud)在东莞拉开帷幕。基于盘古大模型能力,华为云MetaStudio数字内容生产线全新升级,推出数字人模型生成服务和模型驱动服务,旨在通过数字人服务......
  • 【专题】保险行业数字化洞察白皮书报告PDF合集分享(附原数据表)
    报告链接:https://tecdat.cn/?p=33203原文出处:拓端数据部落公众号近年来,"养老"、"三胎政策"、"医疗成本"等一系列备受关注的民生话题,使得保险服务备受瞩目,并逐渐渗透到每个人的生活中。自2020年以来,由于多种因素的影响,人们对健康的意识不断提高,这正在重新塑造中国消费者对保险的......
  • P1216 [USACO1.5] [IOI1994]数字三角形
    自己的思想:要用逆序,但是某个未知的位置可能存在一个非常大的数,因此不知道如何dp看题解之后:对于倒数第二行的数,可以算出它们的最优解,依次往上推,第一个数就是整体的最优解,其实本质上可以用隔离意识来看,在搞最后一排时,将前面所有排隔离掉,在处理中间的每一排时,又将其他排隔离掉接下......
  • JAVA 数字类型 的使用和选择
    JAVA语言中有八种基本的数字类型,分别是byte、short、int、long、float、double、char和boolean。这些类型的区别在于它们所占用的内存空间和表示的范围不同。在使用和选择数字类型时,需要考虑以下几个因素:数字的大小:如果数字很小,可以使用byte或short类型,它们占用1个字......