我用floats
来表示游戏中的位置:
struct Position
{
float x;
float y;
};
我想知道这是否是最佳选择,以及随着头寸价值的不断增长,后果会是什么。我花了一些时间复习一下浮标是如何存储的,并意识到我有点困惑。
(我正在使用Microsoft Visual C++编译器。
在float.h
中,FLT_MAX
定义如下:
#define FLT_MAX 3.402823466e+38F /* max value */
这是340282346600000000000000000000000000000
.
该值远大于UINT_MAX
定义为:
#define UINT_MAX 0xffffffff
并对应于值4294967295
。
基于此,似乎float
存储非常大的数字(如仓位)是一个不错的选择。尽管FLT_MAX
非常大,但我想知道精度问题将如何发挥作用。
根据我的理解,一个float
用 1 位来存储符号,8 位来存储指数,用 23 位来存储尾数(假设前导为 1):
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
这意味着FLT_MAX
可能如下所示:
0 11111111 11111111111111111111111
这相当于:
1.11111111111111111111111 x 2^128
或
111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
即使知道这一点,我也很难想象精度的损失,并且随着值的不断增加,我感到困惑。
有没有更简单的方法来思考这个问题?floats
或doubles
通常用于在unsigned int
之类的东西上存储非常大的数字吗?
考虑浮点精度的一种方法是考虑它们具有大约 5 位精度。因此,如果你的单位是米,而你有1公里外的东西,那就是1000米 - 试图以10厘米(0.1米)或更小的分辨率处理该物体可能会有问题。
游戏中的常用方法是使用浮点数,但要划分世界,使位置相对于局部坐标系(例如,将世界划分为一个网格,并且每个网格正方形都有一个平移值)。一切都将具有足够的精度,直到它相对于相机进行渲染转换,此时远处事物的不精确性不是问题。
举个例子,想象一个以太阳系为背景的游戏。如果坐标系的原点位于太阳的中心,那么行星表面的坐标将无法在浮标中准确表示。但是,如果你有一个相对于行星表面的坐标系,而这个坐标系又是相对于行星的中心,然后你知道行星相对于太阳的位置,你可以精确地对局部空间中的事物进行操作,然后转换为你想要渲染的任何空间。
不,他们不是。
假设自游戏对象移动以来,您的位置需要为某个帧增加 10 厘米。
假设游戏世界以米为单位缩放,则为 0.10。但是,如果您的float
值足够大,它将无法再表示 0.10 的差异,并且您增加该值的尝试将失败。
您是否需要存储大于 16.7m 的值和小数部分? 那么浮点数就会太小。
布鲁斯·道森(Bruce Dawson)的这个系列可能会有所帮助。
如果您确实需要处理非常大的数字,请考虑使用任意精度的算术库。您必须分析代码,因为这些库比内置类型的算术慢。
您可能实际上并不需要非常大的坐标值。例如,您可以环绕世界的边缘,并使用模算术来处理位置。