数学计算之JS小数精度问题(java/python)

news2024/9/21 8:02:31

number 小数计算会出现精度不准确问题,js中number是64 位双精度浮点数。

其实,不仅仅只有javascript,还有java、python等都会有类似问题,因为计算机中存的都是二进制(浮点数IEEE754是被普遍使用的标准),小数转二进制时是乘2取整,再用余下的小数部分乘2再取整,如此反复。有的小数转二进制可能会无限循环比如0.1、0.2等,计算机中不可能提供无限个bit位去存储它们,会舍弃一部分二进制位,因而造成了精度损失。

而且在加减乘除运算完毕后,由于尾数的位数有限,需要进行舍入(舍弃多余的位数) 常用方法有0舍1入、恒置1

0.1+0.2=0.30000000000000004

0.1 + 0.2 === 0.3 //为false

以下是一些常见的解决方法:

1.先转为整数并计算然后再转回小数:

function add(num1, num2){
    const getDecimalLen = (numStr) => numStr.includes('.') ? (numStr.split('.')[1]).length : 0,//获取小数长度
    num1Len = getDecimalLen(num1.toString()),
    num2Len = getDecimalLen(num2.toString()),
    factor = Math.pow(10, Math.max(num1Len, num2Len));//10的maxLen次方
    return (num1 * factor + num2 * factor) / factor;
}
add(0.1, 0.2); // 0.3

2.使用专门的库或工具:

在处理需要高精度计算的场景中,可以使用一些专门的库或工具。例如,JavaScript 中的 Decimal.js、Big.js 或 BigNumber.js 等库提供了高精度的数学计算功能,可以避免精度丢失的问题。

var Decimal = require('decimal.js');
new Decimal(0.1).add(new Decimal(0.2)).toNumber(); //0.3

python中可以使用SciPy、Numpy等。例如,SciPy中的derivative函数可以用于计算数值导数,而NumPy中的梯度函数则可以用于计算向量或矩阵的梯度

java中可使用jdk8的BigDecimal(不支持三角函数) 和 big-math拓展的BigDecimalMath(支持三角函数)

比如 求2的平方根(保留6位精度):BigDecimalMath.root(new BigDecimal(2), new BigDecimal(2) , new MathContext(6));

对于divide除数计算需要指定保留精度,否则除出来无限循环会报此错误:Non-terminating decimal expansion; no exact representable decimal result

BigDecimal.divide(new BigDecimal(8), new MathContext(10));// 第二个参数传入MathContext指定精度
BigDecimal.divide(new BigDecimal(8), 8, BigDecimal.ROUND_HALF_DOWN);//第二个参数保留几位小数,第三个参数为四舍五入规则

3.toFixed限制小数位数(返回字符串):

这种虽然简便,但是由于浮点数IEEE754规则的限制,不能够准确的达到四舍五入的效果。

1.35.toFixed(1); // '1.4' 正确

1.335.toFixed(2) // '1.33' 错误

解决toFixed问题:

转为整数,取舍后再转回小数, 但是Math.round对于负数的四舍五入处理时还存在一定问题。

Number.prototype.toFixed = function(size) {
    const padDecimal = (num, decimalPlaces) => {
        let numStr = num.toString();
        if (numStr.includes('.')) { //有小数,补0
            let decimalPart = numStr.split('.')[1];
            if (decimalPart.length < decimalPlaces) {
                numStr += '0'.repeat(decimalPlaces - decimalPart.length);
            }
        } else { // 如果没有小数部分,添加小数点和0
            numStr += '.';
            numStr += '0'.repeat(decimalPlaces);
        }
        return numStr;
    }
    return padDecimal((Math.round(this * Math.pow(10, size)) / Math.pow(10, size)), size);//还需要补充缺失的0
}

1.335.toFixed(2); //'1.34' 正确

(-1.335).toFixed(2);//'-1.33' 错误

-1.335.toFixed(2); //'-1.34' 正确 是因为'.'运算符优先级高于'-'

常见的舍入策略包括四舍五入Math.round、向上取整Math.ceil、向下取整Math.floor。

但是注意:Math.round对于负数的处理会存在一定问题。 floor和ceil不会出现问题。

Math.round(-5.4); // -5 正确

Math.round(-5.5); // -5 错误

Math.round(-5.6); // -6 正确

Math.round方法准确说是“四舍六入”,对0.5要进行判断对待。

Math.round的原理是对传入的参数+0.5之后,再floor向下取整得到的数就是返回的结果。

public static long round(double a) {
if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5
    return (long)floor(a + 0.5d);
else
    return 0;
}

优化之后:

//先记录数值正负,保证round操作的是正数,在最后返回时,再进行修改正负

