JavaScript中的浮点数之谜:为什么0.1 + 0.2 不等于 0.3?

在JavaScript中,为什么0.1 + 0.2 不等于 0.3?

在 JavaScript 中,0.1 + 0.2 不等于 0.3 的原因与浮点数的表示和计算有关。JavaScript 使用 IEEE 754 双精度浮点数标准来表示数字,这是一种广泛用于计算机系统中的标准。但由于这种表示方式的限制,某些小数不能被精确地表示为二进制浮点数。

让我们深入了解为什么这会发生:

  1. 二进制表示:在计算机中,所有的数据都是以二进制形式存储的。而某些十进制小数在转换为二进制时会得到一个无限循环的小数。例如,十进制的 0.1 在二进制中的表示是一个无限循环的小数。

  2. 精度限制:由于双精度浮点数的存储空间是有限的(64位),所以只能存储该小数的前面几位。这意味着存储的值是原始值的一个近似值。

  3. 计算误差:当你将两个这样的近似值相加时,误差可能会累积,导致结果与预期不符。

具体来说,0.10.2 在二进制中都不能被精确表示。当它们被加在一起时,结果是一个接近 0.3 的数,但不完全等于 0.3。因此,当你在 JavaScript 中测试 0.1 + 0.2 === 0.3 时,结果是 false

为了避免这种问题,当处理浮点数计算并需要精确的结果时,开发者通常会使用特定的库或采用某种策略(如将值乘以一个大的整数,进行整数运算,然后再除以该整数)来确保计算的准确性。

什么是双精度浮点数

双精度浮点数是一种计算机编程中用于表示实数(即小数和整数)的数据类型。它是基于IEEE 754标准中定义的64位双精度表示法。这种表示法允许数字在非常大的范围内变化,同时还能保持相对的精度。以下是双精度浮点数的一些关键特点:

  1. 位数:双精度浮点数使用64位来存储一个数字。

  2. 组成

    • 符号位:1位,用于表示数字的正负。0表示正数,1表示负数。
    • 指数:11位,表示2的指数。这11位允许的范围是从-1022到1023(使用偏移量或偏置1023)。
    • 尾数(或称为分数部分):52位,表示数字的实际“有效数字”。
  3. 范围:双精度浮点数可以表示的范围大约是±5.0 × 10^−324 到 ±1.8 × 10^308。

  4. 精度:双精度浮点数可以精确到约15位十进制数字。

  5. 特殊值:IEEE 754定义了一些特殊的值,如正无穷、负无穷和NaN(非数字)。

  6. 存储方式:数字是以科学记数法的形式存储的,其中基数是2(即,它是一个二进制的科学记数法)。

在JavaScript中,Number类型就是使用双精度浮点数表示的。这意味着,尽管JavaScript可以处理非常大或非常小的数字,但由于双精度浮点数的限制,它可能无法精确地表示非常大的整数或非常接近0的小数。

需要注意的是,由于双精度浮点数的表示方式,某些数字可能无法精确表示。这就是为什么在JavaScript中,0.1 + 0.2 不等于 0.3 的原因。这是浮点数精度问题的一个常见例子,不仅在JavaScript中存在,而且在许多其他编程语言中也存在。

如果将数字都转换为二进制,0.1 + 0.2是如何计算的?

  1. 十进制转二进制

    • 0.1 在二进制中表示为:0.0001100110011001100110011001100110011001100110011001101...(无限循环)
    • 0.2 在二进制中表示为:0.001100110011001100110011001100110011001100110011001101...(无限循环)

    注意,这两个数在二进制中都是无限循环的。

  2. 双精度浮点数的存储
    在 JavaScript 中,数字是按照 IEEE 754 双精度浮点数格式存储的,这意味着它们有 64 位的空间。其中 1 位用于符号,11 位用于指数,剩下的 52 位用于尾数(实际有效数字)。由于存储空间是有限的,我们不能存储上述二进制小数的所有位。因此,我们只能存储它们的前 52 位(加上隐藏的第一位,总共 53 位的精度)。

  3. 计算
    当我们将这两个近似值相加时,结果是两个二进制小数的和。但由于它们都是近似值,所以和也是一个近似值。

    0.1 的近似二进制值(前 53 位):0.0001100110011001100110011001100110011001100110011001101

    0.2 的近似二进制值(前 53 位):0.001100110011001100110011001100110011001100110011001101

    将这两个值相加,我们得到:

    0.01001100110011001100110011001100110011001100110011001101

    这个值转换回十进制是 0.30000000000000004,而不是 0.3

因此,由于二进制表示的限制和双精度浮点数的有限精度,0.1 + 0.2 在 JavaScript 中的结果是 0.30000000000000004,而不是 0.3

0.1是如何转换为二级制数的?

将十进制小数转换为二进制小数涉及到一种称为“乘以2取整法”的方法。以下是将 0.1 转换为二进制的步骤:

步骤:

  1. 乘以2:
    将小数乘以2。对于 0.1,我们有:
    [0.1 \times 2 = 0.2]

  2. 取整数部分:
    记录整数部分(在这种情况下是 0),并保留小数部分(0.2)以进行下一步的计算。

  3. 重复步骤1和2:
    使用上一步留下的小数部分重复步骤1和2:
    0.2 * 2 = 0.4 (整数部分 0
    0.4 * 2 = 0.8 (整数部分 0
    0.8 * 2 = 1.6 (整数部分 1
    0.6 * 2 = 1.2 (整数部分 1
    0.2 * 2 = 0.4 (整数部分 0
    ...(这个过程会一直重复)

  4. 记录整数部分:
    记录每一步的整数部分。在这个例子中,我们得到的二进制小数是 0.00011001100110011...

结果:

因此,0.1 在二进制中是一个无限循环的小数:0.00011001100110011...

这是因为 0.1 不能被精确地表示为一个有限的二进制小数。在二进制系统中,只有像 1/20.5),1/40.25)或 1/80.125)这样的分数可以被精确表示,因为它们的分母是2的幂。而 0.11/10,它不能被二进制系统精确表示,所以它在二进制中是一个无限循环的小数。

结论

由于双精度浮点数的存储方式和二进制表示的限制,JavaScript中的某些浮点数运算可能会产生出乎意料的结果。为了避免这种情况,开发者在进行浮点数运算时应该特别小心,并考虑使用库或工具来帮助处理这种精度问题。

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

推荐阅读更多精彩内容