7

Given an integer x, how would you return an integer y that is lower than or equal to x and a multiple of 64?

idealistikz
  • 1,247
  • 5
  • 21
  • 35

6 Answers6

17

Simply and it with the bit inversion of (64-1):

x = x & ~63
// 64  is 000...0001000000
// 63  is 000...0000111111
// ~63 is 111...1111000000

This basically clears out the lower six bits which is the same as rounding it down to a multiple of 64. Be aware that this will round towards negative infinity for negative numbers, not towards zero, but that seems to be what your question requires.

You can see the behaviour here in this multiple-of-four variant:

#include <stdio.h>
int main (void) {
    int i;
    for (i = -10; i <= 10; i++) {
        printf ("%3d -> %3d\n", i, i & ~3);
    }
    return 0;
}

This produces:

-10 -> -12
 -9 -> -12
 -8 ->  -8
 -7 ->  -8
 -6 ->  -8
 -5 ->  -8
 -4 ->  -4
 -3 ->  -4
 -2 ->  -4
 -1 ->  -4
  0 ->   0
  1 ->   0
  2 ->   0
  3 ->   0
  4 ->   4
  5 ->   4
  6 ->   4
  7 ->   4
  8 ->   8
  9 ->   8
 10 ->   8

Keep in mind this only works for powers of two (like 26 = 64) and two's complement (the ISO standard doesn't mandate that representation - see here for details - but I've never seen an C environment that doesn't use it and I've worked on systems from the puniest 8051 to the largest mainframes). If you want to use any other number for the divisor, you should probably use the proper math functions like floor.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
5

Where x is the number you wish to round down to the nearest multiple of n, the method that you need is:

floor(x / n) * n

which you can implement really nicely in C++ (as opposed to C):

int n = 5;
for (int x = 0; x < 100; x++)
    cout << x << " -> " << (x / n) * n << endl;
icio
  • 3,060
  • 20
  • 22
3

(x >> 6) << 6
First shifting 6 bits right, then left - lower bits filled with nulls.
No problems with sign

EDIT : I think most compilers will optimize x / 64 * 64 (and any divide / multiply with small powers of 2) to the same code, so there is no actual need in such bit magic, until you want your code to look really cool :)

(And AndreyT thinks there are even better optimizations for straightforward code, read comments to his post)

Community
  • 1
  • 1
Alexander Malakhov
  • 3,383
  • 2
  • 33
  • 58
2

Assuming that you need the nearest such integer and that you are working with positive numbers:

x = x / 64 * 64;

Various bit hacks look intreresing, but there's absolutely no need for them in this specific case.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Except bit hacks are shown to be faster than division most every time. And compilers usually optimize power of 2 MULT DIVs (for low powers of 2) into shifts where reasonable. – jcolebrand May 05 '10 at 04:11
  • 3
    @drachenstern: No, bit hacks are only faster when the precise intent is not expressible by means of the language. In this particular case any good compiler should generate the most efficient code, and if it happens to be a "bit hack", then the compiler should use it, not the author of the source code. And no, mul/div is not necessarily optimized into shifts - this is an old urban legend. They are normally optimized into the most efficient operation appropriate in each case, which could be a shift or something else. In fact, it is rarely a shift these days. – AnT stands with Russia May 05 '10 at 05:12
  • 1
    And, finally, by using a bit hack at the level of source code you are actually reducing the chances of efficient optimization taking place. In other words, for straightforward cases like this, bit hack are shown to be generally *slower*, not faster as you seem to be mistakenly believing. – AnT stands with Russia May 05 '10 at 05:13
  • @Andrey: thanks for interesting info, didn't heard about it. Could you give some links to learn a bit more ? Didn't thought there could be smth faster then shift in case of mul/div2 – Alexander Malakhov May 05 '10 at 05:39
  • 2
    @Alexander Malakhov: I don't have any dedicated and/or exhaustive links handy. Just by looking at the assembly code generated by modern compiler one can see that, for example, on x86 platform integer multiplication by a constant is usually translated into a `lea` operation, not into shifts. Like, multiplying something by `3` would turn into `lea eax, [eax * 2 + eax]` and so on. Multiplication by `4` simply turns into a `lea eax, [eax * 4]` since it is more efficient than a shift. – AnT stands with Russia May 05 '10 at 05:43
  • @AndreyT: At first I thought you were wrong. But I think the / will get turned first into a shift, and the code generation for the shift will use lea. So you are correct on that. The multiply by 64 may or may not generate a shift. A bit mask may or may not lead to such efficient code. Now I'm going to have to start comparing performance in cases I thought I knew the answer to. – phkahler May 05 '10 at 13:10
  • @AndreyT ~ Good info. I wasn't sure if it was still urban legend, thanks for the enlightening response. +1's indeed. – jcolebrand May 05 '10 at 14:27
  • 1
    @drachenstern: Don't get me wrong. You *will* see shifts used to optimize arithmetic operations. They are not useless. All I'm saying is that the compiler's choice is not even remotely limited to shifts and explicit mul/div. The compiler has a lot more options these days, some of which could be more efficient than a shift. For this reason, trying to "force" a compiler to use some specific machine instructions by obfuscating your intent with a bit hack is counterproductive more often than not. – AnT stands with Russia May 05 '10 at 16:12
  • @AndreyT ~ Yeah I followed you, I just didn't realize there were more efficient ops for this sort of thing, that's all ;) ~ Thanks again. – jcolebrand May 05 '10 at 19:03
  • Just came to mind. Couldn't some optimizer eliminate `/ const * const` ? Maybe I should protect it somehow, like with parens `(x / c) * c` ? Though with intergers it probably should never do that. Really don't know. – Alexander Malakhov Oct 10 '11 at 17:32
  • @Alexander Malakhov: `x / c * c` already means exactly `(x / c) * c`. No need for any extra `()`. No compiler will dare to "optimize" it unless it is broken. – AnT stands with Russia Oct 10 '11 at 21:36
1
int y = x;
while ( y % 64 )
    y--;
Jeff Kelley
  • 19,021
  • 6
  • 70
  • 80
1

For unsigned ints

return 0

For signed ints

return floor(-MAXINT/64)*64

;-)

Plynx
  • 11,341
  • 3
  • 32
  • 33
  • Funny, but humour should probably best be put in comments lest you risk the wrath of the downvote police :-) – paxdiablo May 05 '10 at 02:12
  • It's actually a factually correct answer. And it works better than some other responses that would fail when given negatives or -MAXINT. Still, perhaps OP meant to specify *greatest* integer that meets the aforementioned requirements :) – Plynx May 05 '10 at 02:13
  • It depends on how you parse the question. The precedence of logical operators in natural languages is usually a bit different ;) – Georg Fritzsche May 05 '10 at 02:17
  • 5
    "It's actually a factually correct answer" - remind me to never leave you alone with a customer during requirements gathering phase :-) – paxdiablo May 05 '10 at 02:20
  • @Plynx: The question did say "nearest" (in the title) – Ben Voigt Sep 18 '11 at 23:44