开发者

Which is the best way, in C, to see if a number is divisible by another?

开发者 https://www.devze.com 2023-03-08 04:39 出处:网络
Which is the best way, in C, to see if a number is divisible by another? I use this: if (!(a % x)) { // this will be executed if a is divisible by x

Which is the best way, in C, to see if a number is divisible by another? I use this:

if (!(a % x)) {
// this will be executed if a is divisible by x
}

Is there 开发者_StackOverflow社区anyway which is faster? I know that doing, i.e, 130 % 13 will result into doing 130 / 13 per 10 times. So there are 10 cycles when just one is needed (I just want to know if 130 is divisible by 13).

Thanks!


I know that doing, i.e, 130 % 13 will result into doing 130 / 13 per 10 times

Balderdash. % does no such thing on any processor I've ever used. It does 130/13 once, and returns the remainder.

Use %. If your application runs too slowly, profile it and fix whatever is too slow.


For two arbitrary numbers, the best way to check is to check whether a % b == 0. The modulus operator has different performance based on the hardware, but your compiler can figure this out much better than you can. The modulus operator is universal, and your compiler will figure out the best sequence of instructions to emit for whatever hardware you're running on.

If one of the numbers is a constant, your compiler might optimize by doing some combination of bit shifts and subtractions (mostly for powers of two), since hardware div/mod is slower than addition or subtraction, but on modern processors the latency (already only a few nanoseconds) is hidden by tons of other performance tricks, so you needn't worry about it. No hardware computes modulus by repeated division (some old processors did division by repeated bit shifts and subtraction, but they still used specialized hardware for this, so it's still faster to have the hardware do it than to try to emulate it in software). Most modern ISAs actually compute both division and remainder in one instruction.

The only optimization that might be useful is if the divisor is a power of two. Then you can use & to mask the low-order bits (by divisor - 1) and check the result against zero. For example, to check if a is divisible by 8, a & 7 == 0 is equivalent. A good compiler will do this for you, so stick with just stick with %.


In the general case, using the modulo operator is likely to be the fastest method available. There are exceptions, particularly if you are interested in whether numbers are divisible by powers of two (in which case bitwise operations are available), but the compiler should choose them automatically for you if you just use %. You are unlikely to be able to do any better for arbitrary values such as 13.

Also, what do you mean by "doing 130 / 13 per 10 times"? It does 130 / 13 once. Which is exactly what is required.


If x is a constant, then yes:

if (a * 0x4ec4ec4ec4ec4ec5 < 0x13b13b13b13b13b2) {
    // this will be executed if a is divisible by 13
}

0x4ec4ec4ec4ec4ec5 is the modular multiplicative inverse of 13 (modulo 264), so if a is really a multiple of 13 then the product will be less than (264/13). (Because a is 13 times some integer n, and n must have fit into a 64-bit word which implies that it was less than 264.)

This only works for odd values of x. For even numbers (i.e. multiples of 2y for y>0) you can combine this test with a bitwise-AND test (the last y bits of a should be zero. If they are then divide a by 2y and proceed with the multiplication test.)

This is only worthwhile if x is a constant, because computing the multiplicative inverse is more expensive than integer division.


Edit: I am also assuming a and x are unsigned.


When the machine does % it just does a division instruction, and that automatically generates a remainder.

However, be aware that if one of the numbers is negative, % will give a negative remainder. If you only care about a remainder of zero, this is not a problem, but if you happen to be looking for another remainder, like 1, it can really trip you up.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号