浮点数的原罪

编程基石:整数与浮点数的存储、精度与应用实战 数据类型是编程的底层逻辑,它定义了数据的表示与操作方式。整数通过二进制补码实现精确存储,运算高效,但需警惕溢出问题。浮点数则遵循IEEE 754标准,以科学计数法形式近似表示实数,其核心挑战在于精度损失与舍入误差。理解这些原理对于保障程序正确性、优化性能与内存至关重要。在工程实践中,单精度与双精度浮点数的选择是一场典型的空间/速度与精度的权衡,直接影响着科学计算、图形渲染、深度学习及大数据处理等场景的效能。本文聚焦于整数与浮点数的本质区别,并结合大整数和精度损失等常见问题,深入探讨其在数据库、Flink、P 阅读详情

Javascript中的浮点数

在Javascript中,alert(0.1+0.2==0.3),结果为false。

这是因为javascript精度丢失的问题

    十进制0.1
    => 二进制0.00011001100110011…(循环0011) 
    =>尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-4(二进制移码为00000000010),符号位为0
    => 计算机存储为:0 00000000100 10011001100110011…11001
    => 因为尾数最多52位,所以实际存储的值为0.00011001100110011001100110011001100110011001100110011001
    而十进制0.2
    => 二进制0.0011001100110011…(循环0011)
    =>尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-3(二进制移码为00000000011),符号位为0
    => 存储为:0 00000000011 10011001100110011…11001
    因为尾数最多52位,所以实际存储的值为0.00110011001100110011001100110011001100110011001100110011
    那么两者相加得:    
    0.00011001100110011001100110011001100110011001100110011001
   +  0.00110011001100110011001100110011001100110011001100110011 (确认??)
    =  0.01001100110011001100110011001100110011001100110011001100
    转换成10进制之后得到:0.30000000000000004

在Javascript中如何破这个问题呢,可以通过自己实现一个浮点数的加减乘除 function来实现。原理是通过 Math.pow(x,y)将小数部分变成整数,再除回去就可以了:

  //加法  
  function FloatAdd(arg1,arg2){  
       var r1,r2,m;  
       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));  
       return (arg1*m+arg2*m)/m;  
  }  

     //减法  
  function FloatSub(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));  
      //动态控制精度长度  
      n=(r1>=r2)?r1:r2;  
      return ((arg1*m-arg2*m)/m).toFixed(n);  
  }  

     //乘法  
  function FloatMul(arg1,arg2)   {   
      var m=0,s1=arg1.toString(),s2=arg2.toString();   
      try{m+=s1.split(".")[1].length}catch(e){}   
      try{m+=s2.split(".")[1].length}catch(e){}   
      return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);   
  }   


    //除法  
  function FloatDiv(arg1,arg2){   
        var t1=0,t2=0,r1,r2;   
        try{t1=arg1.toString().split(".")[1].length}catch(e){}   
        try{t2=arg2.toString().split(".")[1].length}catch(e){}   
        with(Math){   
            r1=Number(arg1.toString().replace(".",""));

            r2=Number(arg2.toString().replace(".",""));   
            return (r1/r2)*pow(10,t2-t1);   
        }   
  }  

Java中的浮点数

不单单是Javascript有这个问题,所有支持二进制浮点数运算的编程语言都有这个问题,比如Java:

package com.notech.lang;

public class FloatTest {

    public static void main(String[] args) {
        System.out.println(0.1+0.2);
        System.out.println(0.3+0.4);
        System.out.println(String.format("0.1+0.2==0.3?%s", 0.1+0.2==0.3));

    }

}

// output is as below
/*
0.30000000000000004
0.7
0.1+0.2==0.3?false
*/

Java提供了BigDecimal来处理float值运算,可以如下:

package com.notech.lang;

import java.math.BigDecimal;

public class FloatTestWithBigDecimal {

