use warnings; use Benchmark; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; int uv_fits_double3(SV * x, ...) { dXSARGS; int i, count = 0; UV arg; for(i = 0; i < items; i++) { arg = SvUV(ST(i)); if(arg) { while(!(arg & 1)) arg >>= 1; if(arg < 9007199254740993) count++; } } return count; } int uv_fits_double_bitfiddle(SV * t, ...) { dXSARGS; int i, count = 0; UV arg; for(i = 0; i < items; i++) { arg = SvUV(ST(i)); IV smallest_invalid = (arg & -arg) << 53; UV valid_bits = smallest_invalid - 1; UV invalid_bits = ~valid_bits; if ( !(arg & invalid_bits)) count++; } return count; } int uv_fits_double3x(SV* the_min, SV* the_max) { dXSARGS; UV i_min = SvUV(the_min); UV i_max = SvUV(the_max); UV i; int count = 0; UV arg; for(i = i_min; i < i_max; i++) { arg = i; if(arg) { while(!(arg & 1)) arg >>= 1; if(arg < 9007199254740993) count++; } } return count; } int uv_fits_double_bitfiddle2(SV* the_min, SV* the_max) { dXSARGS; UV i_min = SvUV(the_min); UV i_max = SvUV(the_max); UV i; int count = 0; for(i = i_min; i < i_max; i++) { UV arg = i; IV neg = -arg; IV smallest_invalid = (arg & -arg)<<53; UV valid_bits = smallest_invalid-1; UV invalid_bits = ~valid_bits; if (! (arg & invalid_bits)) count++; } return count; } int uv_empty_func(SV* the_min, SV* the_max) { dXSARGS; UV i_min = SvUV(the_min); UV i_max = SvUV(the_max); return i_max - i_min; } int uv_empty_loop(SV* the_min, SV* the_max) { dXSARGS; UV i_min = SvUV(the_min); UV i_max = SvUV(the_max); UV i; int count = 0; for(i = i_min; i < i_max; i++) { UV arg = i; // boring count++; } return count * i_max - i_min; } EOC @in2 = ( [ 1844674407366955161, 1844674407378955161 ], [ 9007199248740992, 9007199260740992 ], [ 184467436737095, 184467448737095 ], [ 184463440737, 184475440737 ], ); push @in, $_->[0] .. $_->[1] for @in2; print "=== Test 1: roughly equivalent speed\n"; our ($count1, $count2); ($count1, $count2) = (0, 0); timethese (5, { 'uv_fits_double3' => '$count1 = uv_fits_double3(@in);', 'uv_fits_double_bitfiddle' => '$count2 = uv_fits_double_bitfiddle(@in);', }); print "$count1 $count2 (", scalar(@in), ")\n"; print "!!!! MISMATCH !!!!\n" if $count1 != $count2; print "\n=== TEST 2: twiddle has an advantage if we don't use SvUV()\n"; ($count1, $count2, $count3) = (0, 0, 0, 0); timethese (10000, { 'double3x' => '$count1 = uv_fits_double3x(@{$in2[0]})' .' + uv_fits_double3x(@{$in2[1]})' .' + uv_fits_double3x(@{$in2[2]})' .' + uv_fits_double3x(@{$in2[3]})' , 'bitfiddle_3x'=>'$count2 = uv_fits_double_bitfiddle2(@{$in2[0]})' .' + uv_fits_double_bitfiddle2(@{$in2[1]})' .' + uv_fits_double_bitfiddle2(@{$in2[2]})' .' + uv_fits_double_bitfiddle2(@{$in2[3]})' , 'empty_func'=>'$count3 = uv_empty_func(@{$in2[0]})' .' + uv_empty_func(@{$in2[1]})' .' + uv_empty_func(@{$in2[2]})' .' + uv_empty_func(@{$in2[3]})' , 'empty_loop'=>'$count4 = uv_empty_loop(@{$in2[0]})' .' + uv_empty_loop(@{$in2[1]})' .' + uv_empty_loop(@{$in2[2]})' .' + uv_empty_loop(@{$in2[3]})' , }); print "$count1 $count2 $count3 $count4\n"; print "!!!! MISMATCH !!!!\n" if $count1 != $count2;