如何检查给定的数字是否能以最快的方式整除15?

时间:2013-09-09 20:35:29

标签: c++ c performance compiler-optimization integer-division

处理器中的分区需要很长时间,所以我想问一下如果数字可以被其他数字整除,如何以最快的方式检查,在我的情况下,我需要检查数字是否可以被15整除。

此外,我一直在浏览网页并找到 fun 方法来检查数字是否可以被某些数字整除,但我正在寻找快速选项。

注意:因为除非需要/%,我正在寻找答案。

6 个答案:

答案 0 :(得分:31)

其他可能会寻找答案的学员的强制性答案。

if (number % n == 0)

大多数案例中,您始终可以这样做,相信智能现代编译器。

这并不意味着你会因为学习有趣的方式而气馁。看看这些链接。

Fast divisibility tests (by 2,3,4,5,.., 16)?

Bit Twiddling Hacks

答案 1 :(得分:24)

乘法比划分花费更少的时间,所以你可以试试这个:

inline bool divisible15(unsigned int x)
{
    //286331153 = (2^32 - 1) / 15
    //4008636143 = (2^32) - 286331153
    return x * 4008636143u <= 286331153u;
}

这种方式有效,因为2^32-1(最大32位值)可以被15整除,但是如果你采用,例如7,它看起来像工作,但不会在所有情况下都有效。

编辑:请参阅this,它证明此解决方案(某些编译器上的 )比模块更快。

编辑: Here是解释和概括。

答案 2 :(得分:24)

只需使用i % 15 == 0

即可
  1. 由于编译器可以很容易地看到15将永远不会改变,因此可以随意对mod操作进行任何优化。编译器编写者的工作是进行这种优化,如果他们没有想到更好的方法来做到这一点你不会。

  2. 例如,检查一个数字是否可被2整除是非常容易的,因为您只需检查第一位。编译器编写者知道这一点,您可以自己编写代码来检查第一位,但特别是成熟的编译器会让人们思考和处理这些事情多年。这种类型的优化是非常简单的,因为它只需要更改指令或2,更好的寄存器分配等优化更难实现

  3. 要考虑的另一件事是你的编译器是为它所在的系统编写的,另一方面你的代码在任何地方都是一样的,如果你写一些奇怪的代码可能同样快一个系统(可能仍然没有更快)但在另一个具有特殊硬件优化的系统上,您的代码可能会丢失一个数量级。由于您编写了一些深奥的代码来检查可分性,因此编译器不太可能意识到它可以优化到单个硬件操作系统,编写明显的事情可以让您的生活变得更好,编译器也更容易。

  4. 由于您实际上没有检查速度是否与编写代码有关,因此奇怪的方式会使代码很难为下一个人阅读而且更容易出错(premature optimization is the root of all evil

    < / LI>
  5. 无论输入是16位,32位还是64位,它仍然有效,因为它不依赖于位操作。

  6. 即使编译器编写者没有实现它,显然有人可以实现它(甚至是你自己)

答案 3 :(得分:6)

在一个相当现代的过程中,除以15不应该那么可怕。 AMD优化指南根据商(被分割的值)定义它,并且它需要商的最高有效位的8 +位位置。因此,如果你的数字设置了第63位,你最终会得到71个周期 - 当然这是一个很长的指令。但对于32位数字,顶部位有几个零,我们说的是30-40个周期。如果数字符合16位值,则最大值为23个周期。

为了获得余数,还有一个时钟周期。

如果你一直这样做,当然,你可能会发现这个时间很长,但我不确定是否有一种琐碎的方法可以避免它。

正如其他人所说,编译器可能能够用更好的东西取而代之。但据我所知15并没有明显的快速解决方案(如果你有16而不是15,那么我们可以使用x & 15的技巧)。

如果它是一个有限的范围,你可以构建一个表[vector<bool>,例如,每个条目将存储1位],但你很快就会遇到非缓存内存访问需要的问题只要分裂操作......

有一些有趣的方法可以通过对数字求和来确定一个数字是否除以3,5等等,但不幸的是,这些数字仅基于十进制数字工作,这涉及一长串的除法。

答案 4 :(得分:5)

这是另一种方法,它可能比其他方法慢,但只使用加法,按位和移位:

int divisible15(unsigned int x) {
        if (x==0) return 1;
        x = (x & 0x0f0f0f0f) + ((x&0xf0f0f0f0)>>4);
        x = (x & 0x00ff00ff) + ((x&0xff00ff00)>>8);
        x = (x & 0x0000ffff) + ((x&0xffff0000)>>16);
        x = (x & 0x0f) + ((x&0xf0)>>4);
        return x==15;
}

这个想法是,基数为16的15的可分性就像基数10中的9的可分性一样 - 数字的总和必须能被15整除。
所以代码总结了所有十六进制数字(类似于计算位的方式),总和必须等于15(除了0)。

答案 5 :(得分:0)

如果您有十六进制表示,那么在您的头脑中很容易做到。只需将所有数字相加,直到您只有一位数。如果答案是'0xf',它可以被15整除。

示例0x3a98:3 + 0xa + 9 + 8 = 0x1e = 1 + 0xe = 0xf,因此可以被15整除。

这适用于X-1上的所有因素,其中X是用于表示数字的基础。 (对于较小的因子,最后的数字必须可以被因子整除)。

不要指望这在代码中很快。