Unity3D研究院之被坑了的浮点数的精度(一百零三)

栏目: 后端 · 发布时间: 5年前

内容简介:最近被浮点数坑了,所以一定要写篇文章记录下。先看看如下代码通过上面代码,我们可以发现float和uint(为了取最大值,这里就用无符号整形)都是4字节,那么为什么float的取值范围要比int大呢?继续再看一段代码如果有人不知道 取值范围 -3.402823E+38-3.402823E+38 其中的E+38的含义我这里解释一下

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

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

通过上面代码,我们可以发现float和uint(为了取最大值,这里就用无符号整形)都是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+38 – 3.402823E+38 也就等价于

-340282300000000000000000000000000000000 至 340282300000000000000000000000000000000

看到这里大家应该心里有点明白了吧?float的最大值340282300000000000000000000000000000000完全秒杀int的最大值4294967295

在回到文章开头的代码,float占4字节int也占4字节 ,此刻你的内心是否有个疑问?为什么差这么多?

首先咱先看看int 4字节 (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

而且浮点数计算结果不同的CPU计算出来可能是不一致的,像帧同步那种游戏基本应该告别float和double了。

最后我们在聊一下定点数,应对解决精度问题,c#提供了定点数decimal关键字。可以看到它是由16个字节组成也就是64位,内存大小相当于4个float或者2个double 取值范围也很高。

Debug.Log(sizeof(decimal)); //16
Debug.Log(decimal.MaxValue);//79228162514264337593543950335
Debug.Log(decimal.MinValue);//-79228162514264337593543950335

1-12字节:它先用前12个字节来表示定点数数据,1字节4位,12个字节就是4*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);

Unity3D研究院之被坑了的浮点数的精度(一百零三)

只要数据在10进制28-29位之间,小数点在中间任意位置均可。数据运算就不会像float和double一样被和谐了。所以说如果需要准确精度的小数计算就一定要使用定点数。

最后欢迎大家提出意见或者建议。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

高性能JavaScript

高性能JavaScript

【美】Nicholas C. Zakas(尼古拉斯.泽卡斯) / 丁琛 / 电子工业出版社 / 2015-8-1 / 65

如果你使用 JavaScript 构建交互丰富的 Web 应用,那么 JavaScript 代码可能是造成你的Web应用速度变慢的主要原因。《高性能JavaScript》揭示的技术和策略能帮助你在开发过程中消除性能瓶颈。你将会了解如何提升各方面的性能,包括代码的加载、运行、DOM 交互、页面生存周期等。雅虎的前端工程师 Nicholas C. Zakas 和其他五位 JavaScript 专家介绍......一起来看看 《高性能JavaScript》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具