Created
April 20, 2022 14:44
-
-
Save lancejpollard/373ce50cf5ffd651657110049a17d851 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Frigo/all> | |
#include <Frigo/all.cpp> | |
// from https://stackoverflow.com/questions/7365562/de-bruijn-like-sequence-for-2n-1-how-is-it-constructed/7369288#7369288 | |
using namespace Frigo::Lang; | |
using namespace std; | |
class MagicNumberGenerator | |
{ | |
public: | |
static const int32 log2n = 5; | |
static const int32 n = 1 << log2n; | |
static const bool tryZero = false; | |
MagicNumberGenerator () {} | |
void tryAllMagic () | |
{ | |
for( int32 magic = 0; magic < Integer::MAX_VALUE; magic++ ){ | |
tryMagic(magic); | |
} | |
tryMagic(Integer::MAX_VALUE); | |
for( int32 magic = Integer::MIN_VALUE; magic < 0; magic++ ){ | |
tryMagic(magic); | |
} | |
} | |
bool tryMagic (int32 magic) | |
{ | |
// clear table | |
for( int32 i = 0; i < n; i++ ){ | |
table[i] = -1; | |
} | |
// try for zero | |
if( tryZero and not tryInput(magic, 0) ){ | |
return false; | |
} | |
// try for all power of two inputs, filling table quickly in the process | |
for( int32 i = 0; i < 32; i++ ){ | |
if( not tryInput(magic, 1 << i) ){ | |
return false; | |
} | |
} | |
// here we would test all possible 32-bit inputs except zero, but it is pointless due to the reduction to 2^n-1 form | |
// we found a magic number | |
cout << "Magic number found: 0x" << Integer::toHexString(magic) << endl; | |
return true; | |
} | |
bool tryInput (int32 magic, int32 x) | |
{ | |
// calculate good answer | |
int32 leadingZeros = goodNumberOfLeadingZeros(x); | |
// calculate scrambled but hopefully injective answer | |
x |= x >> 1; | |
x |= x >> 2; | |
x |= x >> 4; | |
x |= x >> 8; | |
x |= x >> 16; | |
x *= magic; | |
x = Integer::unsignedRightShift(x, 32 - log2n); | |
// reject if answer is not injective | |
if( table[x] != -1 ){ | |
return table[x] == leadingZeros; | |
} | |
// store result for further injectivity checks | |
table[x] = leadingZeros; | |
return true; | |
} | |
static int32 goodNumberOfLeadingZeros (int32 x) | |
{ | |
int32 r = 32; | |
if( cast<uint32>(x) & 0xffff0000 ){ | |
x >>= 16; | |
r -= 16; | |
} | |
if( x & 0xff00 ){ | |
x >>= 8; | |
r -= 8; | |
} | |
if( x & 0xf0 ){ | |
x >>= 4; | |
r -= 4; | |
} | |
if( x & 0xc ){ | |
x >>= 2; | |
r -= 2; | |
} | |
if( x & 0x2 ){ | |
x >>= 1; | |
r--; | |
} | |
if( x & 0x1 ){ | |
r--; | |
} | |
return r; | |
} | |
int32 table[n]; | |
}; | |
int32 main (int32 argc, char* argv[]) | |
{ | |
if(argc||argv){} | |
measure{ | |
MagicNumberGenerator gen; | |
gen.tryAllMagic(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment