program DecCnt;
{$mode objfpc}{$H+}
uses
SysUtils, Math;
function DecCntu32( u: UInt32 ):NativeInt;inline;
const
CTable: array [0..32] of UInt64 =
(
4294967296,
4294967296, 8589934582, 8589934582, 8589934582,
12884901788, 12884901788, 12884901788, 17179868184,
17179868184, 17179868184, 21474826480, 21474826480,
21474826480, 21474826480, 25769703776, 25769703776,
25769703776, 30063771072, 30063771072, 30063771072,
34349738368, 34349738368, 34349738368, 34349738368,
38554705664, 38554705664, 38554705664, 41949672960,
41949672960, 41949672960, 42949672960, 42949672960
);
begin
Result := ( u+CTable[ UInt8( BsrDWord( u )+1 ) ] ) shr 32;
end;
function DecCnti32( i: UInt32 ):NativeInt;inline;
const
CTable: array [0..32] of QWord =
(
4294967296,
4294967296, 8589934582, 8589934582, 8589934582,
12884901788, 12884901788, 12884901788, 17179868184,
17179868184, 17179868184, 21474826480, 21474826480,
21474826480, 21474826480, 25769703776, 25769703776,
25769703776, 30063771072, 30063771072, 30063771072,
34349738368, 34349738368, 34349738368, 34349738368,
38554705664, 38554705664, 38554705664, 41949672960,
41949672960, 41949672960, 42949672960, 42949672960
);
begin
Result := ( i+CTable[ UInt8( BsrDWord( Abs( i ) )+1 ) ] ) shr 32;
end;
// the following defines are just for code beautifying purposes
{$push}{$macro on}
{$define E0 := -1}
{$define E1 := -10}
{$define E2 := -100}
{$define E3 := -1000}
{$define E4 := -10000}
{$define E5 := -100000}
{$define E6 := -1000000}
{$define E7 := -10000000}
{$define E8 := -100000000}
{$define E9 := -1000000000}
{$define E10 := -10000000000}
{$define E11 := -100000000000}
{$define E12 := -1000000000000}
{$define E13 := -10000000000000}
{$define E14 := -100000000000000}
{$define E15 := -1000000000000000}
{$define E16 := -10000000000000000}
{$define E17 := -100000000000000000}
{$define E18 := -1000000000000000000}
{$define E19 := 8446744073709551616}
function DecCntu64( u: UInt64 ):NativeInt;inline;
const
CTable: array [0..64,0..1] of QWord =
(
( 1, UInt64( E0 ) ),
( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ),
( 2, UInt64( E2 ) ), ( 2, UInt64( E2 ) ), ( 2, UInt64( E2 ) ),
( 3, UInt64( E3 ) ), ( 3, UInt64( E3 ) ), ( 3, UInt64( E3 ) ),
( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ),
( 5, UInt64( E5 ) ), ( 5, UInt64( E5 ) ), ( 5, UInt64( E5 ) ),
( 6, UInt64( E6 ) ), ( 6, UInt64( E6 ) ), ( 6, UInt64( E6 ) ),
( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ),
( 8, UInt64( E8 ) ), ( 8, UInt64( E8 ) ), ( 8, UInt64( E8 ) ),
( 9, UInt64( E9 ) ), ( 9, UInt64( E9 ) ), ( 9, UInt64( E9 ) ),
( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ),
( 11, UInt64( E11 ) ), ( 11, UInt64( E11 ) ), ( 11, UInt64( E11 ) ),
( 12, UInt64( E12 ) ), ( 12, UInt64( E12 ) ), ( 12, UInt64( E12 ) ),
( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ),
( 14, UInt64( E14 ) ), ( 14, UInt64( E14 ) ), ( 14, UInt64( E14 ) ),
( 15, UInt64( E15 ) ), ( 15, UInt64( E15 ) ), ( 15, UInt64( E15 ) ),
( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ),
( 17, UInt64( E17 ) ), ( 17, UInt64( E17 ) ), ( 17, UInt64( E17 ) ),
( 18, UInt64( E18 ) ), ( 18, UInt64( E18 ) ), ( 18, UInt64( E18 ) ),
( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) )
);
var
Index: UInt8;
begin
Index := UInt8( BsrQWord( u )+1 );
Result := CTable[ Index,0 ] + NativeInt( ( CTable[ Index,1 ]+u )<u );
end;
function DecCntu64v2( u: UInt64 ):NativeInt;inline;
const
CTable1: array [0..64] of UInt8 =
(
1,
1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6,
7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18,
19, 19, 19, 19
);
CTable2: array [0..64] of UInt64 =
(
UInt64( E0 ),
UInt64( E1 ), UInt64( E1 ), UInt64( E1 ), UInt64( E1 ),
UInt64( E2 ), UInt64( E2 ), UInt64( E2 ),
UInt64( E3 ), UInt64( E3 ), UInt64( E3 ),
UInt64( E4 ), UInt64( E4 ), UInt64( E4 ), UInt64( E4 ),
UInt64( E5 ), UInt64( E5 ), UInt64( E5 ),
UInt64( E6 ), UInt64( E6 ), UInt64( E6 ),
UInt64( E7 ), UInt64( E7 ), UInt64( E7 ), UInt64( E7 ),
UInt64( E8 ), UInt64( E8 ), UInt64( E8 ),
UInt64( E9 ), UInt64( E9 ), UInt64( E9 ),
UInt64( E10 ), UInt64( E10 ), UInt64( E10 ), UInt64( E10 ),
UInt64( E11 ), UInt64( E11 ), UInt64( E11 ),
UInt64( E12 ), UInt64( E12 ), UInt64( E12 ),
UInt64( E13 ), UInt64( E13 ), UInt64( E13 ), UInt64( E13 ),
UInt64( E14 ), UInt64( E14 ), UInt64( E14 ),
UInt64( E15 ), UInt64( E15 ), UInt64( E15 ),
UInt64( E16 ), UInt64( E16 ), UInt64( E16 ), UInt64( E16 ),
UInt64( E17 ), UInt64( E17 ), UInt64( E17 ),
UInt64( E18 ), UInt64( E18 ), UInt64( E18 ),
UInt64( E19 ), UInt64( E19 ), UInt64( E19 ), UInt64( E19 )
);
var
Index: UInt8;
begin
Index := UInt8( BsrQWord( u )+1 );
Result := CTable1[ Index ] + NativeInt( ( CTable2[ Index ]+u )<u );
end;
function DecCnti64( i: Int64 ):NativeInt;inline;
const
CTable: array [0..64,0..1] of QWord =
(
( 1, UInt64( E0 ) ),
( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ), ( 1, UInt64( E1 ) ),
( 2, UInt64( E2 ) ), ( 2, UInt64( E2 ) ), ( 2, UInt64( E2 ) ),
( 3, UInt64( E3 ) ), ( 3, UInt64( E3 ) ), ( 3, UInt64( E3 ) ),
( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ), ( 4, UInt64( E4 ) ),
( 5, UInt64( E5 ) ), ( 5, UInt64( E5 ) ), ( 5, UInt64( E5 ) ),
( 6, UInt64( E6 ) ), ( 6, UInt64( E6 ) ), ( 6, UInt64( E6 ) ),
( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ), ( 7, UInt64( E7 ) ),
( 8, UInt64( E8 ) ), ( 8, UInt64( E8 ) ), ( 8, UInt64( E8 ) ),
( 9, UInt64( E9 ) ), ( 9, UInt64( E9 ) ), ( 9, UInt64( E9 ) ),
( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ), ( 10, UInt64( E10 ) ),
( 11, UInt64( E11 ) ), ( 11, UInt64( E11 ) ), ( 11, UInt64( E11 ) ),
( 12, UInt64( E12 ) ), ( 12, UInt64( E12 ) ), ( 12, UInt64( E12 ) ),
( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ), ( 13, UInt64( E13 ) ),
( 14, UInt64( E14 ) ), ( 14, UInt64( E14 ) ), ( 14, UInt64( E14 ) ),
( 15, UInt64( E15 ) ), ( 15, UInt64( E15 ) ), ( 15, UInt64( E15 ) ),
( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ), ( 16, UInt64( E16 ) ),
( 17, UInt64( E17 ) ), ( 17, UInt64( E17 ) ), ( 17, UInt64( E17 ) ),
( 18, UInt64( E18 ) ), ( 18, UInt64( E18 ) ), ( 18, UInt64( E18 ) ),
( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) ), ( 19, UInt64( E19 ) )
);
var
Index: UInt8;
Absi: UInt64;
begin
Absi := Abs( i );
Index := UInt8( BsrQWord( Absi )+1 );
Result := CTable[ Index,0 ] + NativeInt( ( CTable[ Index,1 ]+Absi )<Absi );
end;
{$undef E19}
{$undef E18}
{$undef E17}
{$undef E16}
{$undef E15}
{$undef E14}
{$undef E13}
{$undef E12}
{$undef E11}
{$undef E10}
{$undef E9}
{$undef E8}
{$undef E7}
{$undef E6}
{$undef E5}
{$undef E4}
{$undef E3}
{$undef E2}
{$undef E1}
{$undef E0}
{$pop}
const
laps=100000000;
TestValu32Tab: array[ 0..20 ] of UInt32 =
(
0, 1, 9, 10, 99, 100, 999, 1000, 9999, 10000, 99999, 100000, 999999,
1000000, 9999999, 10000000, 99999999, 100000000, 999999999, 1000000000,
4294967295
);
TestCntu32Tab: array[ 0..20 ] of UInt8 =
(
1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10
);
TestValu64Tab: array[ 0..40 ] of UInt64 =
(
0, 1, 9, 10, 99, 100, 999, 1000, 9999, 10000, 99999, 100000, 999999,
1000000, 9999999, 10000000, 99999999, 100000000, 999999999, 1000000000,
9999999999, 10000000000, 99999999999, 100000000000, 999999999999,
1000000000000, 9999999999999, 10000000000000, 99999999999999, 100000000000000,
999999999999999, 1000000000000000, 9999999999999999, 10000000000000000,
99999999999999999, 100000000000000000, 999999999999999999, 1000000000000000000,
9999999999999999999, 10000000000000000000, 18446744073709551615
);
TestCntu64Tab: array[ 0..40 ] of UInt8 =
(
1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20
);
var
s: QWord;
x, i: Integer;
a: array of DWord = nil;
begin
SetLength(a, laps);
for i := 0 to High(a) do
a[i] := Random(MaxInt);
x:=0;
s:=GetTickCount64;
for i := 0 to High(a) do
Inc( x, DecCntu32( a[ i ] ) );
WriteLn( 'DecCntu32: ', GetTickCount64-s );
x:=0;
s:=GetTickCount64;
for i := 0 to High(a) do
Inc( x, DecCnti32( a[ i ] ) );
WriteLn( 'DecCnti32: ', GetTickCount64-s );
x:=0;
s:=GetTickCount64;
for i := 0 to High(a) do
Inc( x, DecCntu64( a[ i ] ) );
WriteLn( 'DecCntu64: ', GetTickCount64-s );
x:=0;
s:=GetTickCount64;
for i := 0 to High(a) do
Inc( x, DecCntu64v2( a[ i ] ) );
WriteLn( 'DecCntu64v2: ', GetTickCount64-s );
x:=0;
s:=GetTickCount64;
for i := 0 to High(a) do
Inc( x, DecCnti64( a[ i ] ) );
WriteLn( 'DecCnti64: ', GetTickCount64-s );
Write( LineEnding, 'Test DecCntu32: ' );
for i := Low( TestValu32Tab ) to High( TestValu32Tab ) do begin
if( DecCntu32( TestValu32Tab[ i ] )=TestCntu32Tab[ i ] ) then begin
Write( '*' );
end else begin
Write( ' failed: ', TestValu32Tab[ i ] );
Exit;
end;
end;
Write( LineEnding, 'Test DecCntu64: ' );
for i := Low( TestValu64Tab ) to High( TestValu64Tab ) do begin
if( DecCntu64( TestValu64Tab[ i ] )=TestCntu64Tab[ i ] ) then begin
Write( '*' );
end else begin
Write( ' failed: ', TestValu64Tab[ i ] );
Exit;
end;
end;
end.