Rust 如何在精度损失最小的情况下检查大于2^54的u64数是否可以被f64整除?

Rust 如何在精度损失最小的情况下检查大于2^54的u64数是否可以被f64整除?,rust,floating-point,precision,Rust,Floating Point,Precision,对于小于2^54的u64编号,可以通过铸造到f64,而不会造成太多精度损失: ((6为f64)%1.5)考虑 u>代码>是代码> x = f>代码>的倍数。2代码代码>。根据定义,当且仅当存在整数k时,u=k•F•2E。当且仅当u是F的倍数,并且是2E的倍数时,我们才会看到这一点,并且每个都可以测试 如果2E是整数(E是非负的),并且存在这样的k,那么u是F的倍数,是2E的倍数。相反,如果u不是F的倍数或不是2E的倍数,则不存在这样的k(通过算术基本定理) F必须在请求的整数格式的范围内(最多

对于小于2^54的
u64
编号,可以通过铸造到
f64
,而不会造成太多精度损失:

((6为f64)%1.5)
对于较大的数字,将有显著的精度损失:


1u64这里有一个解决方案,假设
u
是一个整数,
x
是一个有限的非零IEEE-754二进制64数,我们使用它进行IEEE-754算术<根据IEEE-754的规定,假定code>x
代表一个特定数字,并且不考虑在获取
x
时出现的先前舍入误差。这个答案涉及到相关的数学,而不是锈的语义,因为我不熟悉锈

首先,找到
x
=
F
•2
E
的表示形式,其中
F
是奇数整数,
E
是整数。一个简单的方法是:

  • F
    设置为
    x
    并将
    E
    设置为0
  • F
    不是整数时,将
    F
    乘以2,然后从
    E
    中减去1
  • F
    为偶数时,将
    F
    除以2,然后将1添加到
    E
以上所有操作都可以在IEEE-754算法中执行,没有舍入误差。如果Rust提供了一种分离浮点数的有效位和指数的方法,类似于C的
frexp
函数,那么将其合并到上述函数中可以提高效率

>考虑<代码> u>代码>是代码> x = <代码> f>代码>的倍数。2代码<代码>代码>。根据定义,当且仅当存在整数

k
时,
u
=
k
F
•2
E
。当且仅当
u
F
的倍数,并且是2
E
的倍数时,我们才会看到这一点,并且每个都可以测试

如果2
E
是整数(
E
是非负的),并且存在这样的
k
,那么
u
F
的倍数,是2
E
的倍数。相反,如果
u
不是
F
的倍数或不是2
E
的倍数,则不存在这样的
k
(通过算术基本定理)

F
必须在请求的整数格式的范围内(最多53位),我们假设
F
可以转换为该格式。然后可以测试
u
F
整除。如果2
E
超过表示
u
的整数格式的最大值,则
u
不是2
E
的倍数。否则,可以将2
E
转换为格式,并且可以测试
u
被2
E
整除的情况


如果2
E
不是整数(
E
为负),那么,如果所需的
k
存在(因此
u
F
的倍数),则它是2的倍数−<代码>E
。相反,如果
k
不是2的倍数−
E
,则
k
F
•2
E
不是整数,因此它不能等于
u
。因此,
u
x的倍数
当且仅当
u
F的倍数

这个问题表明你将
f64
视为无限精确,对吗?哦,我会纠正这个问题,我的意思是-以最小的精度损失这首先是一件值得怀疑的事情。我不认为您的示例实现可以精确表示整数的情况是您想要的。即使您尽可能精确地表示可表示为f64的整数a和b的商,由于各种原因,
a%q
可能比浮点类型的ε大得多。即使在这种情况下也很难做到这一点。因此,在任何情况下,舍入和限制到
u64
f64
都是不符合要求的。您需要将序列化JSON中的所有数字视为精确的,并对它们执行任意精度算术,而不进行任何舍入或ε。您选择的用于演示精度损失的特定示例实际上并不涉及任何值的更改<代码>(1u64