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

Floating point 为什么long/int不能用作小数(分数)?,floating-point,Floating Point,在我以前的一个项目中,我在这里发布了一个问题,我非常恼火地意识到我必须处理浮点数中的舍入错误。舍入误差对我来说是个问题,因为我正在进行碰撞检测,而允许舍入误差舍入意味着我允许对象碰撞。我看到了一些解决方案,但需要猜测式的解决方案 一个人可以忽略小的碰撞,但是你怎么知道预期的碰撞有多小呢?浮点的性质使得舍入误差/精度很难预测,除非您知道小数部分的精度随着数字远离0而变小 B人们可以自动减去一个小数字,以确保浮点舍入误差通常不会引起问题。此解决方案的问题与上述解决方案相同 我决定采用解决方案B,因为

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

一个人可以忽略小的碰撞,但是你怎么知道预期的碰撞有多小呢?浮点的性质使得舍入误差/精度很难预测,除非您知道小数部分的精度随着数字远离0而变小

B人们可以自动减去一个小数字,以确保浮点舍入误差通常不会引起问题。此解决方案的问题与上述解决方案相同

我决定采用解决方案B,因为它更容易实现。我承认,在进行这种计算之前,通过将舍入误差转换到局部空间,可以在某种程度上解决舍入误差,但对我来说,这并不是一个优雅的解决方案

然后,我开始考虑另一个解决方案,从那时起,这个解决方案最终形成了一个完整的想法。为什么整数/长数不能用作分数?这带来的好处是,它将具有可预测的步进和舍入误差。整数只能上下移动1,因此您只需担心这种步进。这也将使各种行为在总体上更加可预测。您不必考虑代码接收的输入类型,因为行为不会随着数字从0变远而改变。另外,如果我在有限的研究中没有记错的话,浮点运算可能会占用大量的CPU周期,而我认为INT不会有这样的问题

让我更深入地解释一下我的意思

0B0000000000000000111111111表示通常为32位整数的二进制数。但是如果二进制数中的1代表一个数字的小数部分,那么0b0000000000000000.1111111111111将代表一个非常接近1的数字。这个方案将给出数字小数部分的无符号短精度,以及数字整部分的有符号短精度是的,有点低。如果在这里使用long表示小数,则两边的精度都将是整数级别,这通常足以满足大多数需要。用于表示数字的小数部分的位数也可以是可变的,这取决于您需要什么,即48位表示整数,16位表示小数部分


可能会有这样的代码实现,但硬件实现会很酷,而且可能会更有效。分数的可变精度可能很难,但其余的听起来对我来说非常可行。告诉我,如果我所做的假设是错误的,如果这是不存在的原因,或者如果它存在,它叫什么?我不是第一个想到这个的人。如果不明显的话,我来告诉你,你所描述的被称为固定点,它被频繁使用。但也有一些问题:

与浮点duh相比,它的范围很小。 它本质上并不比浮点更精确。如果使用定点表示,0.5+0.25将正好等于0.75,但浮点也是如此。32位浮点数不能准确表示10^10-1,但32位固定点数也不能,因为它不能表示至少一个值。同样,1/3在定点中的精度不会比在浮点中的精度高。 浮点数误差源于浮点数之间的间隙,但固定点数也有间隙,假设任意两个连续浮点数的中值也大致相同,则任意两个连续浮点数之间的中值间隙与任意两个连续固定点数之间的中值间隙大致相同,你的例子就是这样

至于硬件实现:您已经有了一个!所有定点类型的算术运算都可以直接用整数模拟。事实上,加法和减法可以在没有任何变化的情况下使用。像平方根和三角函数这样的东西会变得有点复杂,但只要你有一个尾数足够大的浮点类型来存储一个固定点号,例如,一个双精度来存储一个32位的固定点号,你也可以利用这个硬件

您还提到了可变大小类型的使用。这些在某些情况下很有用,但它们并不常见:IME,数值应用程序中数据类型所需的范围往往不是很大,或者基本上是infi
黑夜。无论分数有多大,你都无法存储1/3。

运动有多准确?双精度允许高达14-15位的精度。即使有不断累积的误差,我想这对于大多数目的来说已经足够好了,即使是在宇宙尺度上。只需确保你的计算不会累积太多错误。FWIW,您描述的是一种非常有限的固定点格式。已经做了很多次了,但我想硬件支持的Double速度更快、更可靠、更精确,足以满足大多数目的,甚至可能是您的目的。它们允许你使用正弦、余弦和其他三角函数。FWIW,据我所知,没有固定点格式的硬件实现,但如果有,它们可能在普通硬件上找不到。FWIW,您描述的定点格式具有非常有限的范围-32768..0..+32767,步长为0.0000152587890625,请注意,任何乘法、除法、三角函数的计算都需要舍入,其效果比仅1/65536的FP舍入精度差得多。我真的建议你使用double,如果你已经准备好了,试着把double改成single/float,看看这是否足够好。您可能会发现它比您有限的定点类型要好得多。@RudyVelthuis感谢您的回复,我知道如果您使用32位整数,范围将非常糟糕,但是如果您使用64位整数,范围将非常大,正如我在上文的文字墙中所述。不管怎样,我想使用double,但我在该程序中设置了我的整个定位系统,使用32位浮点,因为我认为OpenGL不支持double,而且我讨厌每次处理OpenGL时都从double转换为float。我发现浮点分数是非常有限的,但是double有太多的,对于许多应用来说,它感觉是无限的。是的,范围会更好一些,但是仍然会有同样的问题。但是,嘿,试试看。发明你自己的例程,做很多工作,然后将它与硬件支持的double进行比较,你会发现你做了很多工作都是徒劳的。固定点很好,但非常有限,您只能依靠自己。猜猜为什么没有这种类型的硬件版本。毕竟,这个想法并不新鲜。感谢您提供的信息,我确实意识到了上面提到的挫折,但与固定点在某些场景中可能带来的优势相比,这些挫折有时似乎无关紧要。我刚刚想到的另一个解决方案是,如果有一种方法可以使舍入误差总是导致舍入,对于那个特定的计算。一个64位的固定点数几乎没有32位的固定点数的限制,因为对于大多数需求,分数大约40亿个可能的数字是相当大的。其优点只是想象出来的。但是试试看。做这项工作并进行比较。你会非常失望的。我怎么知道?猜测