use bigint; { my @lookup = (1); # 2, 4, 8, ... sub int_log2 { my $n = shift; return if $n < 1; my $exp = 0; # this still could be optimized by starting at # $exp = min( $#lookup, $some_educated_guess_using_floating_point_approximation ) while ( $lookup[ $exp++ ] <= $n ) { $lookup[$exp] = 2 * $lookup[ $exp - 1 ] if not exists $lookup[$exp]; } return $exp - 2; } } for ( 1 .. 2**10 ) { print int_log2(2**$_-1), ' ', int_log2(2**$_), ' ', int_log2(2**$_+1), "\n"; }