【问题标题】:Why this algorithm to determine is divisible or not work?为什么这个算法来判断是整除还是不行?
【发布时间】:2020-10-07 01:34:00
【问题描述】:
static inline bool is_divisible(uint32_t n, uint64_t M) {
    return n * M <= M - 1;
}

static uint64_t M3 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 3 + 1;
....
uint8_t div3 = is_divisible(17, M3);

正如标题中提到的,这个函数可以判断n是否能被3整除。 我唯一知道的是Mceil((1&lt;&lt;64)/d) 相同,d 是 3。

有没有人打电话解释为什么is_divisible 工作?谢谢!

【问题讨论】:

  • 这似乎依赖于整数溢出。我看不出这比使用简单的模运算符更好。
  • @paddy 除法运算对处理器来说代价高昂。乘法更便宜。 M3 也可以在运行前被删除。
  • @Steven 是的,但是如果你把函数改成return n % 3 == 0;,优化器无论如何都会把除法转换成乘法,所以不需要这段代码。
  • 提示:找出 2*M33*M3 是什么。然后将您的号码写为n=3*x+y,其中y012。使用算术属性,确定n*M3 可能是什么,以及何时小于M3-1
  • 确实使用这些优化通常hinders the good compilers from generating effective code。只需使用M3 % 17 并让编译器计算出来

标签: c math


【解决方案1】:

n除以3得到商q和余数r,让我们将n表示为n = 3q + r,其中 0 ≤ r

直观地说,3q + r 乘以 (264−1)/3 + 1 会导致 q em> 部分消失,因为它包含模 264,剩余部分位于 [0, 264) 的三个段之一中,具体取决于 64) 的值em>r。与M3的比较判断是否在第一段,即r为零。证明如下。

请注意,M3 为 (264−1)/3 + 1。

然后nM3 = (3q + r)•((264 -1)/3 + 1) = q•(264-1)+3q+r •((264−1)/3 + 1) = q•264+2q+r•((264-1)/3 + 1).

当使用 uint64_t 算术计算时,q•264 项会由于模 264 包装而消失,因此计算结果是 2q+r•((264-1)/3 + 1)。

假设 n 是 3 的倍数。那么 r = 0。由于 nuint32_t 值,q 32,所以 2q+r•((264-1)/ 3 + 1) = 2q 33 M3.

假设 n 不是 3 的倍数。那么 r = 1 或 r = 2。如果 r = 1, r•((264-1)/3 + 1) = (264-1)/3 + 1 > M3-1。当然,如果 r = 2,r•((264−1)/3 + 1) 甚至更大,而且超过M3-1。但是,我们需要关注 uint64_t 算术的包装。同样,由于 q 32,我们有,对于 r = 2, 2q+ r•((264−1)/3 + 1) 32 + 2•((264−1)/3 + 1) = 233 + 2/3•264 - 2/3 + 2 = 264 - 1/3•264 + 233 + 4/3,明显小于264,所以不会发生换行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2017-04-27
    • 2019-10-20
    • 1970-01-01
    相关资源
    最近更新 更多