    public static void main(String[] args) {
        BigDecimal number1 = new BigDecimal("0.1");
        BigDecimal number2 = new BigDecimal("0.2");
        BigDecimal number3 = number1.add(number2);
        System.out.println("number 3:"+number3);
        System.out.println(String.format("number3 == 0.3?%s", number3.equals(new BigDecimal("0.3"))));

    }
}

//output is:
/*
number 3:0.3
number3 == 0.3?true
*/

需要注意的是:传给BigDecimal构造函数的值一定要是 字符串,否则会发生不可思议的事:

package com.notech.lang;

import java.math.BigDecimal;

public class FloatTestWithBigDecimal {

    public static void main(String[] args) {
        BigDecimal number4 = new BigDecimal(0.1);
        BigDecimal number5 = new BigDecimal(0.2);
        BigDecimal number6 = number4.add(number5);
        System.out.println("number 3:"+number6);
        System.out.println(String.format("number3 == 0.3?%s", number3.equals(new BigDecimal(0.3))));

    }
}
//output is:
/*
number 3:0.3000000000000000166533453693773481063544750213623046875
number3 == 0.3?false
*/

BigDecimal的API文档是这么说的

  1. 此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
  2. 另一方面,String 构造方法是完全可预知的:写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。
  3. 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。
STM32串口高效传输浮点数的秘密武器:巧用union和指针,告别sprintf的坑 本文揭示了STM32串口传输浮点数时sprintf的潜在问题,并介绍了使用union和指针的高效解决方案。通过对比测试,展示了指针和union方案在速度、精度和内存占用上的显著优势,特别适合工业级实时数据传输需求。 阅读详情

相关推荐

Python 精确计算:告别浮点数陷阱,深入 decimal 模块的实战指南

本文深入探讨Python中浮点数精度问题及解决方案。首先揭示浮点数计算误差的根源——二进制存储导致的截断误差,并通过金融案例展示其严重后果。随后重点介绍decimal模块,详细讲解其核心概念(上下文与精度)、正确的字符串初始化方式,并演示如何构建精确的会计类。进阶部分探讨量化交易中的舍入控制,比较不同舍入模式,分析性能差异及适用场景。最后总结最佳实践:始终用字符串初始化Decimal、合理管理上下文,并针对不同场景选择合适的数据类型。该指南帮助开发者避免浮点陷阱,确保关键计算精确无误。

weixin_42636075的博客 394

为什么0.1+0.2不等于0.3

https://segmentfault.com/a/1190000012175422 但程序员在使用浮点数进行计算或逻辑处理时,不注意,就可能出问题。记住,永远不要直接比较两个浮点的大小:

前端菜鸟 1万+

AI确定性推理:从浮点数混沌到整数秩序,构建可信AI系统

在人工智能和机器学习领域,模型推理的**可重现性**与**跨平台一致性**是构建可信系统的核心挑战。其根源在于传统浮点数运算(如FP16、FP32)的数学特性:浮点数加法不满足结合律,导致计算顺序的微小差异(如不同的线程调度、编译器优化或硬件指令集)会引发累积的舍入误差,最终使结果分岔。这种不确定性在自动驾驶、金融风控等关键场景中可能引发严重后果。为解决此问题,**整数量化**技术应运而生,它将模型权重和激活值映射到整数域。整数运算在代数环上具有封闭性,满足结合律和交换律,为确定性计算提供了数学保证。结合*

weixin_32296621的博客 533

为什么 javascript 中 0.1 + 0.2 !== 0.3 为 True

惊闻 0.1 + 0.2 !== 0.3,赶忙计算得验证,发现,0.1 加 0.2 等于 0.30000000000000004 0.1 + 0.2 == 0.30000000000000004 返回 True注:下面为早期学习记录未注明原作者,找到时补上。JavaScript的number类型按照ECMA的JavaScript标准,它的Number类型就是IEEE 754的双精度数值,相当于j

BonDevil的专栏 1597

double转十进制字符串:大整数实现完全正确舍入的浮点数算法

