Jérôme M. Berger wrote: > OK, I found a solution that is optimal in over 99% of the cases > (99.195% to be precise), while still being fast (because it avoids > looping over the bits): > I've run my function and Andrei's on all possible min, max pairs in 0..299 without checking, just for the timing. On my computer (Athlon X2 64 @2GHz), my function took 50s and Andrei's took 266s. The difference should be even bigger for larger numbers.
Jerome -- mailto:jeber...@free.fr http://jeberger.free.fr Jabber: jeber...@jabber.fr
#include <assert.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #define N 300 // Comment the following line to get Andrei's implementation #define MINE // Comment the following line for exhaustive checking (slow! don't // forget to reduce N) #define BENCH int highbit (uint32_t n) { assert (n != 0); int result = 0; if (n & 0xFFFF0000) { result += 16; n >>= 16; } if (n & 0xFF00) { result += 8; n >>= 8; } if (n & 0xF0) { result += 4; n >>= 4; } if (n & 0xC) { result += 2; n >>= 2; } if (n & 0x2) { result += 1; n >>= 1; } return result; } inline uint32_t min (uint32_t a, uint32_t b) { return (a<b) ? a : b; } #ifdef MINE uint32_t maxOr (uint32_t minA, uint32_t minB, uint32_t maxA, uint32_t maxB) { assert (minA <= maxA); assert (minB <= maxB); if (maxA == 0) return maxB; if (maxB == 0) return maxA; uint32_t a = maxA ^ minA; if (a != 0) a = ((1 << highbit (a)) - 1); uint32_t b = maxB ^ minB; if (b != 0) b = ((1 << highbit (b)) - 1); uint32_t t = maxA & maxB; if (t != 0) t = ((1 << highbit (t)) - 1); return min (maxA|maxB|a|b, maxA|maxB|t); } #else // Andrei's uint32_t maxOr (uint32_t, uint32_t, uint32_t maxa, uint32_t maxb) { uint32_t candidate = 0; uint32_t mask = 1u << 31; for (; mask; mask >>= 1) { if (maxa & mask) continue; uint32_t t = candidate | mask; if (t <= maxb) candidate = t; } return maxa | candidate; } #endif int main (int, char**) { int count = 0; int countTight = 0; for (uint32_t minA = 0; minA < N; ++minA) for (uint32_t maxA = minA; maxA < N; ++maxA) for (uint32_t minB = 0; minB < N; ++minB) for (uint32_t maxB = minB; maxB < N; ++maxB) { bool reached = false; uint32_t max = maxOr (minA, minB, maxA, maxB); #ifdef BENCH count += max; #else // Check for (uint32_t a = minA; a <= maxA; ++a) for (uint32_t b = minB; b <= maxB; ++b) { if ((a|b) > max) { printf ("minA=%x\n" "maxA=%x\n" "minB=%x\n" "maxB=%x\n" "a=%x\n" "b=%x\n" "a|b=%x\n" "maxOr=%x\n", minA, maxA, minB, maxB, a, b, a|b, max); exit (1); } if ((a|b) == max) reached = true; } if (reached) ++countTight; ++count; #endif } #ifdef BENCH printf ("Result: %d (this number doesn't mean anything, it is only here\n" "to make sure the compiler doesn't optimize everything away...\n", count); #else printf ("Total: %d\n", count); printf ("Tight: %d (%g%%)\n", countTight, countTight * 100. / count); printf ("Loose: %d (%g%%)\n", (count - countTight), (count - countTight) * 100. / count); #endif return 0; }
signature.asc
Description: OpenPGP digital signature