为什么不能将long / int用作小数(分数)?

时间:2019-04-04 11:55:55

标签: floating-point

在我的上一个项目(我在此处发布了一个问题)中,我对必须处理浮点数舍入误差感到非常恼火。舍入错误对我来说是个问题,因为我正在进行碰撞检测,而舍入舍入错误意味着我允许对象碰撞。我看到一些解决方案,但是需要猜测类型的解决方案。

A)人们可以忽略小的碰撞,但是您如何知道期望发生的碰撞量有多小?浮点的性质使舍入误差/精度难以预测,除了您知道小数部分的精度随着数字远离0而变小之外。

B)可以自动减去一小部分,以确保浮点舍入错误通常不会引起问题。此解决方案与上述解决方案具有相同的问题。

我决定采用解决方案B,因为它易于实施。我确实承认在进行此类计算之前可以通过转换为局部空间来解决舍入误差,但这对我来说并不是一个优雅的解决方案。

然后我开始考虑另一种解决方案,此解决方案从那时起一直形成一个完整的想法。为什么不将整数/长整数用作分数?这带来的优点是它将具有可预测的步进和舍入误差。一个int只能上升或下降1,因此您只需要担心这种步进。通常,这也将使各种行为更可预测。您无需考虑代码接收的输入类型,因为随着数字从0进一步变远,行为也不会改变。此外,如果我从有限的研究中没记错的话,浮点会占用大量CPU周期,虽然我认为int不会出现此类问题。

让我更深入地解释我的意思...

0b00000000000000001111111111111111111代表一个二进制数,通常为32位整数。但是,如果该二进制数中的1代表数字的小数部分,那么0b0000000000000000.1111111111111111111将代表一个非常非常接近1的数字。该方案将为数字的小数部分提供无符号的短精度等级,以及整个数字的带符号的短精度等级(是的,有点低)。如果在这里用长号表示小数,则两边的精度都是整数级,对于大多数需求而言,这通常绰绰有余。用于表示数字小数部分的位数也可以根据您的需要而变化,也就是整数48位,分数16位。

可能会有这样的代码实现,但是硬件实现会很酷并且效率更高。小数部分的可变精度可能很困难,但是其余的听起来对我来说确实可行。告诉我我所做的假设是否有误,以及是否有某种原因不存在(或者如果存在,则称为什么)?我不能成为第一个想到这个的人。如果不是很明显,我来

1 个答案:

答案 0 :(得分:1)

您所描述的东西被称为“定点”,并且使用非常频繁。不过有一些问题:

  • 与浮点(duh)相比,它的范围很小。
  • 它本质上不比浮点数更精确。如果使用定点表示,则0.5 + 0.25将完全等于0.75,但对于浮点情况也是如此。 32位浮点数不能准确表示10^10 - 1,但32位定点数也不能准确表示(因为它不能表示至少一个值)。同样,定点数的1/3不会比浮点数的精确。

浮点错误是由浮点数之间的间隙引起的,但是定点数也有间隙,并且任何两个连续的浮点数之间的中值间隙与任何两个连续的定点数之间的中值间隙大致相同(假设它们的中值也大致相同,在您的示例中就是这种情况。

关于硬件实现:您已经拥有一个!定点类型上的所有算术运算都可以直接用整数模拟。 (实际上,可以直接使用加法和减法。)诸如平方根和三角函数之类的函数会变得更毛茸茸,但是只要您的浮点类型的尾数大到足以存储一个定点数即可(例如double用于存储32位定点数),您也可以利用该硬件。

您还提到了使用大小可变的类型。在某些情况下,它们可能会派上用场,但并不常见:IME,数值应用程序中数据类型所需的范围往往不是“那么大”或“基本上是无限的”。而且无论分数多大,您都将无法存储1/3。