当前位置: 首页 > news >正文

为什么使用 toFixed 方法的结果不一致呢?

偶遇一个不准确的方法 toFixed() ,其是 JS 中用于将数字格式化为指定小数位数的方法,但有时返回的结果不够准确,展示如下:

这通常是由于 JavaScript 对浮点数的处理方式导致的。

1. 浮点数精度问题

JavaScript 中的数字是以 IEEE 754 双精度浮点数 格式存储的,遵循64位的二进制浮点数表示。这种表示方式虽然能精确表示一些数值(如整数),但对某些小数(如 0.1 或 0.2 等)无法精确表示,它们会被存储为近似值。这是因为在二进制中,有些小数无法被精确地表示,导致了舍入误差。

🌰

这里 0.1 + 0.2 并不是精确的 0.3,而是稍微大于 0.3 的近似值。这种舍入误差是由于浮点数在二进制中表示精度不足造成的。

分析:

1、存储不精确

计算机存储的是二进制格式,不能存储无限小数,需要进行截断处理,导致第一步存储不精确,截断之后为 1 进一位,截断之后为 0 保留位。

2、运算不精确

因为存储的问题,进一步导致运算出问题,但不是绝对的,可能会抵消。

3、显示不精确

浏览器会进行近似处理,而不是完全展示真实数据。

一个神奇的现象,两个不一样的数据居然返回为 true。 

2. toFixed() 的行为

toFixed() 方法会将一个数字四舍五入为指定的小数位数,然后返回字符串形式的结果。

虽然它的作用看起来很简单,但由于浮点数的精度问题,有时会返回意料之外的结果。尤其是当浮点数内部表示的近似值超出人们期望时,toFixed() 会将这个误差传播到结果中。

🌰:

在 1.005 的例子中,浮点数舍入时引入了误差,toFixed(2) 结果会让人觉得舍入有问题,然而这是浮点数精度不足的体现。

十进制位数不同导致精度最后取舍有问题,究竟是1100的循环还是0011还是其他,影响不大。

3. 如何解决 toFixed 精度不准的问题

要解决浮点数精度问题,可以采用以下几种方法:

1、手动控制四舍五入的逻辑

function toFixedFix(num, decimalPlaces) {const factor = Math.pow(10, decimalPlaces);return (Math.round((num + Number.EPSILON) * factor) / factor).toFixed(decimalPlaces);
}console.log(toFixedFix(1.005, 2));  // 输出 1.01
console.log(toFixedFix(10.235, 2));  // 输出 10.24

2、使用第三方库

由于 JavaScript 内置的浮点数精度问题,一些库提供了更加精确的数值处理方法,尤其适用于财务计算等对精度要求较高的场景。

🌰:BigNumber、Decimal,它可以精确处理任意大小和精度的数字。

// npm install bigdecimal.js
const BigDecimal = require('bigdecimal.js');function toFixedBigDecimal(num, decimalPlaces) {const bigNum = new BigDecimal(num.toString());return bigNum.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).toString();
}console.log(toFixedBigDecimal(1.005, 2)); // 输出 1.01
console.log(toFixedBigDecimal(10.235, 2)); // 输出 10.24

这些库通过不同的底层实现来避免 JavaScript 浮点数的精度问题,并提供更多精确的数值操作方法。

3、使用字符串运算解决浮点误差

可以通过将数字转换为字符串,避免浮点数计算的问题。

function toFixedString(num, decimalPlaces) {let [integerPart, decimalPart] = num.toString().split('.');if (decimalPart && decimalPart.length > decimalPlaces) {// 提取多余的位数进行四舍五入操作const roundingDigit = parseInt(decimalPart[decimalPlaces], 10);decimalPart = decimalPart.slice(0, decimalPlaces);if (roundingDigit >= 5) {decimalPart = (parseInt(decimalPart, 10) + 1).toString();}}return parseFloat(integerPart + '.' + decimalPart).toFixed(decimalPlaces);
}console.log(toFixedString(1.005, 2)); // 输出 1.01
console.log(toFixedString(10.235, 2)); // 输出 10.24

http://www.mrgr.cn/news/58402.html

相关文章:

  • vue富文本使用editor
  • 【大模型】3分钟了解提示(Prompt)工程、检索增强(RAG)和微调
  • 1GS/s 4通道14bit PCIE采集卡
  • 晨辉考试抽签软件的两种注册方法之二:在线注册
  • LeetCode题解:2357. 使数组中所有元素都等于零,排序,详细注释
  • 对话系统介绍
  • 什么品牌的台灯护眼比较好?五款性能与品质兼并的护眼台灯分享
  • 2024年双十一有什么好物推荐?盘点2024双十一爆款好物分享
  • Nature 正刊丨阻断翻译的mRNA ADP核糖基转移酶的抗病毒防御
  • 中小企业设备管理数字化转型:Spring Boot实现
  • cpp的string类
  • 如何对网络设备进行监控:以监控易平台为例
  • 对数平均温差计算
  • 文档透明加密系统怎么用?五款透明加密软件汇总!2024热门推荐,实测分享!
  • Pytest-Bdd-Playwright 系列教程(2):支持在多浏览器、多环境中执行测试
  • 大语言模型训练方式探索(基于llma3模型)
  • 使用docker-compose部署一个springboot项目(包含Postgres\redis\Mongo\Nginx等环境)
  • java中this的内存原理是?
  • 伦敦银是24小时交易吗?
  • 《证据规定》之鉴定人拒不出庭的法律后果
  • 100 个常见网络基础知识普及
  • 爱回收品牌ID查询接口技术实现与代码示例
  • 雷池社区版有多个防护站点监听在同一个端口上,匹配顺序是怎么样的
  • 病毒分析-SysTracer工具监控进行行为
  • 自动化测试:等待方式
  • Java泛型Generic