js精度丢失问题:0.1 + 0.2 !== 0.3

这个问题的核心在于浮点数在计算机中的表示方式,以及浮点数算术的精度问题。以下是转换过程的逐步解释,以展示为什么在JavaScript中0.1 + 0.2的结果并不严格等于0.3

浮点数的二进制表示

首先,我们需要理解的是计算机如何存储和处理小数。计算机使用的是IEEE 754标准下的浮点数表示法。在这种表示法下,数值是以二进制形式存储的。例如,十进制的0.1和0.2不能被精确地转换为二进制浮点数。而是被转换为一个接近的、有限的二进制近似值。

当我们试图将十进制的0.1转换为二进制时,我们会遇到问题,因为0.1在二进制中是一个无限循环小数。在十进制中,我们知道,1/3表示为0.3333...,后面是无限个3。二进制中的0.1类似,因为它是一个1除以2的幂(1/2, 1/4, 1/8, 1/16等等)。

下面是0.1的十进制值转换为二进制的过程:

0.1 (十进制) = 1/10

为了将这个分数转换为二进制,我们将数字乘以2,并且只关注结果的整数部分:

0.1 * 2 = 0.2 -> 整数部分是0,小数部分是0.2
0.2 * 2 = 0.4 -> 整数部分是0,小数部分是0.4
0.4 * 2 = 0.8 -> 整数部分是0,小数部分是0.8
0.8 * 2 = 1.6 -> 整数部分是1,小数部分是0.6
0.6 * 2 = 1.2 -> 整数部分是1,小数部分是0.2

并且此时我们可以看到0.2再次出现,意味着从这一步开始结果将会循环。因此,二进制表示开始循环0011,我们可以写作:

0.1 (十进制) = 0.0001100110011001100110011001100110011001100110011001101... (二进制)

所以0.1和0.2转换为二进制表示如下:

  • 0.1在二进制下是一个无限循环小数 0.0001100110011001100110011001100110011001100110011001101...
  • 0.2在二进制下也是一个无限循环小数 0.001100110011001100110011001100110011001100110011001101...

由于内存的限制,这些无限循环的小数需要被截断,舍入为最接近的可表示数(通常是使用“四舍五入”规则),这就引入了一个小的舍入误差。

执行加法运算

当你在JavaScript中执行0.1 + 0.2时,实际上执行的是两个舍入后的浮点数的加法运算。由于每个数都有一个微小的舍入误差,它们相加时这些误差也会相加,可能导致最终结果的误差超出了可以接受的范围。

结果与0.3的比较

最后,0.1 + 0.2的结果是另一个二进制浮点数,它并不完全等于十进制的0.3。当这个结果被转换回十进制以供显示时,你看到的是最接近的表示,它可能是0.30000000000000004,而不是精确的0.3

验证0.1 + 0.2 !== 0.3

在JavaScript中,当你比较0.1 + 0.20.3时,你实际上比较的是两个不同的浮点数:

0.1 + 0.2 // 结果是 0.30000000000000004
0.3       // 在二进制下是 0.0100110011001100110011001100110011001100110011001100111...

这两个值因为舍入误差的存在,并不完全相同。当它们以最接近的浮点数表示时,就会产生微小的差异,这是为什么在JavaScript中0.1 + 0.2 !== 0.3返回true的原因。

这个问题并不是JavaScript特有的,而是所有使用IEEE 754浮点数表示法的编程语言共同的问题。因此,执行精确的小数计算时,需要特别注意这个问题,或者使用专门的库(如decimal.js)来避免这种精度问题。

js通过bigdecimal计算出来得结果与java计算出来得结果是否一致?

在JavaScript和Java中使用BigDecimal(或类似的高精度数值处理机制)进行计算时,如果遵循相同的数学规则和精度设置,那么理论上得到的结果应当是一致的。这是因为BigDecimal类旨在提供超出标准浮点数类型精度的数值计算能力,它通过存储数值为任意精度的整数(在底层实现中可能是数组)和单独的比例因子(来表示小数点的位置)来避免浮点数精度问题。

相同之处

  • 精度管理:无论是Java中的BigDecimal类还是JavaScript中的高精度数值处理库(如big.js, decimal.js等),都允许你指定操作的精度。这意味着你可以控制运算的准确性,比如指定四舍五入的小数位数。
  • 数值表示:这些库表示大数和进行精确的小数运算的基本原理相似,它们避开了浮点数表示的限制,能够精确表示和处理极大或极小的数值。

不同之处

  • 实现和接口:虽然基本原理相同,但具体的实现细节和提供的接口可能有所不同。例如,方法的命名和可用的功能可能会有一些区别。
  • 性能:性能也可能会有所不同,这取决于具体的实现方式以及运行环境的不同(例如JVM和JavaScript引擎的差异)。

注意事项

  • 精度设置:确保在两种语言中使用相同的精度设置进行计算。不一致的舍入模式和精度设置是导致结果差异的常见原因。
  • 数学规则:遵循相同的数学规则和运算顺序。数学运算的顺序(特别是在涉及到多个操作符时)可以影响最终结果,尤其是在涉及到高精度计算时。

总的来说,只要确保两种环境下使用了相同的数值表示、精度控制以及数学规则,那么JavaScript和Java中通过BigDecimal(或类似机制)计算出来的结果应该是一致的。不过,实践中最好通过测试验证这一点,以确保跨语言应用的一致性和准确性。

解决前后端小数计算差异的问题,除了使用如decimal.jsbig.jsbignumber.js等高精度数学库,还有几种其他的方法和实践:

字符串传输

在前后端之间传输数值时,使用字符串而非浮点数。这样可以确保数值在传输过程中不会发生变化。在接收端再将字符串转换成高精度数值对象进行计算。

整数转换

将小数转换为整数进行计算。例如,可以将所有的小数乘以一个共同的因子(比如100,如果处理的是两位小数的货币值)使其变成整数,然后进行计算。计算结束后再除以相同的因子转换回小数。

定点数

使用定点数表示法代替浮点数。定点数表示法中,小数点的位置是固定的,通常可以通过将数值乘以一个固定的倍数来进行计算,确保前后端的一致性。

限制精度

在进行小数运算后,统一在前后端对结果进行四舍五入或截断,以匹配特定的精度。例如,如果你的应用程序只需要保留两位小数,你可以在每次运算后立即四舍五入到两位小数。

货币单位

对于金融相关的应用,考虑使用最小货币单位进行所有的计算(例如,用分而不是元)。这样,所有的货币值都可以作为整数处理,避免了浮点数运算的问题。

使用相同计算逻辑

尽量保证前后端使用完全相同的计算逻辑和算法。如果后端提供了一个API来进行计算,前端可以通过这个API来获取计算结果,而不是自己重新计算。

测试

进行彻底的测试以确保前后端处理数值计算的方式是一致的。包括单元测试、集成测试和端到端测试,确保在不同的环境和场景下计算结果都是一致的。

设计考虑

在设计时考虑这些问题,尽量避免在前端进行复杂的金融计算,而是将这些计算任务交给后端,后端通常会使用更加可靠和精确的方式来处理数值。

避免不必要的计算

在可能的情况下,避免进行不必要的中间计算步骤。每一次数值的运算都可能引入额外的舍入误差。如果可以直接使用最终结果,那么就避免了中间步骤可能带来的误差。

通过这些策略,可以在不同程度上缓解或解决前后端在处理小数时可能出现的精度差异问题。在具体实践时,可以根据应用场景的需求和约束选择最适合的方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容