首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

求助众位前辈,19.99 * 100 - 1999 算式为什么结果是-2.2737367544323E-13 ?

  •  
  •   qq292382270 · 31 天前 · 2000 次点击
    这是一个创建于 31 天前的主题,其中的信息可能已经有所发展或是发生改变。

    脑壳疼,测试段代码需要用到个算式 : 19.99 * 100 - 1999,结果为-2.2737367544323E-13;
    算式中的 19.99 可以以变量形式传递进来,也还是这个结果. 用 19.98100-1998(或其他两位小数的数字减去它乘 100 的数字) 都正常为 0.
    算式在 java php js 中都为这个结果,感觉 19.99 好诡异,各位前辈有遇到过这样的情况么,有没有好的解决方案来避免.目前我的测试是用命令(php) sprintf("%.0f", 19.99
    100)才能正常执行..
    (咦~好奇怪,上面这段文本突然斜体了...)

    20 回复  |  直到 2019-07-23 14:27:28 +08:00
        1
    limuyan44   31 天前 via Android   ♥ 1
    java 中有专门用于高精度计算的类型,php 料想应该也有,通常涉及浮点型本身就是近似计算。
        2
    ipwx   31 天前   ♥ 1
    月经问题。。。

    内存中浮点数是二进制存储的。一个有限十进制小数不一定存在对应的有限二进制小数。事实上除了能写成“某个整数 + sum_{i=1}^k a_i 2^{-i}”这种形式的小数,都不能写成有限的二进制小数。

    而计算机的浮点数有长度限制,一个无限循环二进制小数截断以后,就和原来的十进制小数并不完全相等了。你减出来的这个值,就是截断误差。
        3
    johnniang   31 天前 via Android   ♥ 1
    建议看看 《计算机组成原理》。
        4
    Rekkles   31 天前   ♥ 1
    php 请用 bcmath
    echo bcsubbcmul(19.99,100,2),1999);
        5
    Raymon111111   31 天前   ♥ 1
    简单讲

    你看见的 19.99 十进制下人畜无害, 有可能在二进制下是一个无限循环小数 (可以自己做一下进制转换)

    这样一来, 就算乘以 100 和后面的数相减也得不到 0
        6
    ClericPy   31 天前   ♥ 1
    搜一下 浮点数 IEEE
        7
    laodao1990   31 天前   ♥ 1
    推荐看看《深入理解计算机系统》
    通俗点解释就是,计算机是用二进制表示的,对于某些小数和人类用 10 进制无法准确表示 1/3 是一个意思,会有误差。
        8
    VDimos   31 天前 via Android   ♥ 1
    真—月经问题
        9
    Kirscheis   31 天前 via Android   ♥ 3
    f64(19.99) = 0x1.3fd70a3d70a3dp+4

    f64(100.0) = 0x1.9000000000000p+6

    0x1.3fd70a3d70a3dp+4 * 0x1.9000000000000p+6 = 0x1.f3bffffffffffp+10

    f64(1999.0) = 0x1.f3c0000000000p+10

    所以结果是

    0x1.f3c0000000000p+10 - 0x1.f3bffffffffffp+10 = -0x1.0000000000000p-42

    转换到 10 进制就是 -2.2737367544323206e-13
        10
    Kirscheis   31 天前 via Android
    上面打多一个负号,凑合看
        11
    joshu   31 天前 via Android   ♥ 1
    浮点数的比较一般是小于 1e-N ( N 多少我忘了)就视为相等
    不要比较浮点数相等
        12
    akazure   31 天前 via Android   ♥ 1
    一般采取新建一个 equal 方法,并定义一个极小量,以作为误差范围。
        13
    jamesliu96   31 天前 via Android   ♥ 1
    IEEE 754
        14
    Mistwave   31 天前 via iPhone   ♥ 1
        15
    littlewing   31 天前   ♥ 1
    手动搜索 “ IEEE754 浮点数”
        16
    heart4lor   31 天前   ♥ 1
    浮点数存储问题都不知道的么,斜体是因为 markdown 语法
        17
    xuanbg   31 天前   ♥ 1
    一般的业务场景有小数的时候不要用浮点数,不要用浮点数,不要用浮点数。重要的事情说 3 遍。因为我们默认计算的结果是精确的,而浮点数是有精度问题的,不能满足精确的要求。
        18
    msg7086   31 天前   ♥ 1
    小数通常是近似值不是精确值。
        19
    TobiahShaw   31 天前   ♥ 1
    因为不连续,你可以判断 19.99 * 100 - 1999 < Epsilon,或者使用 BigDecimal
        20
    brust   30 天前   ♥ 1
    精度问题 浮点数 计算会丢失精度
    java 的话推荐<码出高效>这本书
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   4231 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 30ms · UTC 02:09 · PVG 10:09 · LAX 19:09 · JFK 22:09
    ♥ Do have faith in what you're doing.