If you have RAM to spare, (you are using perl, of course you do) you could build a 2048-entry lookup table, mask arg with 2047, shift once with the value from the table and then compare with 9007199254740993 once.
Something like: (untested)
static uint8_t ctz_table_11bit[2048] = { /* elided */ };
int uv_fits_double(UV arg) {
arg >>= ctz_table_11bit[arg & 2047];
return arg < 9007199254740993;
}
The relative elegance of this solution is probably a matter of opinion, but it should run much faster, since it is theoretically a single basic block and should be a candidate for inlining. This trades considerable computation for a single memory read, which will have relative performance depending on your hardware.
Here is some Perl code to generate that table: (I think this is the first time I have used formats; output spot checked for plausibility)
#!/usr/bin/perl
use strict;
use warnings;
use constant BITS => 11;
our @pos; our @bits; our @val;
format STDOUT_TOP=
.
$= = 1<<(BITS-1);
format STDOUT =
/* @### -> @0######### */ @#, /* @### -> @0######### */ @#,
$pos[0], $bits[0], $val[0], $pos[1], $bits[1], $val[1],
.
print "static uint8_t ctz_table_",BITS,"bit[",1<<BITS,"] = {\n";
for (my $pos = 0; $pos < (1<<BITS); $pos += 2) {
@pos = ($pos, $pos+1);
@bits = map substr(unpack('B*', pack 'n', $_), -(BITS)), @pos;
@val = map length((m/(0*?)\z/)[0]), @bits;
write
}
print "};\n";
# EOF
Update: change two magic numbers to use symbolic constant.