Number.prototype.toFixed = function(size) {
    const padDecimal = (num, decimalPlaces) => {
        let numStr = num.toString();
        if (numStr.includes('.')) { //有小数,补0
            let decimalPart = numStr.split('.')[1];
            if (decimalPart.length < decimalPlaces) {
                numStr += '0'.repeat(decimalPlaces - decimalPart.length);
            }
        } else { // 如果没有小数部分,添加小数点和0
            numStr += '.';
            numStr += '0'.repeat(decimalPlaces);
        }
        return numStr;
    }
    let abs = 1;
    if (this < 0) abs = -1;
    const _this = Math.abs(this);
    let factor = Math.pow(10, size);
    let result = Math.round(_this * factor) / factor;
    //补充缺失的0
    return padDecimal(result * abs, size);
}

1.335.toFixed(2); //'1.34' 正确

(-1.335).toFixed(2);//'-1.34' 正确

高等数学中一些基本概念

在数学和计算机中三角函数的所有计算都采用弧度制(pi/2),而不是角度制。

其实,如果只是为了度量一个角度,用“角度”是满方便的.但是,在数学和工程技术中,大量用到三角函数和相关公式。用角度制的话相关公式比较复杂,不便计算。

使用弧度制的话, 公式是相对最简单的如下图所示:

radian 弧度   degress角度

三角函数(sin/cos/tan) 反三角函数等在计算机中一般传入的是弧度,而非角度。需转换(弧度=Math.PI/180 * 角度)。

exp,高等数学里以自然常数e为底的指数函数。exp(2)就是e的平方。

log:表示对数,与指数相反

root:表示开根计算。 sqrt 平方根

pow:表示幂,计算n次幂

add、subtract、multiple、divide 加减乘除

remainder %取余   negate 取反(-this)

笛卡尔积:两个集合X和Y的笛卡尔积(Cartesian product),又称直积,表示为X × Y,第一个对象是X集合的成员而第二个对象是Y集合的成员所有可能有序对。

通俗的解释就是:用来表示两个团体中融合时候,两个团体中的每一个个体之间会产生什么样的可能性

Mysql中多表查询就是利用笛卡尔积生成一个虚拟表,然后再去除其中无关的记录。

微分、求导、积分相关概念:

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

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

相关文章

Java:线程安全

引子 首先来看一段代码: private static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(()->{for (int i 0; i < 50000; i) {count;}});Thread t2 new Thread(()->{for (int i 0; i < 50000; i) {…

Java语言程序设计——篇十一(4)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

深入解析 KMZ 文件的处理与可视化:从数据提取到地图展示项目实战

文章目录 1. KMZ 文件与 KML 文件简介1.1 KMZ 文件1.2 KML 文件 2. Python 环境配置与依赖安装3. 代码实现详解3.1 查找 KMZ 文件3.2 解压 KMZ 文件3.3 解析 KML 文件3.4 可视化 KMZ 数据 4. 项目实战4.1. 数据采集4.2. 项目完整代码 5. 项目运行与结果展示6. 总结与展望 在处理…

2007-2023年上市公司国内外专利申请获得情况数据

2007-2023年上市公司国内外专利申请获得情况数据 1、时间&#xff1a;2007-2023年 2、来源&#xff1a;上市公司年报 3、指标&#xff1a;证券代码、统计截止日期、报表类型、地区、申请类型编码、申请类型、专利&#xff08;件&#xff09;、发明专利&#xff08;件&#x…

动态路由协议基础

一、动态路由协议简介 动态路由协议:路由器用来计算和维护路由信息的协议;通俗的说,就算路由器用来学习路由的协议。 二、动态路由与静态路由的区别 静态路由动态路由路由表手工配置自动生成路由维护人工维护自动收敛资源消耗路由表生成不占网络资源路哟表生成占用网络资源…

学习Java的日子 Day59 学生管理系统 web1.0版本

Day59 学生管理系统 web1.0 1.项目需求 有两个角色&#xff0c;老师和学生&#xff0c;相同的功能提取到父类用户角色 2.数据库搭建 设计学生表 设计老师表 插入数据 (超级管理员) 设计学科表 3.项目搭建 处理基础页面&#xff0c;分包&#xff0c;实体类&#xff0c;导入数据…

微软AI业务最新营收数据情况(2024年7月)

Azure AI 年度经常性收入 (ARR)&#xff1a;达到50亿美元客户数量&#xff1a;60,000家平均客户价值 (ACV) 中位数&#xff1a;83,000美元同比增长率&#xff1a;达到了惊人的900% GitHub Copilot 年度经常性收入 (ARR)&#xff1a;达到3亿美元客户数量&#xff1a;77,000家…

每日两题8

买卖股票的最佳时机 III class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();int INF 0x3f3f3f3f;vector<vector<int>> f(n, vector<int>(3, -INF));auto g f;g[0][0] 0;f[0][0] -prices[0];for (int i 1; i…

Leetcode3227. 字符串元音游戏

Every day a Leetcode 题目来源&#xff1a;3227. 字符串元音游戏 解法1&#xff1a;博弈论 分类讨论&#xff1a; 如果 s 不包含任何元音&#xff0c;小红输。如果 s 包含奇数个元音&#xff0c;小红可以直接把整个 s 移除&#xff0c;小红赢。如果 s 包含正偶数个元音&am…

10.Redis类型SortedSet

介绍 Redis的SortedSet是一个可排序的set集合。与java的TreeSet有些类似&#xff0c;但底层数据结构却差别很大。 SortedSet中的每个元素都带有一个score属性&#xff0c;可以基于score属性对元素排序&#xff0c;底层实现是一个跳表SkipList加hash表。 特点 可排序 元素不…

“银狐”团伙再度出击:利用易语言远控木马实施钓鱼攻击

PART ONE 概述 自2023年上半年“银狐”工具被披露以来&#xff0c;涌现了多个使用该工具的黑产团伙。这些团伙主要针对国内的金融、教育、医疗、高新技术等企事业单位&#xff0c;集中向管理、财务、销售等从业人员发起攻击&#xff0c;窃取目标资金和隐私信息。该团伙惯用微信…

多旋翼+四光吊舱:5Kg负载无人机技术详解

多旋翼无人机是一种具有三个及以上旋翼轴的无人驾驶飞行器。它通过每个轴上的电动机转动&#xff0c;带动旋翼&#xff0c;从而产生升推力。旋翼的总距固定&#xff0c;不像一般直升机那样可变。通过改变不同旋翼之间的相对转速&#xff0c;可以控制飞行器的运行轨迹。多旋翼无…

Js在线Eval加密混淆及解密运行

具体请前往&#xff1a;Js在线Eval加密混淆及解密运行

自动打电话软件的效果怎么样?

​​使用这个系统&#xff0c;机器人自动拨打电话&#xff0c;真人录制的语音与客户对话&#xff0c;整个过程非常顺畅。而且系统可以每天外呼数千乃至数万通电话&#xff0c;是人工的5-10倍&#xff0c;这样就不需要招聘大量员工来外呼&#xff0c;只需要留下一些优秀的销售人…

动视封禁超过6.5万名《战区》和《MW3》作弊者

动视已经在《使命召唤&#xff1a;战区》和《使命召唤&#xff1a;现代战争3》中封禁了超过65000名玩家。这些封禁在过去的几小时内实施&#xff0c;清除了数千名在排名赛和非排名赛中“作弊和代练”的玩家。 Ricochet反作弊团队现已清理了《使命召唤&#xff1a;战地》和《现代…

【PyTorch】神经风格迁移项目

神经风格迁移中&#xff0c;取一个内容图像和一个风格图像&#xff0c;综合内容图像的内容和风格图像的艺术风格生成新的图像。 目录 准备数据 处理数据 神经风格迁移模型 加载预训练模型 定义损失函数 定义优化器 运行模型 准备数据 创建data文件夹&#xff0c;放入…

人工智能与大数据的融合:驱动未来的力量

人工智能与大数据的融合&#xff1a;驱动未来的力量 一、人工智能与大数据的概述二、人工智能与大数据在数据库中的融合三、实际应用案例四、未来发展方向总结 【纪录片】中国数据库前世今生 在数字化潮流席卷全球的今天&#xff0c;数据库作为IT技术领域的“活化石”&#xff…

16进制转换-系统架构师(三十九)

1、&#xff08;软件架构设计->构件与中间件技术->构件标准&#xff09;对象管理组织&#xff08;OMG&#xff09;基于CORBA基础设施定义了四种构件标准。其中&#xff0c;&#xff08;&#xff09;状态信息是构件自身而不是由容器维护的。 A实体构件 B加工构件 C服务…

C++中lambda使用mutable关键字详解

C中lambda使用mutable关键字详解 在《C初学者指南-5.标准库(第二部分)–更改元素算法》中&#xff0c;讲“generate”算法时有下面这段代码&#xff1a; auto gen [i0]() mutable { i 2; return i; }; std::vector<int> v; v.resize(7,0); generate(begin(v)1, begin…

(南京观海微电子)——LCD OTP(烧录)介绍

OTP OTP只是一种存储数据的器件&#xff0c;全写:ONETIMEPROGRAM。 OTP目的&#xff1a;提高产品的一致性 客户端的接口不支持和我们自己的产品IC之间通信&#xff0c;即不支持写初始化&#xff0c;所以产品的电学功能以及光学特性需要固化在IC中&#xff0c;所以需要我们来进行…