By: Abe Timmerman; Alkmaar, The Netherlands
Send improvements to: A.Timmerman@beta.hsholland.nlThis unit uses an array of bytes to represent a LARGE number. The number is binairy-stored in the array, with the Least Significant Byte (LSB) first and the Most Significant Byte (MSB) last, like all Intel-integer types.
Arithmetic is not 10-based or 2-based, but 256-based, so that each byte represents one (1) digit.
The HugeInttype numbers are Signed Numbers.
When Compiled with the R+ directive, ADD and MUL wil generate an "Arithmetic Overflow Error" (RunError(215)) when needed. Otherwise use the "HugeIntCarry" variable.
Use the "HugeIntDiv0" variable to check on division by zero.
Use {$DEFINE HugeInt_xx } or "Conditional defines" from the "Compiler options" for sizing, where xx is 64, 32 or 16, otherwhise HugeIntSize will be set to 8 bytes.
unit HugeInts; interface const {$IFDEF HugeInt_64 } HugeIntSize = 64; {$ELSE}{$IFDEF HugeInt_32 } HugeIntSize = 32; {$ELSE}{$IFDEF HugeInt_16 } HugeIntSize = 16; {$ELSE} HugeIntSize = 8; {$ENDIF}{$ENDIF}{$ENDIF} HugeIntMSB = HugeIntSize-1; type HugeInt = array[0..HugeIntMSB] of Byte; const HugeIntCarry: Boolean = False; HugeIntDiv0: Boolean = False; procedure HugeInt_Min(var a: HugeInt); { a := -a } procedure HugeInt_Inc(var a: HugeInt); { a := a + 1 } procedure HugeInt_Dec(var a: HugeInt); { a := a - 1 } procedure HugeInt_Add(a, b: HugeInt; var R: HugeInt); { R := a + b } procedure HugeInt_Sub(a, b: HugeInt; var R: HugeInt); { R := a - b } procedure HugeInt_Mul(a, b: HugeInt; var R: HugeInt); { R := a * b } procedure HugeInt_Div(a, b: HugeInt; var R: HugeInt); { R := a div b } procedure HugeInt_Mod(a, b: HugeInt; var R: HugeInt); { R := a mod b } function HugeInt_IsNeg(a: HugeInt): Boolean; function HugeInt_Zero(a: HugeInt): Boolean; function HugeInt_Odd(a: HugeInt): Boolean; function HugeInt_Comp(a, b: HugeInt): Integer; {-1:a< 0; 1:a> } procedure HugeInt_Copy(Src: HugeInt; var Dest: HugeInt);{ Dest := Src } procedure String2HugeInt(AString: string; var a: HugeInt); procedure Integer2HugeInt(AInteger: Integer; var a: HugeInt); procedure HugeInt2String(a: HugeInt; var S: string); implementation procedure HugeInt_Copy(Src: HugeInt; var Dest: HugeInt); { Dest := Src } begin Move(Src, Dest, SizeOf(HugeInt)); end;{ HugeInt_Copy } function HugeInt_IsNeg(a: HugeInt): Boolean; begin HugeInt_IsNeg := a[HugeIntMSB] and $80 > 0; end;{ HugeInt_IsNeg } function HugeInt_Zero(a: HugeInt): Boolean; var i: Integer; begin HugeInt_Zero := False; for i := 0 to HugeIntMSB do if a[i] <> 0 then Exit; HugeInt_Zero := True; end;{ HugeInt_Zero } function HugeInt_Odd(a: HugeInt): Boolean; begin HugeInt_Odd := a[0] and 1 > 0; end;{ HugeInt_Odd } function HugeInt_HCD(a: HugeInt): Integer; var i: Integer; begin i := HugeIntMSB; while (i > 0) and (a[i] = 0) do Dec(i); HugeInt_HCD := i; end;{ HugeInt_HCD } procedure HugeInt_SHL(var a: HugeInt; Digits: Integer); { Shift "a" "Digits", digits (bytes) to the left, "Digits" bytes will 'fall off' on the MSB side Fill the LSB side with 0's } var t: Integer; b: HugeInt; begin if Digits > HugeIntMSB then FillChar(a, SizeOf(HugeInt), 0) else if Digits > 0 then begin Move(a[0], a[Digits], HugeIntSize-Digits); FillChar(a[0], Digits, 0); end;{ else if } end;{ HugeInt_SHL } procedure HugeInt_SHR(var a: HugeInt; Digits: Integer); var t: Integer; begin if Digits > HugeIntMSB then FillChar(a, SizeOf(HugeInt), 0) else if Digits > 0 then begin Move(a[Digits], a[0], HugeIntSize-Digits); FillChar(a[HugeIntSize-Digits], Digits, 0); end;{ else if } end;{ HugeInt_SHR } procedure HugeInt_Inc(var a: HugeInt); { a := a + 1 } var i: Integer; h: Word; begin i := 0; h := 1; repeat h := h + a[i]; a[i] := Lo(h); h := Hi(h); Inc(i); until (i > HugeIntMSB) or (h = 0); HugeIntCarry := h > 0; {$IFOPT R+ } if HugeIntCarry then RunError(215); {$ENDIF} end;{ HugeInt_Inc } procedure HugeInt_Dec(var a: HugeInt); { a := a - 1 } var Minus_1: HugeInt; begin { this is the easy way out } FillChar(Minus_1, SizeOf(HugeInt), $FF); { -1 } HugeInt_Add(a, Minus_1, a); end;{ HugeInt_Dec } procedure HugeInt_Min(var a: HugeInt); { a := -a } var i: Integer; begin for i := 0 to HugeIntMSB do a[i] := not a[i]; HugeInt_Inc(a); end;{ HugeInt_Min } function HugeInt_Comp(a, b: HugeInt): Integer; { a = b: ==0; a > b: ==1; a < b: ==-1 } var A_IsNeg, B_IsNeg: Boolean; i: Integer; begin A_IsNeg := HugeInt_IsNeg(a); B_IsNeg := HugeInt_IsNeg(b); if A_IsNeg xor B_IsNeg then if A_IsNeg then HugeInt_Comp := -1 else HugeInt_Comp := 1 else begin if A_IsNeg then HugeInt_Min(a); if B_IsNeg then HugeInt_Min(b); i := HugeIntMSB; while (i > 0) and (a[i] = b[i]) do Dec(i); if A_IsNeg then { both negative! } if a[i] > b[i] then HugeInt_Comp := -1 else if a[i] < b[i] then HugeInt_Comp := 1 else HugeInt_Comp := 0 else { both positive } if a[i] > b[i] then HugeInt_Comp := 1 else if a[i] < b[i] then HugeInt_Comp := -1 else HugeInt_Comp := 0; end;{ else } end;{ HugeInt_Comp } procedure HugeInt_Add(a, b: HugeInt; var R: HugeInt); { R := a + b } var i: Integer; h: Word; begin h := 0; for i := 0 to HugeIntMSB do begin h := h + a[i] + b[i]; R[i] := Lo(h); h := Hi(h); end;{ for } HugeIntCarry := h > 0; {$IFOPT R+ } if HugeIntCarry then RunError(215); {$ENDIF} end;{ HugeInt_Add } procedure HugeInt_Sub(a, b: HugeInt; var R: HugeInt); { R := a - b } var i: Integer; h: Word; begin HugeInt_Min(b); HugeInt_Add(a, b, R); end;{ HugeInt_Sub } procedure HugeInt_Mul(a, b: HugeInt; var R: HugeInt); { R := a * b } var i, j, k: Integer; A_end, B_end: Integer; A_IsNeg, B_IsNeg: Boolean; h: Word; begin A_IsNeg := HugeInt_IsNeg(a); B_IsNeg := HugeInt_IsNeg(b); if A_IsNeg then HugeInt_Min(a); if B_IsNeg then HugeInt_Min(b); A_End := HugeInt_HCD(a); B_End := HugeInt_HCD(b); FillChar(R, SizeOf(R), 0); HugeIntCarry := False; for i := 0 to A_end do begin h := 0; for j:= 0 to B_end do if (i + j) < HugeIntSize then begin h := h + R[i+j] + a[i] * b[j]; R[i+j] := Lo(h); h := Hi(h); end;{ if } k := i + B_End + 1; while (k < HugeIntSize) and (h > 0) do begin h := h + R[k]; R[k] := Lo(h); h := Hi(h); Inc(k); end;{ while } HugeIntCarry := h > 0; {$IFOPT R+} if HugeIntCarry then RunError(215); {$ENDIF} end;{ for } { if all's well... } if A_IsNeg xor B_IsNeg then HugeInt_Min(R); end;{ HugeInt_Mul } procedure HugeInt_DivMod(var a: HugeInt; b: HugeInt; var R: HugeInt); { R := a div b a := a mod b } var MaxShifts, s, q: Integer; d, e: HugeInt; A_IsNeg, B_IsNeg: Boolean; begin if HugeInt_Zero(b) then begin HugeIntDiv0 := True; Exit; end{ if } else HugeIntDiv0 := False; A_IsNeg := HugeInt_IsNeg(a); B_IsNeg := HugeInt_IsNeg(b); if A_IsNeg then HugeInt_Min(a); if B_IsNeg then HugeInt_Min(b); if HugeInt_Comp(a, b) < 0 then { a<b; no need to divide } FillChar(R, SizeOf(R), 0) else begin FillChar(R, SizeOf(R), 0); repeat Move(b, d, SizeOf(HugeInt)); { first work out the number of shifts } MaxShifts := HugeInt_HCD(a) - HugeInt_HCD(b); s := 0; while (s <= MaxShifts) and (HugeInt_Comp(a, d) >= 0) do begin Inc(s); HugeInt_SHL(d, 1); end;{ while } Dec(s); { Make a new copy of b } Move(b, d, SizeOf(HugeInt)); { Shift d as needed } HugeInt_ShL(d, S); { Use e = -d for addition, faster then subtracting d } Move(d, e, SizeOf(HugeInt)); HugeInt_Min(e); Q := 0; { while a >= d do a := a+-d and keep trek of # in Q} while HugeInt_Comp(a, d) >= 0 do begin HugeInt_Add(a, e, a); Inc(Q); end;{ while } { OOps!, one too many subtractions; correct } if HugeInt_IsNeg(a) then begin HugeInt_Add(a, d, a); Dec(Q); end;{ if } HugeInt_SHL(R, 1); R[0] := Q; until HugeInt_Comp(a, b) < 0; if A_IsNeg xor B_IsNeg then HugeInt_Min(R); end;{ else } end;{ HugeInt_Div } procedure HugeInt_DivMod100(var a: HugeInt; var R: Integer); { This works on positive numbers only 256-Based division: R := a mod 100; a:= a div 100; } var Q: HugeInt; S: Integer; begin R := 0; FillChar(Q, SizeOf(Q), 0); S := HugeInt_HCD(a); repeat r := 256*R + a[S]; HugeInt_SHL(Q, 1); Q[0] := R div 100; R := R mod 100; Dec(S); until S < 0; Move(Q, a, SizeOf(Q)); end;{ HugeInt_DivMod100 } procedure HugeInt_Div(a, b: HugeInt; var R: HugeInt); begin HugeInt_DivMod(a, b, R); end;{ HugeInt_Div } procedure HugeInt_Mod(a, b: HugeInt; var R: HugeInt); begin HugeInt_DivMod(a, b, R); Move(a, R, SizeOf(HugeInt)); end;{ HugeInt_Mod } procedure HugeInt2String(a: HugeInt; var S: string); function Str100(i: Integer): string; begin Str100 := Chr(i div 10 + Ord('0')) + Chr(i mod 10 + Ord('0')); end;{ Str100 } var R: Integer; Is_Neg: Boolean; begin S := ''; Is_Neg := HugeInt_IsNeg(a); if Is_Neg then HugeInt_Min(a); repeat HugeInt_DivMod100(a, R); Insert(Str100(R), S, 1); until HugeInt_Zero(a) or (Length(S) = 254); while (Length(S) > 1) and (S[1] = '0') do Delete(S, 1, 1); if Is_Neg then Insert('-', S, 1); end;{ HugeInt2String } procedure String_DivMod256(var S: string; var R: Integer); { This works on Positive numbers Only 10(00)-based division: R := S mod 256; S := S div 256 } var Q: string; begin FillChar(Q, SizeOf(Q), 0); R := 0; while S <> '' do begin R := 10*R + Ord(S[1]) - Ord('0'); Delete(S, 1, 1); Q := Q + Chr(R div 256 + Ord('0')); R := R mod 256; end;{ while } while (Q <> '') and (Q[1] = '0') do Delete(Q, 1, 1); S := Q; end;{ String_DivMod256 } procedure String2HugeInt(AString: string; var a: HugeInt); var i, h: Integer; Is_Neg: Boolean; begin if AString = '' then AString := '0'; Is_Neg := AString[1] = '-'; if Is_Neg then Delete(Astring, 1, 1); i := 0; while (AString <> '') and (i <= HugeIntMSB) do begin String_DivMod256(AString, h); a[i] := h; Inc(i); end;{ while } if Is_Neg then HugeInt_Min(a); end;{ String2HugeInt } procedure Integer2HugeInt(AInteger: Integer; var a: HugeInt); var Is_Neg: Boolean; begin Is_Neg := AInteger < 0; if Is_Neg then AInteger := -AInteger; FillChar(a, SizeOf(HugeInt), 0); Move(AInteger, a, SizeOf(Integer)); if Is_Neg then HugeInt_Min(a); end;{ Integer2HugeInt } end.{ This code came from Lloyd's help file! }
From: "Bobby W. Jones II"<ctech@earthlink.net>
Another alternative is to create a function like the one native in Clipper, called PadL(string,width,character), like the following:
function TfrmFunc.PadL(cVal: string; nWide: integer; cChr: char): string; var i1,nStart: integer; begin if length(cVal) < nWide then begin nStart:=length(cVal); for i1:=nStart to nWide-1 do cVal:=cChar+cVal; end; PadL:=cVal; end;
This then can be called with any string that you want to make a specific length. As with your example, PadL(A,length(B),'0'); It also gives you the flexibility to pad with any character and to be able to set a fixed length (like making sure your text counters remain the same width -- PadL(A,6,'0');
From: "Earl F. Glynn" <EarlGlynn@postoffice.worldnet.att.net>
the Delphi 1.0 UNIT follows (slight changes must be made for Delphi 2.0):
UNIT CRC32; {CRC32 calculates a cyclic redundancy code (CRC), known as CRC-32, using a byte-wise algorithm. (C) Copyright 1989, 1995-1996 Earl F. Glynn, Overland Park, KS. All Rights Reserved. This UNIT was derived from the CRCT FORTRAN 77 program given in "Byte-wise CRC Calculations" by Aram Perez in IEEE Micro, June 1983, pp. 40-50. The constants here are for the CRC-32 generator polynomial, as defined in the Microsoft Systems Journal, March 1995, pp. 107-108 This CRC algorithm emphasizes speed at the expense of the 512 element lookup table.} INTERFACE PROCEDURE CalcCRC32 (p: pointer; nbyte: WORD; VAR CRCvalue: LongInt); PROCEDURE CalcFileCRC32 (FromName: STRING; VAR CRCvalue: LongInt; VAR IOBuffer: pointer; BufferSize: WORD; VAR TotalBytes: LongInt; VAR error: WORD); IMPLEMENTATION CONST table: ARRAY[0..255] OF LongInt = ($00000000, $77073096, $EE0E612C, $990951BA, $076DC419, $706AF48F, $E963A535, $9E6495A3, $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988, $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91, $1DB71064, $6AB020F2, $F3B97148, $84BE41DE, $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7, $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC, $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5, $3B6E20C8, $4C69105E, $D56041E4, $A2677172, $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B, $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940, $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59, $26D930AC, $51DE003A, $C8D75180, $BFD06116, $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F, $2802B89E, $5F058808, $C60CD9B2, $B10BE924, $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D, $76DC4190, $01DB7106, $98D220BC, $EFD5102A, $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433, $7807C9A2, $0F00F934, $9609A88E, $E10E9818, $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01, $6B6B51F4, $1C6C6162, $856530D8, $F262004E, $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457, $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C, $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65, $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2, $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB, $4369E96A, $346ED9FC, $AD678846, $DA60B8D0, $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9, $5005713C, $270241AA, $BE0B1010, $C90C2086, $5768B525, $206F85B3, $B966D409, $CE61E49F, $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4, $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD, $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A, $EAD54739, $9DD277AF, $04DB2615, $73DC1683, $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8, $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1, $F00F9344, $8708A3D2, $1E01F268, $6906C2FE, $F762575D, $806567CB, $196C3671, $6E6B06E7, $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC, $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5, $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252, $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B, $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60, $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79, $CB61B38C, $BC66831A, $256FD2A0, $5268E236, $CC0C7795, $BB0B4703, $220216B9, $5505262F, $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04, $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D, $9B64C2B0, $EC63F226, $756AA39C, $026D930A, $9C0906A9, $EB0E363F, $72076785, $05005713, $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38, $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21, $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E, $81BE16CD, $F6B9265B, $6FB077E1, $18B74777, $88085AE6, $FF0F6A70, $66063BCA, $11010B5C, $8F659EFF, $F862AE69, $616BFFD3, $166CCF45, $A00AE278, $D70DD2EE, $4E048354, $3903B3C2, $A7672661, $D06016F7, $4969474D, $3E6E77DB, $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0, $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9, $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6, $BAD03605, $CDD70693, $54DE5729, $23D967BF, $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94, $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D); TYPE buffer = ARRAY[1..65521] OF BYTE; {largest buffer that can be} {allocated on heap } VAR i: WORD; q: ^buffer; PROCEDURE CalcCRC32 (p: pointer; nbyte: WORD; VAR CRCvalue: LongInt); {The following is a little cryptic (but executes very quickly). The algorithm is as follows: 1. exclusive-or the input byte with the low-order portion of the CRC register to get an INDEX 2. shift the CRC register eight bits to the right 3. exclusive-or the CRC register with the contents of Table[INDEX] 4. repeat steps 1 through 3 for all bytes} BEGIN q := p; FOR i := 1 TO nBYTE DO CRCvalue := (CRCvalue SHR 8) XOR Table[ q^[i] XOR (CRCvalue AND $000000FF) ] END {CalcCRC32}; PROCEDURE CalcFileCRC32 (FromName: STRING; VAR CRCvalue: LongInt; VAR IOBuffer: pointer; BufferSize: WORD; VAR TotalBytes: LongInt; VAR error: WORD); VAR BytesRead: WORD; FromFile : FILE; i : WORD; BEGIN FileMode := 0; {Turbo default is 2 for R/W; 0 is for R/O} CRCValue := $FFFFFFFF; ASSIGN (FromFile,FromName); {$I-} RESET (FromFile,1); {$I+} error := IOResult; IF error = 0 THEN BEGIN TotalBytes := 0; REPEAT BlockRead (FromFile,IOBuffer^,BufferSize,BytesRead); CalcCRC32 (IOBuffer,BytesRead,CRCvalue); INC (TotalBytes, BytesRead) UNTIL BytesRead = 0; CLOSE (FromFile) END; CRCvalue := NOT CRCvalue END {CalcFileCRC32}; END {CRC}.
Paul Cunningham (pjcunningham@cix.compulink.co.uk)
Question[ This may sound trivial, but how do you raise a value to a power? eg). 2^12 = 4095 ]The question is not that trivial. The trouble is that the power function is not that simple. Several distinct situations need to be considered for the function Power(X, N) i.e X^N.
interface type EPowerException = class(Exception) end; implementation function Power(X, N : real) : extended; var t : longint; r : real; isInteger : boolean; begin if N = 0 then begin result := 1.0; exit; end; if X = 1.0 then begin result := 1.0; exit; end; if X = 0.0 then begin if N > 0.0 then begin result := 0.0; exit; end else raise EPowerException.Create('Infinite Result'); end; if (X > 0) then try result := exp(N * ln(X)); exit; except raise EPowerException.Create('Overflow/Underflow Result'); end; { X is negative but we still may compute the result if n is an integer} { try and get integer portion of n into a longint, it will be quicker to } { compute odd n} try t := trunc(n); if (n - t) = 0 then isInteger := true else isInteger := False; except {Bit superfluous as result will probably underflow/overflow anyway} r := int(n); if (n - r) = 0 then begin isInteger := true; if frac(r/2) = 0.5 then t := 1 else t := 2; end else isInteger := False; end; if isInteger then begin {n is an integer} if odd(t) then {n is odd} try result := -exp(N * ln(-X)); exit; except raise EPowerException.Create('Overflow/Underflow Result'); end else {n is even} try result := exp(N * ln(-X)); exit; except raise EPowerException.Create('Overflow/Underflow Result'); end; end else raise EPowerException.Create('Complex Result'); end;
unit uNum2Str; // Possible enhancements // Move strings out to resource files // Put in a general num2str utility interface function Num2Dollars( dNum: double ) : String; implementation uses SysUtils; function LessThan99( dNum: double ) : String; forward; // floating point modulus function FloatMod( i,j: double ): double; begin result := i - (Int(i/j) * j); end; function Hundreds( dNum: double ) : String; var workVar: double; begin if ( dNum < 100 ) or ( dNum > 999 ) then raise Exception.Create( 'hundreds range exceeded' ); result := ''; workVar := Int( dNum / 100 ); if workVar > 0 then result := LessThan99(workVar) + ' Hundred'; end; function OneToNine( dNum: Double ) : String; begin if ( dNum < 1 ) or (dNum > 9 ) then raise exception.create( 'onetonine: value out of range' ); result := 'woops'; if dNum = 1 then result := 'One' else if dNum = 2 then result := 'Two' else if dNum = 3 then result := 'Three' else if dNum = 4 then result := 'Four' else if dNum = 5.0 then result := 'Five' else if dNum = 6 then result := 'Six' else if dNum = 7 then result := 'Seven' else if dNum = 8 then result := 'Eight' else if dNum = 9 then result := 'Nine'; end; function ZeroTo19( dNum: double ) : String; begin if (dNum < 0) or (dNum > 19) then raise Exception.Create( 'Bad value in dNum' ); result := ''; if dNum = 0 then result := 'Zero' else if (dNum >= 1) and (dNum <= 9) then result := OneToNine( dNum ) else if dNum = 10 then result := 'Ten' else if dNum = 11 then result := 'Eleven' else if dNum = 12 then result := 'Twelve' else if dNum = 13 then result := 'Thirteen' else if dNum = 14 then result := 'Fourteen' else if dNum = 15 then result := 'Fifteen' else if dNum = 16 then result := 'Sixteen' else if dNum = 17 then result := 'Seventeen' else if dNum = 18 then result := 'Eighteen' else if dNum = 19 then result := 'Nineteen' else result := 'woops!'; end; function TwentyTo99( dNum: double ) : String; var BigNum: String; begin if ( dNum < 20 ) or ( dNum > 99 ) then raise exception.Create( 'TwentyTo99: dNum out of range!' ); BigNum := 'woops'; if dNum >= 90 then BigNum := 'Ninety' else if dNum >= 80 then BigNum := 'Eighty' else if dNum >= 70 then BigNum := 'Seventy' else if dNum >= 60 then BigNum := 'Sixty' else if dNum >= 50 then BigNum := 'Fifty' else if dNum >= 40 then BigNum := 'Forty' else if dNum >= 30 then BigNum := 'Thirty' else if dNum >= 20 then BigNum := 'Twenty'; // lose the big num dNum := FloatMod( dNum, 10 ); if dNum > 0.00 then result := BigNum + ' ' + OneToNine( dNum ) else result := BigNum; end; function LessThan99( dNum: double ) : String; begin if dNum <= 19 then result := ZeroTo19(dNum) else result := TwentyTo99(dNum); end; function Num2Dollars( dNum: double ) : String; var centsString: String; cents: double; workVar: double; begin result := ''; if dNum < 0 then raise Exception.Create( 'Negative numbers not supported' ); if dNum > 999999999.99 then raise Exception.Create( 'Num2Dollars only supports up to the millions at this point!' ); cents := (dNum - Int( dNum )) * 100.0; if cents = 0.0 then centsString := 'and 00/100 Dollars' else if cents < 10 then centsString := Format( 'and 0%1.0f/100 Dollars', [cents] ) else centsString := Format( 'and %2.0f/100 Dollars', [cents] ); dNum := Int( dNum - (cents / 100.0) ); // lose the cents // deal with million's if (dNum >= 1000000 ) and ( dNum <= 999999999 ) then begin workVar := dNum / 1000000; workVar := Int( workVar ); if (workVar <= 9) then result := ZeroTo19(workVar) else if ( workVar <= 99 ) then result := LessThan99( workVar ) else if ( workVar <= 999 ) then result := Hundreds( workVar ) else result := 'mill fubar'; result := result + ' Million'; dNum := dNum - ( workVar * 1000000 ); end; // deal with 1000's if (dNum >= 1000 ) and ( dNum <= 999999.99 ) then begin // doing the two below statements in one line of code yields some really // freaky floating point errors workVar := dNum/1000; workVar := Int( workVar ); if (workVar <= 9) then result := ZeroTo19(workVar) else if ( workVar <= 99 ) then result := LessThan99( workVar ) else if ( workVar <= 999 ) then result := Hundreds( workVar ) else result := 'thou fubar'; result := result + ' Thousand'; dNum := dNum - ( workVar * 1000 ); end; // deal with 100's if (dNum >= 100.00 ) and (dNum <= 999.99) then begin result := result + ' ' + Hundreds( dNum ); dNum := FloatMod( dNum, 100 ); end; // format in anything less than 100 if ( dNum > 0) or ((dNum = 0) and (Length( result ) = 0)) then begin result := result + ' ' + LessThan99( dNum ); end; result := result + ' ' + centsString; end; end.
Here is a routine (written by a Frank Fetthauer) that I found in a group some days ago:
FORMULA has to be a string containing the formular. Variables x y and z are allowed, as well as the operatins below. Example:
sin(x)*cos(x^y)+exp(cos(x))
uses EVALCOMP; var calc: EVALVEC ; (evalvec is a pointer to an object defined by evalcomp) FORMULA: string; begin FORMULA:='x+y+z'; new (calc,init(FORMULA)); (Building the evaluation tree) writeln ( calc^.eval1d(7) ) ; (x=7 y=0 z=0; result: 7) writeln ( calc^.eval2d(7,8) ) ; (x=7 y=8 z=0; result: 15) writeln ( calc^.eval3d(7,8,9) ) ; (x=7 y=8 z=9; result: 24) dispose(calc,done); (destroing the evaluation tree) end.
x <l;> y ; Logical operations return 1 if true and 0 if false. x <l;= y x >= y x > y x <l; y x = y x + y x - y x eor y ( exclusive or ) x or y x * y x / y x and y x mod y x div y x ^ y ( power ) x shl y x shr y not (x) sinc (x) sinh (x) cosh (x) tanh (x) coth (x) sin (x) cos (x) tan (x) cot (x) sqrt (x) sqr (x) arcsinh (x) arccosh (x) arctanh (x) arccoth (x) arcsin (x) arccos (x) arctan (x) arccot (x) heavy (x) ; 1 for positive numbers, 0 else sgn (x) ; 1 for positive, -1 for negative, 0 for 0 frac (x) exp (x) abs (x) trunc (x) ln (x) odd (x) pred (x) succ (x) round (x) int (x) fac (x) ; x*(x-1)*(x-2)*...*3*2*1 rnd ; Random number in [0,1] rnd (x) ; Random number in [0,x] pi e--------------------------------------------------------------------
unit evalcomp; interface type fun= function(x,y:real):real; evalvec= ^evalobj; evalobj= object f1,f2:evalvec; f1x,f2y:real; f3:fun; function eval:real; function eval1d(x:real):real; function eval2d(x,y:real):real; function eval3d(x,y,z:real):real; constructor init(st:string); destructor done; end; var evalx,evaly,evalz:real; implementation var analysetmp:fun; function search (text,code:string; var pos:integer):boolean; var i,count:integer; flag:boolean; newtext:string; begin if length(text)<l;length(code) then begin search:=false; exit; end; flag:=false; pos:=length(text)-length(code)+1; repeat if code=copy(text,pos,length(code)) then flag:=true else dec(pos); if flag then begin count:=0; for i:= pos+1 to length(text) do begin if copy(text,i,1) = '(' then inc(count); if copy(text,i,1) = ')' then dec(count); end; if count<l;>0 then begin dec(pos); flag:=false; end; end; until (flag=true) or (pos=0); search:=flag; end; function myid(x,y:real):real; begin myid:=x; end; function myunequal(x,y:real):real; begin if x<l;>y then myunequal:=1 else myunequal:=0; end; function mylessequal(x,y:real):real; begin if x<l;=y then mylessequal:=1 else mylessequal:=0; end; function mygreaterequal(x,y:real):real; begin if x>=y then mygreaterequal:=1 else mygreaterequal:=0; end; function mygreater(x,y:real):real; begin if x>y then mygreater:=1 else mygreater:=0; end; function myless(x,y:real):real; begin if x<l;y then myless:=1 else myless:=0; end; function myequal(x,y:real):real; begin if x=y then myequal:=1 else myequal:=0; end; function myadd(x,y:real):real; begin myadd:=x+y; end; function mysub(x,y:real):real; begin mysub:=x-y; end; function myeor(x,y:real):real; begin myeor:=trunc(x) xor trunc(y); end; function myor(x,y:real):real; begin myor:=trunc(x) or trunc(y); end; function mymult(x,y:real):real; begin mymult:=x*y; end; function mydivid(x,y:real):real; begin mydivid:=x/y; end; function myand(x,y:real):real; begin myand:=trunc(x) and trunc(y); end; function mymod(x,y:real):real; begin mymod:=trunc(x) mod trunc(y); end; function mydiv(x,y:real):real; begin mydiv:=trunc(x) div trunc(y); end; function mypower(x,y:real):real; begin if x=0 then mypower:=0 else if x>0 then mypower:=exp(y*ln(x)) else if trunc(y)<l;>y then begin writeln (' Fehler in x^y '); halt; end else if odd(trunc(y))=true then mypower:=-exp(y*ln(-x)) else mypower:=exp(y*ln(-x)) end; function myshl(x,y:real):real; begin myshl:=trunc(x) shl trunc(y); end; function myshr(x,y:real):real; begin myshr:=trunc(x) shr trunc(y); end; function mynot(x,y:real):real; begin mynot:=not trunc(x); end; function mysinc(x,y:real):real; begin if x=0 then mysinc:=1 else mysinc:=sin(x)/x end; function mysinh(x,y:real):real; begin mysinh:=0.5*(exp(x)-exp(-x)) end; function mycosh(x,y:real):real; begin mycosh:=0.5*(exp(x)+exp(-x)) end; function mytanh(x,y:real):real; begin mytanh:=mysinh(x,0)/mycosh(x,0) end; function mycoth(x,y:real):real; begin mycoth:=mycosh(x,0)/mysinh(x,0) end; function mysin(x,y:real):real; begin mysin:=sin(x) end; function mycos(x,y:real):real; begin mycos:=cos(x) end; function mytan(x,y:real):real; begin mytan:=sin(x)/cos(x) end; function mycot(x,y:real):real; begin mycot:=cos(x)/sin(x) end; function mysqrt(x,y:real):real; begin mysqrt:=sqrt(x) end; function mysqr(x,y:real):real; begin mysqr:=sqr(x) end; function myarcsinh(x,y:real):real; begin myarcsinh:=ln(x+sqrt(sqr(x)+1)) end; function mysgn(x,y:real):real; begin if x=0 then mysgn:=0 else mysgn:=x/abs(x) end; function myarccosh(x,y:real):real; begin myarccosh:=ln(x+mysgn(x,0)*sqrt(sqr(x)-1)) end; function myarctanh(x,y:real):real; begin myarctanh:=ln((1+x)/(1-x))/2 end; function myarccoth(x,y:real):real; begin myarccoth:=ln((1-x)/(1+x))/2 end; function myarcsin(x,y:real):real; begin if x=1 then myarcsin:=pi/2 else myarcsin:=arctan(x/sqrt(1-sqr(x))) end; function myarccos(x,y:real):real; begin myarccos:=pi/2-myarcsin(x,0) end; function myarctan(x,y:real):real; begin myarctan:=arctan(x); end; function myarccot(x,y:real):real; begin myarccot:=pi/2-arctan(x) end; function myheavy(x,y:real):real; begin myheavy:=mygreater(x,0) end; function myfrac(x,y:real):real; begin myfrac:=frac(x) end; function myexp(x,y:real):real; begin myexp:=exp(x) end; function myabs(x,y:real):real; begin myabs:=abs(x) end; function mytrunc(x,y:real):real; begin mytrunc:=trunc(x) end; function myln(x,y:real):real; begin myln:=ln(x) end; function myodd(x,y:real):real; begin if odd(trunc(x)) then myodd:=1 else myodd:=0; end; function mypred(x,y:real):real; begin mypred:=pred(trunc(x)); end; function mysucc(x,y:real):real; begin mysucc:=succ(trunc(x)); end; function myround(x,y:real):real; begin myround:=round(x); end; function myint(x,y:real):real; begin myint:=int(x); end; function myfac(x,y:real):real; var n : integer; r : real; begin if x<l;0 then begin writeln(' Fehler in Fakultät '); halt; end; if x = 0 then myfac := 1 else begin r := 1; for n := 1 to trunc ( x ) do r := r * n; myfac:= r; end; end; function myrnd(x,y:real):real; begin myrnd:=random; end; function myrandom(x,y:real):real; begin myrandom:=random(trunc(x)); end; function myevalx(x,y:real):real; begin myevalx:=evalx; end; function myevaly(x,y:real):real; begin myevaly:=evaly; end; function myevalz(x,y:real):real; begin myevalz:=evalz; end; procedure analyse (st:string; var st2,st3:string); label start; var pos:integer; value:real; newterm,term:string; begin term:=st; start: if term='' then begin analysetmp:=myid; st2:='0'; st3:=''; exit; end; newterm:=''; for pos:= 1 to length(term) do if copy(term,pos,1)<l;>' ' then newterm:=newterm+copy(term,pos,1); term:=newterm; if term='' then begin analysetmp:=myid; st2:='0'; st3:=''; exit; end; val(term,value,pos); if pos=0 then begin analysetmp:=myid; st2:=term; st3:=''; exit; end; if search(term,'<l;>',pos) then begin analysetmp:=myunequal; st2:=copy(term,1,pos-1); st3:=copy(term,pos+2,length(term)-pos-1); exit; end; if search(term,'<l;=',pos) then begin analysetmp:=mylessequal; st2:=copy(term,1,pos-1); st3:=copy(term,pos+2,length(term)-pos-1); exit; end; if search(term,'>=',pos) then begin analysetmp:=mygreaterequal; st2:=copy(term,1,pos-1); st3:=copy(term,pos+2,length(term)-pos-1); exit; end; if search(term,'>',pos) then begin analysetmp:=mygreater; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'<l;',pos) then begin analysetmp:=myless; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'=',pos) then begin analysetmp:=myequal; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'+',pos) then begin analysetmp:=myadd; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'-',pos) then begin analysetmp:=mysub; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'eor',pos) then begin analysetmp:=myeor; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if search(term,'or',pos) then begin analysetmp:=myor; st2:=copy(term,1,pos-1); st3:=copy(term,pos+2,length(term)-pos-1); exit; end; if search(term,'*',pos) then begin analysetmp:=mymult; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'/',pos) then begin analysetmp:=mydivid; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'and',pos) then begin analysetmp:=myand; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if search(term,'mod',pos) then begin analysetmp:=mymod; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if search(term,'div',pos) then begin analysetmp:=mydiv; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if search(term,'^',pos) then begin analysetmp:=mypower; st2:=copy(term,1,pos-1); st3:=copy(term,pos+1,length(term)-pos); exit; end; if search(term,'shl',pos) then begin analysetmp:=myshl; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if search(term,'shr',pos) then begin analysetmp:=myshr; st2:=copy(term,1,pos-1); st3:=copy(term,pos+3,length(term)-pos-2); exit; end; if copy(term,1,1)='(' then begin term:=copy(term,2,length(term)-2); goto start; end; if copy(term,1,3)='not' then begin analysetmp:=mynot; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,4)='sinc' then begin analysetmp:=mysinc; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,4)='sinh' then begin analysetmp:=mysinh; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,4)='cosh' then begin analysetmp:=mycosh; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,4)='tanh' then begin analysetmp:=mytanh; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,4)='coth' then begin analysetmp:=mycoth; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,3)='sin' then begin analysetmp:=mysin; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,3)='cos' then begin analysetmp:=mycos; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,3)='tan' then begin analysetmp:=mytan; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,3)='cot' then begin analysetmp:=mycot; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,4)='sqrt' then begin analysetmp:=mysqrt; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,3)='sqr' then begin analysetmp:=mysqr; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,7)='arcsinh' then begin analysetmp:=myarcsinh; st2:=copy(term,8,length(term)-7); st3:=''; exit; end; if copy(term,1,7)='arccosh' then begin analysetmp:=myarccosh; st2:=copy(term,8,length(term)-7); st3:=''; exit; end; if copy(term,1,7)='arctanh' then begin analysetmp:=myarctanh; st2:=copy(term,8,length(term)-7); st3:=''; exit; end; if copy(term,1,7)='arccoth' then begin analysetmp:=myarccoth; st2:=copy(term,8,length(term)-7); st3:=''; exit; end; if copy(term,1,6)='arcsin' then begin analysetmp:=myarcsin; st2:=copy(term,7,length(term)-6); st3:=''; exit; end; if copy(term,1,6)='arccos' then begin analysetmp:=myarccos; st2:=copy(term,7,length(term)-6); st3:=''; exit; end; if copy(term,1,6)='arctan' then begin analysetmp:=myarctan; st2:=copy(term,7,length(term)-6); st3:=''; exit; end; if copy(term,1,6)='arccot' then begin analysetmp:=myarccot; st2:=copy(term,7,length(term)-6); st3:=''; exit; end; if copy(term,1,5)='heavy' then begin analysetmp:=myheavy; st2:=copy(term,6,length(term)-5); st3:=''; exit; end; if copy(term,1,3)='sgn' then begin analysetmp:=mysgn; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,4)='frac' then begin analysetmp:=myfrac; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,3)='exp' then begin analysetmp:=myexp; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,3)='abs' then begin analysetmp:=myabs; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,5)='trunc' then begin analysetmp:=mytrunc; st2:=copy(term,6,length(term)-5); st3:=''; exit; end; if copy(term,1,2)='ln' then begin analysetmp:=myln; st2:=copy(term,3,length(term)-2); st3:=''; exit; end; if copy(term,1,3)='odd' then begin analysetmp:=myodd; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,4)='pred' then begin analysetmp:=mypred; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,4)='succ' then begin analysetmp:=mysucc; st2:=copy(term,5,length(term)-4); st3:=''; exit; end; if copy(term,1,5)='round' then begin analysetmp:=myround; st2:=copy(term,6,length(term)-5); st3:=''; exit; end; if copy(term,1,3)='int' then begin analysetmp:=myint; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if copy(term,1,3)='fac' then begin analysetmp:=myfac; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if term='rnd' then begin analysetmp:=myrnd; st2:=''; st3:=''; exit; end; if copy(term,1,3)='rnd' then begin analysetmp:=myrandom; st2:=copy(term,4,length(term)-3); st3:=''; exit; end; if term='x' then begin analysetmp:=myevalx; st2:=''; st3:=''; exit; end; if term='y' then begin analysetmp:=myevaly; st2:=''; st3:=''; exit; end; if term='z' then begin analysetmp:=myevalz; st2:=''; st3:=''; exit; end; if (term='pi') then begin analysetmp:=myid; str(pi,st2); st3:=''; exit; end; if term='e' then begin analysetmp:=myid; str(exp(1),st2); st3:=''; exit; end; writeln(' WARNING : UNDECODABLE FORMULA '); analysetmp:=myid; st2:=''; st3:=''; end; function evalobj.eval:real; var tmpx,tmpy:real; begin if f1=nil then tmpx:=f1x else tmpx:=f1^.eval; if f2=nil then tmpy:=f2y else tmpy:=f2^.eval; eval:=f3(tmpx,tmpy); end; function evalobj.eval1d(x:real):real; begin evalx:=x; evaly:=0; evalz:=0; eval1d:=eval; end; function evalobj.eval2d(x,y:real):real; begin evalx:=x; evaly:=y; evalz:=0; eval2d:=eval; end; function evalobj.eval3d(x,y,z:real):real; begin evalx:=x; evaly:=y; evalz:=z; eval3d:=eval; end; constructor evalobj.init(st:string); var st2,st3:string; error:integer; begin f1:=nil; f2:=nil; analyse(st,st2,st3); f3:=analysetmp; val(st2,f1x,error); if st2='' then begin f1x:=0; error:=0; end; if error<l;>0 then new (f1,init(st2)); val(st3,f2y,error); if st3='' then begin f2y:=0; error:=0; end; if error<l;>0 then new (f2,init(st3)); end; destructor evalobj.done; begin if f1<l;>nil then dispose(f1,done); if f2<l;>nil then dispose(f2,done); end; end.
{ A word is arranged like this... } { The Word - 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 } { Bit Number - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 } Const Bit0 = 1; Bit1 = 2; Bit2 = 4; Bit3 = 8; Bit4 = 16; Bit5 = 32; Bit6 = 64; Bit7 = 128; Bit8 = 256; Bit9 = 512; Bit10 = 1024; Bit11 = 2048; Bit12 = 4096; Bit13 = 8192; Bit14 = 16384; Bit15 = 32768; Procedure SetBit(SetWord, BitNum : Word); Begin SetWord := SetWord Or BitNum; { Set bit } End; Procedure ClearBit(SetWord, BitNum : Word); Begin SetWord := SetWord Or BitNum; { Set bit } SetWord := SetWord Xor BitNum; { Toggle bit } End; Procedure ToggleBit(SetWord, BitNum : Word); Begin SetWord := SetWord Xor BitNum; { Toggle bit } End; Function GetBitStat(SetWord, BitNum : Word) : Boolean; Begin If SetWord And BitNum = BitNum Then { If bit is set } GetBitStat := True Else GetBitStat := False; End;