Unity3D研究院之被坑了的浮点数的精度

Unity3D研究院之被坑了的浮点数的精度

正文

最近被浮点数坑了,所以一定要写篇文章记录下。先看看如下代码。

Debug.Log(sizeof(float)); //4字节
Debug.Log(sizeof(uint));  //4字节
Debug.Log(float.MaxValue > uint.MaxValue); //true

通过上面代码,我们可以发现floatuint(为了取最大值,这里就用无符号整形)都是4字节,那么为什么float的取值范围要比int大呢?继续再看一段代码。

Debug.LogFormat("{0}至{1}", float.MinValue, float.MaxValue);//取值范围: -3.402823E+38至3.402823E+38
Debug.LogFormat("{0}至{1}", int.MinValue, int.MaxValue);//取值范围: -2147483648至2147483647
Debug.LogFormat("{0}至{1}", uint.MinValue, uint.MaxValue);//取值范围: 0至4294967295

如果有人不知道 取值范围 -3.402823E+38-3.402823E+38 其中的E+38的含义我这里解释一下
-3.402823E+38 等价于 -3.402823*10^38(10的38次方)取值范围-3.402823E+383.402823E+38 也就等价于-340282300000000000000000000000000000000 至 340282300000000000000000000000000000000。
看到这里大家应该心里有点明白了吧?float的最大值340282300000000000000000000000000000000完全秒杀int的最大值4294967295
在回到文章开头的代码,float占4字节int也占4字节 ,此刻你的内心是否有个疑问?为什么差这么多?
首先咱先看看int4字节 (1个字节8位,4字节就是32位)也就表示它由32位保存 也就是它的最大值是 2^32(2的32次方)=4294967296(大家可以拿起计算器算一下是不是这个值)
同样的float 4字节 也表示它由32位保存那么凭什么它能存3.402823E+38这么大的数呢?机器不会骗人,原因就是它不是按int这么存数据的。比如一个float 数据
1024.1024 等价于 1.0241024 * 10^3 (3表示指数,1.0241024表示有效数字)float其实只是把符号、指数、有效数字3部分保存,真正在运算的时候是根据指数在移位操作。
float把32位分成了3部分,1位(符号位)8位(指数位)23位(有效数字)那么 1+ 8 + 23 等于32吧,所以float的32位是这么来的。23位有效数字就表示float真正能存的精度,23位小数部分是反被储存的部分,所以它是有24位存储的,2^24(2的24次方)=16777216 ,请大家记住这个数值,下面我们在做个试验

float a = 16777216f;
float b = a + 0.01f;
Debug.Log(a);//1.677722E+07
Debug.Log(b);//1.677722E+07

读完代码,如果你的程序中有一个float的数值运算后的小数部分,如果超过16777216.xxx那么很抱歉它们的结果是一致的。
float我们介绍完了,double的原理和float差不多,double占8字节,1位符号位+11位指数+52位有效数字 = 64位。double的有效2^53(2的53次方)=9007199254740992,超过9007199254740992.xxx那么很抱歉它们的结果是一致的。

double a = 9007199254740992f;
double b = a + 0.01f;
Debug.Log(a);//9.00719925474099E+15
Debug.Log(b);//9.00719925474099E+15
  • 1-12字节:它先用前12个字节来表示定点数数据,1字节8位,12个字节就是8*12 =96位,那么它的取值范围就是2^96(2的96次方)7.922816251426E+28
  • 13-15字节:在用3个字节来表示指数
  • 16字节:最后一个字节来表示符号
decimal a = 79228162514264337593543950335m;
decimal a1 = 7.9228162514264337593543950335m;
decimal a2 = 79.228162514264337593543950335m;
decimal a3 = 792.28162514264337593543950335m;
decimal a4 = 7922.8162514264337593543950335m;
decimal a5 = 79228.162514264337593543950335m;
 
Debug.Log(a);
Debug.Log(a1);
Debug.Log(a2);
Debug.Log(a3);
Debug.Log(a4);
Debug.Log(a5);


只要数据在10进制28-29位之间,小数点在中间任意位置均可。数据运算就不会像floatdouble一样被和谐了。所以说如果需要准确精度的小数计算就一定要使用定点数。
最后欢迎大家提出意见或者建议。

原文链接

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值