rust - 如何检查大于 2 ^ 54 的 u64 数是否可被 f64 整除且精度损失最小?
问题描述
对于u64
小于 2 ^ 54 的数字,可以通过转换为f64
:
((6 as f64) % 1.5) < f64::EPSILON
对于较大的数字,将有显着的精度损失:
1u64 << 63 // 9223372036854775808
(1u64 << 63) as f64 // 9223372036854776000
并且将检查可除性以获得不同的数字。
上下文:JSONSchema 的multipleOf
关键字实现
问题:检查不适合尾数大小(即 53)的u64
/数字的可除性的最有效方法是什么?i64
f64
f64::MANTISSA_DIGITS
解决方案
这是一个给定的解决方案,它u
是一个整数,x
是一个有限的非零 IEEE-754 binary64 数,我们用它来进行 IEEE-754 算术。x
假定表示一个特定的数字,如 IEEE-754 所规定的,并且x
不考虑在获取时发生的先前舍入误差。这个答案涉及到所涉及的数学,而不是 Rust 语义,因为我不熟悉 Rust。
首先,找到x
= F
• 2的表示形式E
,其中F
是奇数且E
是整数。一个简单的方法是:
- 设置
F
为0x
和E
0。 - While
F
不是整数,乘以F
2 并从 中减去 1E
。 - 虽然
F
是偶数,但除以F
二并加一E
。
上述所有操作都可以在 IEEE-754 算术中执行,没有舍入误差。如果 Rust 提供了一种分离浮点数的有效数和指数的方法,类似于 C 的frexp
函数,那么将其合并到上述函数中可以提高效率。
现在考虑是否u
是x
= F
• 2的倍数E
。根据定义,当且仅当存在k
这样的整数u
= k
• F
• 2 E
。我们将看到当且仅当u
是F
并且 是 2 的倍数时才会如此E
,并且这些中的每一个都可以被测试。
如果 2E
是一个整数(E
非负数)并且k
存在这样的 a,则u
它是 2 的倍数F
并且是 2 的倍数E
。相反,如果u
不是 2 的倍数F
或不是 2 的倍数E
,则不k
存在(通过算术基本定理)。
F
必须在所请求的整数格式的范围内(最多为 53 位),我们假设F
可以转换为该格式。然后可以测试u
by 的整除性。F
如果 2E
超过了所表示的整数格式的最大值u
,则u
不是 2 的倍数E
。否则,E
可以将2转换为格式,可以测试u
被2整除的能力。E
如果 2E
不是整数(E
为负数),那么,如果需要k
存在(u
也是 的倍数F
),则它是 2 -<code>E的倍数。相反,如果k
不是 2 −<code>E的倍数,则k
• F
• 2E
不是整数,因此它不能等于u
。因此u
,x
当且仅当u
是 的倍数时,是 的倍数F
。
推荐阅读
- c++ - 如何创建一个类的唯一指针向量
- android-source - bash: build.env/: 尝试在 PC/ARM64 上构建/运行 Cuttlefish 时没有此类文件或目录错误
- c# - 在 JSON 中为每个列表项赋予不同的名称
- docker - 无法建立 Kafka 连接。经纪人可能不可用
- php - PHP无法连接到数据库
- javascript - 在 Next.js 中,序列化 getStaticProps 时出错?
- sql-server - 视图中的 MS SQL 事务
- python-3.x - 如何在 Python 中更新 GraphQL 请求中的变量?
- android - RecyclerView 在 Fragment 生命周期的哪个阶段准备就绪?
- javascript - 在 Swagger 上覆盖 onError 时如何在 Swagger_Controllers 中指定函数名称?