浮点数转换是编程中的基础操作,但将double精确转成十进制字符串远比想象中复杂。二进制与十进制并非一一对应,0.1在计算机中的存储值与其十进制表示存在细微差异,而IEEE 754的舍入规则也并非简单的四舍五入,这导致传统printf实现偶尔出现最后一位偏差。本文从大整数(BigInt)运算出发,讲述如何将尾数与指数拆解后,通过乘以5的幂次构造精确十进制整数,再基于大整数比较判断最短且正确舍入的候选值,实现任意double的可靠转换。该方案不依赖浮点近似,逻辑透明,可验证性强,也能与Ryu等高性能算法互补,

weixin_31188927的博客 91

【技术博客分享】LLM推理过程中的不确定问题

博客原文: https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/

kakaZhui的博客 777

JS中的“0.1 + 0.2 != 0.3”问题

js中有个经典“0.1 + 0.2 != 0.3”的问题, if(0.1 + 0.2 === 0.3) { alert('yes') } else { alert('no') } 执行后会弹出”no“。 what? 原来,js中浮点数不能直接用等号判断相等,需要通过”2个数的差值小于等于最小精度值“判断相等,如下: if (Math.abs(num1 - ...

Coder Ben's Writing 356

单细胞分析实录(12): 如何推断肿瘤细胞

公众号后台回复20210418,获取本文的测试数据 1. 回顾 前面我已经讲解了inferCNV的基本用法,这一节继续学习:如何推断肿瘤细胞。本文应该是到目前为止,全网最详细的帖子(之一)。 关于肿瘤细胞的推断,比如研究上皮细胞起源的肿瘤,我见过的一些做法如下 简单粗暴型:将来源肿瘤病灶的所有上皮细胞都看成是肿瘤细胞 看CNV:将来源于肿瘤病灶的上皮细胞和参考细胞比较,将那些有明显CNV的细胞看作肿瘤细胞 看表达特征:考虑到有的肿瘤细胞可能没有CNV层面的变化,有的文章会根据肿瘤与正常的表达谱来区分是.

TOP生物信息 1万+

如何解决JavaScript中0.1+0.2不等于0.3

console.log(0.1+0.2===0.3);    //true or false?在正常的数学逻辑思维中,0.1+0.2=0.3这个逻辑是正确的,但是在JavaScript中0.1+0.2!==0.3,这是为什么呢?这个问题也会偶尔被用来当做面试题来考查面试者对JavaScript的数值的理解程度在JavaScript中的二进制的浮点数0.1和0.2并不是十分精确,在他们相加的结果并非...

ㅤ 9868

别再死磕官方文档了!用宿舍开黑的故事,5分钟搞懂Autosar CanNM网管报文

本文通过宿舍开黑游戏的生动类比,深入浅出地解析了Autosar CanNM网管报文的工作原理。从游戏队友协作到汽车ECU节点的同步机制,详细介绍了网管报文的唤醒流程、通信协议及休眠策略,帮助读者快速掌握这一关键技术。

weixin_30463341的博客 261

深入剖析:功率放大电路设计精髓——从理论到实践

输入信号首先被调制(通常是PWM脉宽调制)成高频开关信号,驱动功率开关管(MOSFET),再通过LC低通滤波器滤除高频分量,还原出放大的音频信号。在靠近功放板电源引脚处放置足够容量的电解电容(如100uF - 1000uF)和高频瓷片电容(如0.1uF)并联进行电源去耦,抑制低频和高频干扰,防止低频振荡(Motorboating)和高频自激。,堪称电子世界里的“能量转换器”。当输入信号在零附近(即两个器件切换导通的区域)时,由于器件的开启电压(Vbe或Vgs)不为零,输出波形会出现明显的衔接不流畅的失真。

Zihan2558的博客 1692

alert

打开题目链接 使用burpsuite抓包 ,再Send to repeater,再发送,就会看到最后有一串字符加数字 使用Unicode解码 即可得到flag

weixin_63289925的博客 308

关于Selenium3在MicrosoftEdge浏览器中出现的问题

前言 最近在做web自动化测试,所用环境是java+selenium3.141.59+MicrosoftEdge(Chromium)浏览器。 在调试的过程中,出现了很多问题。比如selenium3在Edge浏览器中远程调用中,不支持addArguments方法等 问题 1.Edge浏览器弹窗问题 在测试过程中,会出现弹出窗提示 ...

zhucheng1994的博客 2188

STM32 中 ADC 数据到 float 浮点数的转化与显示方法

STM32 中 ADC 数据到 float 浮点数的转化与显示方法 STM32 自带一个或多个 12bit 24通道 ADC,足够一般场合使用,但是使用过程中会遇到采集与显示的细节问题。我目前是用的 LCD 来显示,但是LCD驱动中并没有 float 浮点数显示函数,但是有字符串显示功能,所以我们可以利用这个来实现所需的功能: void LCD_ShowString(uint16_t x,uint...

dexfire ’s blog 6291

WOFOST作物模型(3):敏感性分析

使用TAGP(Total Above Ground Production),地上总产量TSUM1,temperature sum from emergence to anthesis,萌发至开花所需温度TSUM2,temperature sum from anthesis to maturity,开花至成熟所需温度SPAN,life span of leaves growing at 35 Celsius,生长温度为35度时的叶龄。

所有专家都曾始于新手 1145

【Unity小游戏】整整一个周末写一款《皇室战争 玩法》 的 即时战斗类 游戏Demo。两万多字游戏制作过程+解析

Unity游戏制作,本篇文章介绍了复刻皇室战争玩法的一个自制小游戏,共有该游戏的两万字教程加制作过程,欢迎品尝! 世界上没有绝对的公平,如果我们起点就比别人第一步,那就更需要比别人努力了。

努力前行,总会成为自己心中的那道光 12万+

Python 精确计算:告别浮点数陷阱,decimal 模块实战指南

摘要 本文介绍了Python中浮点数精度问题的根源及解决方案。由于IEEE 754标准限制,二进制计算机无法精确表示某些十进制小数,导致金融等场景的计算误差。为此,Python提供了decimal模块,通过Decimal数据类型实现精确计算。文章详细讲解了正确初始化Decimal对象的方法、上下文环境配置、常用舍入模式,并给出金融利息计算等实战案例。同时指出性能优化技巧和JSON序列化注意事项,建议在高精度计算场景统一使用Decimal类型。最后提出结合logging模块记录计算过程,便于审计追踪。该模块是

weixin_42636075的博客 1258

STM32 BOOTLOADER配置以及APP跳转实现(裸机)

Bootloader是硬件启动的引导程序,是运行操作系统的前提。在操作系统内核或用户应用程序运行之前运行的一段小代码。对硬件进行相应的初始化和设定,最终为操作系统准备好环境。APP就是我们的应用程序,经过硬件引导程序之后跳转到系统程序运行。

吻等离子的博客 3355

算法比赛中的浮点数精度陷阱:从一个货币分解问题说起

摘要: 文章探讨了算法比赛中常见的浮点数精度陷阱,以巴西货币分解问题为例,展示了浮点误差如何导致结果错误。由于计算机二进制表示小数的局限性,0.1等十进制数存储时会产生截断误差。解决方案是在将金额转换为分时加0.5进行四舍五入(如int(N*100+0.5))。文章还指出了浮点比较、累积误差等常见场景的应对策略,建议优先使用整数模拟小数计算。这一技巧对于ACM/ICPC等比赛中处理货币、几何等问题至关重要。

2301_79411237的博客 1057

2026年全国青少年信息素养大赛算法应用主题赛C++样题及答案解析

2026年全国青少年信息素养大赛算法应用主题赛C++样题

王老师青少年编程 3711

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Python 浮点数陷阱:为什么 0.1 + 0.2 不等于 0.3?深入解析与解决方案

本文深入解析了Python中浮点数计算的精度问题,特别是0.1+0.2不等于0.3的现象。文章从二进制存储原理入手,解释了计算机处理浮点数时的舍入误差根源。通过实际案例展示了浮点数陷阱在循环控制、金融计算等场景中的风险,并提供了三种解决方案:容忍误差的Epsilon比较法、精确计算的decimal模块使用指南,以及科学计算中的numpy处理方式。针对不同应用场景,文章给出了具体代码示例,帮助开发者规避浮点数精度问题,编写更健壮的数值计算代码。

weixin_42636075的博客 1286

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java 隐式转换引发的生产事故,菜是原罪,切记切记~

文章目录取整运算隐式转换规则保留指定小数位结论求余运算附赠Math函数进位方法算数方法随机数 背景:公司项目最近做项目技术建设,SonarLint 对历史代码扫描出的 Bug 进行 ”清零“,故障就此发生。在修改后上线,导致生产环境所有的导出功能全部崩溃!在此复盘跟各位大佬分享一波,基础真的很重要! 先给大佬们看看灾区代码: // 修改之前: int pageCount = (int)Math.ceil(dataset.size()/50000)+1; // ======== 分割线 ========

zhuzicc的博客 1699

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

PHP 内置了 BCMath (Binary Calculator) 扩展,它以字符串形式进行任意精度的数学运算,完全避开二进制浮点数问题。

维度核心要点行动指南本质字符串模拟十进制运算彻底避开 IEEE 754 二进制浮点陷阱输入必须是字符串严禁传入 float,防止隐式转换污染精度精度截断而非四舍五入注意scale参数行为,必要时手动修约比较使用bccomp禁止直接用==比较 BCMath 结果性能慢于原生运算仅用于金额等关键场景,勿用于循环计数依赖需启用扩展部署时确认已加载终极心法BCMath 是 PHP 开发者对“精确性”的最后坚守。在计算机的近似世界里,它开辟了一块精确的净土。但工具虽好,需慎用之。

长风破浪会有时的博客 491

C++浮点数比较的终极方案:为什么fabs(a-b)<eps不总是有效?

本文深入探讨了C++中浮点数比较的复杂性,指出经典的fabs(a-b)<eps方法在数量级差异、运算路径依赖等场景下可能失效。文章分析了浮点数误差根源,并系统介绍了相对误差比较、ULP(Unit in the Last Place)比较法等更健壮的替代方案,帮助开发者根据具体场景选择或组合策略,构建可靠的浮点数比较逻辑。

red88的博客 661

大模型推理不确定性的根源

部分GPU核函数是不确定的;大模型前向传播所用的核函数(如RMSNorm、矩阵乘法)均为确定性;推理服务器(如vLLM)的前向传播可被称为“确定性”(相同输入必出相同输出);从用户视角看,推理结果仍不确定。问题的关键,藏在“批量不变性(Batch Invariance)”这一被忽视的属性中。理想情况下,批量处理中单个样本的结果应与“批量大小”无关——即“对批量中第一个样本单独计算”和“对整个批量计算后取第一个样本”的结果应完全一致。这一属性被称为“批量不变性”。但现实是:多数大模型核函数。

这里是数字化与人工智能的 “实验场” 与 “瞭望台” 1393

【通信心法】把 struct 强转成指针发出去是原罪!撕碎内存对齐与大小端陷阱,用 NanoPB 构筑跨平台的绝对序列化契约

真正的顶级系统架构,必须将内存的数据结构与总线上的传输格式彻底剥离。我们需要引入 Google 的NanoPB。平庸的开发者,把内存里的 0 和 1 视作理所当然,随意地把指针扔来扔去。当系统在异构的夹缝中崩溃时,他们只能在黑暗中盲目地抓取 Bug。而顶级的系统架构师,对每一滴跨越系统边界的比特流都怀揣着绝对的敬畏。我们深知,C 语言的结构体只是编译器在特定架构下的一场“本地狂欢”。

Max_uuc的博客 403
上一篇: GIT - 日常操作(1)
下一篇: 500行JS代码打造你的专属GIT
notechsolution
博客等级 码龄11年 27粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值