定点数与浮点数

这个页面或章节尚在编辑中。
请注意,部分内容可能尚未完成或存在错误。您也可以编辑页面帮助我们完善内容。

明日方舟作为一个使用Unity引擎打造的游戏,其使用的(代码)语言为C#。

其中用于表达“数值”的方式存在许多种类型,常见的有用于常规整数的整数(int)、用于跨度不是太大的极大/极小数的浮点数(float),同时明日方舟也定义了自己的新数值类型——定点数(FP)

而游戏中现存的许多数值计算问题(例如50发弹药的30%是16发弹药、造成1000点法术伤害并不能击倒0法抗1000血的敌人)均是由浮点数与定点数导致的。

浮点数

浮点数(float)是大部分编程语言中最常用的可以表示小数的一种数据类型,其采用IEEE-754标准。

顾名思义,浮点数依靠“浮动”其小数点来匹配数据大小的类型,本质上是依靠科学计数法(不过以2为底数)的指数和小数来存储数据
为便于简明理解,浮点数的记录方法可理解为“实际数值=倍率×2^指数”。
其指数的范围为-127~128,因此它可以存储极大的数值同时也可以存储极小的数值,但因数值大小的存储需求,它的基数(最小单位)也会从2^(-127)到2^128不等。

浮点数永远无法准确表述分母因子含非2质数的值(如0.1、0.01等),因此会因数值大小存在不同的误差。

浮点数类型在明日方舟的程序计算内已被大规模弃用,但其JSON数据库中仍以浮点数存储数据,导致误差仍然存在。

定点数

定点数(FP)是一种可用于定义含整数与小数部分的64位数据类型,在处理大部分数值时与浮点数比较类似,但最大的区别是其“小数点”固定,因此其取名“定点”数。为便于简明理解,定点数的记录方法可理解为“实际数值=基数×倍率”。

与整数类似,在定点数的定义中有固定的基数(最小单位),但不是1,而是\( 2 ^ {-32} = \frac{1}{2 ^ {32}} = \frac{1}{4294967296} \)。

一个定点数在程序中占用64位(比特),其内容分别为:第1位正负号,第2~63位为数值的绝对值,因此其上限是\( 2 ^ {63} * 2 ^ {-32} = 2 ^ {31} \)(2147483648)。

定点数数同样无法准确表述分母因子含非2质数的值(如0.1、0.01等),但不论整数部分大小,相同小数部分最终存在的误差都是相同的。

误差

浮点数在表达小跨度数值时有着极为广泛的数值范围(同一个位置可以存储超过千亿的数值也可以存储亿分之几的数值)。

定点数在表达大跨度数值时有着极为可靠的精确度(即使是跨度如2000000.03125也可以完美存储而无误差)。

但由于基数问题,定点数和浮点数只能准确表达分母为2的幂的数值(例如1/2、325/8、799/512、360/65536等)。在处理分母因子包含非2质数的数值时,定点数和浮点数将均无法准确处理。

而这些本该随IEEE-754标准而被淡化的误差,“可能”会在数据类型读取、转换、处理中完美的被继承到结果中上。有时甚至可能因处理逻辑上的“向上取整”和“向下取整”而被放大,导致呈现给玩家时的数值可能与理论值相差甚远的情况。
不过改用定点数的好处也是有的:浮点数的误差会随着数值的增大而增大,但定点数不论数值大小,其误差都是固定的。但,这一好处在明日方舟内混乱的数据类型使用中几乎可以被忽略,因为一个“数值”在来到玩家面前之前,可能已经经过了数轮浮点数、定点数、整数的转换。

常见误差样例

以下列出的是一些常见的数值小数部分的精确值(1和0在此作为对照),以及精确值比数学意义上的值更大/更小的状态,在判定较为严苛的环境下可能会直接导致“最终的数据”多1或少1。