Lua 精度问题

https://blog.csdn.net/allenjay11/article/details/53485777

浮点数问题

math.floor(0.57*100)
56

这是浮点数都会有的精度丢失问题,lua也有这个问题。

原因是因为浮点数的再cpu上的表示不同cpu表示不一样的。
而为什么是0.57,而其他很多数没影响呢?
可以看连接:https://zhuanlan.zhihu.com/p/269619376

因此十进制下的0.2无法被精确表示成二进制小数,这也是为什么十进制小数转换成二进制小数时会出现精度损失的情况。
也就是说0.57也是无法精准表示成二进制小数的,在不同平台下截断不一样(这个未验证)

重点:这个如果要验证可以通过

print(string.format("%0.99f", 57/100*100))
不要超过100位,因为stringfomat只支持99.。。太多会报错

打印出来
目前unityeditor下


image.png

可以看到具体他在lua中double的具体样子。
BTW,1的表示还是1

也即是说要测试是否有浮点数精度问题,那么通过这个方法打印即可,不然很多其他函数会有四舍五入的情况发生的,就不好验证了。

也就是说如果是lua上看起来是整数的就不会存在精度问题?

其实是对的,但是如果要运算了出现了带小数点的,那么就无法保证了。
下面的代码验证了:

local a = 57
print(math.floor(a/100*100))

结果还是56.。。。
而print(math.floor(a*100/100))
的结果是57就对了。 也就是运算过程中出现了不可表达的浮点数,那么必定会带来精度损失的问题。

再看下整数与浮点数的比较:

=10==10.00000000000000000
true
=10==10.00000000000000001
true
=10==10.00000000000000000
true
=10==9.999999999999999999
true

如何比较两个浮点数是否相等?这里介绍一个方法:

  1. function float_equal(x,v)

  2. local EPSILON = 0.000001

  3. return ((v - EPSILON) < x) and (x <( v + EPSILON))

  4. end

  5. print(float_equal(0.9999999, 1.0000001))

其中,EPSILON就是你允许的精度差

lua整数

在lua5.3之前,lua没有整数,都是用浮点数表示的,最早的版本用float,然后在3.1之后改用double。直到lua5.3,lua才引入了整数,默认是64bit。既然之前的lua版本用到的是浮点数,那必然有精度问题,浮点数需要一部分位来表示指数,double的有效数字是53bit,能表达的最大的有效整数是6755399441055744,而lua5.3能表达的最大整数是 9223372036854775807

至于为什么是6755399441055744,有兴趣的可以看下寂寞同学写的浮点数到整数的快速转换,还有一篇国外的文档 Let's Get to the (Floating)Point

自己案例

装备属性计算的时候,经常会差个1,原因就在于浮点数的精度丢失问题
local MyFloor = function(v)
return math.floor(v + 0.000001)
end

Unity lua5.1

没法判断一个浮点数是不是带小数点后的

local checkhasfloat = function(a)
    if math.floor(a) ~= a then
        print("not a int:"..string.format("%0.99f", a))
    end
end

checkhasfloat(1)
checkhasfloat(0.99999999999)

例如这个就不会打印出来,因为math.floor(0.99999999999) = 1
这就很蛋疼了。

不过可以使用modf

local checkhasfloat = function(a)
    local pre, after = math.modf(a)
    print("------checkhasfloat------")
    print(pre)
end

checkhasfloat(1)
checkhasfloat(0.99999999999)
image.png

结果就很完美。
更完善点,判断负数的情况

local checkhasfloat = function(a)
    local pre, after = math.modf(a)
    print("------checkhasfloat------")
    print(pre)
    if after > 0 or after < 0 then
        print("------has dot after val------")
        print(string.format("%0.99f", after))
    end
end

checkhasfloat(1)
checkhasfloat(-0.0000000000000001)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容