You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

R语言中floor函数为何不总是返回乘法运算的预期结果?及正确计算方法咨询

为啥R里floor(0.57*100)会得到56?

先看看你遇到的这些奇怪现象:

直接对整数用floor()完全正常:

floor(c(50, 55, 56, 57, 58)) 
#> [1] 50 55 56 57 58

但换成小数乘100的结果,就出问题了:

floor(c(0.5*100, 0.55*100, 0.56*100, 0.57*100, 0.58*100)) 
#> [1] 50 55 56 56 57

不管怎么调整括号、先赋值给变量,结果都一样:

floor(c(0.5, 0.55, 0.56, 0.57, 0.58)*100) 
#> [1] 50 55 56 56 57

floor(c((0.5*100), (0.55*100), (0.56*100), (0.57*100), (0.58*100))) 
#> [1] 50 55 56 56 57

x <- 0.57*100
floor(x) 
#> [1] 56

甚至在0到100的范围内,还有不少数字有类似的问题:

x <- diff(floor(seq(0, 1, 0.01)*100))
names(x) <- seq(0, 0.99, 0.01)*100
x
#> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 
#> 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
#> 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 
#> 1 1 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
#> 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 
#> 1 1 1 1 1 0 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
#> 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
#> 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

问题根源:二进制浮点数的精度误差

其实这不是R的bug,而是计算机存储浮点数的固有特性在搞鬼。

我们日常用的是十进制,但计算机底层用的是二进制。很多十进制小数(比如0.57)没办法转换成精确的二进制小数——就像我们没法用十进制精确表示1/3(0.3333...无限循环)一样。所以0.57在计算机里只能被存储成一个近似值,当你计算0.57*100时,实际得到的并不是精确的57,而是一个非常接近57但稍微小一点的数:你可以直接在R里输入0.57*100,会看到输出是56.99999999999999

floor()函数的作用是取不大于输入值的最大整数,面对56.99999999999999,自然就返回56了。

怎么正确得到预期的floor结果?

如果你必须先完成乘法运算再传入floor(),有几种方法可以修正这个精度误差:

  1. 先四舍五入到足够多的小数位
    round()把乘法结果修正到接近真实值,再用floor()

    floor(round(0.57*100, 10))
    #> [1] 57
    

    这里取10位小数足够修正浮点数的微小误差了。

  2. 使用十进制小数类型
    可以用decimal包来处理十进制的精确计算,避免二进制浮点数的误差:

    library(decimal)
    floor(decimal("0.57") * 100)
    #> [1] 57
    
  3. 用有效数字修正
    signif()保留足够的有效数字,修正精度问题:

    floor(signif(0.57*100, 15))
    #> [1] 57
    

内容的提问来源于stack exchange,提问作者Mikko

火山引擎 最新活动