unit Ordinals; (* contents of file ordinals.pas, version which *) (* links lot_one.obj, compiled from lot_one.asm *) (* by Uros Boltin *) { Calculates ordinal numbers of combinations and vice versa. } { Numbers can be in range [1..32]. } interface const MaxN = 32; { not used; assumed 32 in assembler (lot_one.asm) } type Set31 = set of 0..31; LotMap = LongInt; { Type LotMap is used for binary bitmaps of combinations. } { Use Set31 type conversion to access numbers. It's zero-based! } { E.g.: ... if (x-1) in Set31(Lot) then ... } { Here, 0 stands for 1, 1 for 2 etc. until 31 for 32 } { Warning: set of 1..32 won't work! It's shifted and takes 5 bytes. } TPascalTriangle = array[ 1..32, -1..30 ] of LongInt; PPascalTriangle = ^TPascalTriangle; const Triangle: PPascalTriangle = nil; procedure MakeTriangle; procedure FreeTriangle; function Binomial( n,r:integer ): LongInt; function Backwards( Lot:LotMap; n:integer ): LotMap; far; function LotIndex( Lot:LotMap ): LongInt; far; function LotAt( Index:LongInt; r:integer ): LotMap; far; { Functions LotIndex and LotAt are the ones which actually do the job. } { They work with zero-based absolute ordinals. } { The following four functions are simple wrappers around them. } { These work with the usual ordinals, starting 1,2,3... } function AbsoluteOrdinal( Lot:LotMap ): LongInt; function RelativeOrdinal( Lot:LotMap; n,r:integer ): LongInt; function FromAbsolute( Index:LongInt; r:integer ): LotMap; function FromRelative( Index:LongInt; n,r:integer ): LotMap; implementation procedure MakeTriangle; { initialization before any other function can be called } var i,j: integer; begin if Triangle<>nil then Exit; New( Triangle ); for i := 1 to 32 do Triangle^[i,-1] := 0; for j := 0 to 30 do Triangle^[1,j] := j+1; for i := 2 to 32 do for j := 0 to 32-i do Triangle^[i,j] := Triangle^[i-1,j] + Triangle^[i,j-1]; end; procedure FreeTriangle; { cleanup before end of program } begin if Triangle<>nil then Dispose( Triangle ); Triangle := nil; end; function Binomial( n,r:integer ): LongInt; begin case r of 0: Binomial := 1; 1: Binomial := n; else Binomial := Triangle^[r,n-r]; end; end; {$L lot_one.obj} function Backwards( Lot:LotMap; n:integer ): LotMap; external; { mirror Lot: high bits <--> low bits } function LotIndex( Lot:LotMap ): LongInt; external; { returns a zero-based absolute ordinal } function LotAt( Index:LongInt; r:integer ): LotMap; external; { inverse of LotIndex } function AbsoluteOrdinal( Lot:LotMap ): LongInt; begin if Lot=0 then AbsoluteOrdinal := 0 else AbsoluteOrdinal := LotIndex(Lot) + 1; end; function RelativeOrdinal( Lot:LotMap; n,r:integer ): LongInt; begin if Lot=0 then RelativeOrdinal := 0 else RelativeOrdinal := Binomial(n,r) - LotIndex( Backwards(Lot,n) ); end; function FromAbsolute( Index:LongInt; r:integer ): LotMap; begin if Index=0 then FromAbsolute := 0 else FromAbsolute := LotAt( Index-1, r ); end; function FromRelative( Index:LongInt; n,r:integer ): LotMap; begin if Index=0 then FromRelative := 0 else FromRelative := Backwards( LotAt( Binomial(n,r)-Index, r ), n ); end; end.