R语言循环内外取余结果不一致的诡异问题求助
浮点数精度误差导致的取余结果不一致问题
嗨,这个问题其实是双精度浮点数的精度误差导致的经典“坑”,我来给你拆解清楚:
问题根源
R里的数值默认是双精度浮点数,而像3.6这样的十进制小数,没办法用二进制浮点数精确表示(就像十进制里你永远写不完1/3的小数一样)。当你在循环里每次累加3.6时,每次都会产生一点点微小的舍入误差,这些误差积累到65次之后,看起来x的打印值是234,但它实际存储的是一个非常接近234但略小于234的数(比如用sprintf("%.20f", x)可以看到真实值大概是233.99999999999994315658)。
这时候计算x%%6.5时,R会找最大的不超过x的6.5的倍数:6.5×36=234,但因为x略小于234,所以只能取6.5×35=227.5,用x减去这个值得到的结果就是≈6.49999999999994,而R为了显示友好,把它近似成了6.5,自然判断x%%6.5==0就是FALSE。
而你直接赋值x=234时,234是整数,可以被双精度浮点数精确表示,所以x%%6.5的结果就是精确的0,判断为TRUE。
解决方案
这里有两个实用的解决办法:
1. 用整数运算避免浮点数误差
把所有参与运算的数值都放大为整数,累加完成后再缩小回去,从根源上避免精度问题:
x=0 for (i in 1:100){ x=x+36 # 将3.6放大10倍变成整数36 if (i==65){ print(x/10) print((x/10)%%6.5==0) print((x/10)%%6.5) } if((x/10)%%6.5==0){ break } }
2. 用阈值判断代替精确相等
浮点数判断相等时,不要直接用==,而是判断差值是否小于一个极小的阈值(比如1e-10),忽略微小的精度误差:
x=0 for (i in 1:100){ x=x+3.6 if (i==65){ print(x) print(abs(x%%6.5) < 1e-10) # 用阈值判断 print(x%%6.5) } if(abs(x%%6.5) < 1e-10){ break } }
你可以自己试一下用sprintf("%.20f", x)查看循环中x的真实值,就能直观看到这个精度误差啦!
内容的提问来源于stack exchange,提问作者goto
相关产品推荐
相关产品推荐

