source: branches/ByteArray/BigInt.pas

Last change on this file was 55, checked in by chronos, 6 months ago
  • Modified: Extended BigInt type implementation.
File size: 13.3 KB
Line 
1unit BigInt;
2
3interface
4
5uses
6 Classes, SysUtils, Math;
7
8type
9 TArrayOfByte = array of Byte;
10
11 TBigIntSize = Byte;
12
13 { TBigInt }
14
15 TBigInt = record
16 private
17 FData: array of Byte;
18 function GetData(Index: TBigIntSize): Byte;
19 function GetSize: TBigIntSize;
20 procedure SetData(Index: TBigIntSize; AValue: Byte);
21 procedure SetSize(AValue: TBigIntSize);
22 public
23 class operator Implicit(A: Byte): TBigInt;
24 class operator Implicit(A: Word): TBigInt;
25 class operator Implicit(A: ShortInt): TBigInt;
26 class operator Implicit(A: Integer): TBigInt;
27 class operator Implicit(A: QWord): TBigInt;
28 class operator Implicit(A: Int64): TBigInt;
29 class operator Implicit(A: TBigInt): UInt8; // Byte
30 class operator Implicit(A: TBigInt): Int8; // ShortInt
31 class operator Implicit(A: TBigInt): UInt16; // Word
32 class operator Implicit(A: TBigInt): Int16; // SmallInt
33 class operator Implicit(A: TBigInt): UInt32; // LongWord, DWord, Cardinal
34 class operator Implicit(A: TBigInt): Int32; // Int32, LongInt
35 class operator Implicit(A: TBigInt): UInt64; // QWord
36 class operator Implicit(A: TBigInt): Int64;
37 class operator Implicit(A: TBigInt): PByte;
38 class operator Negative(A: TBigInt): TBigInt;
39 class operator Inc(A: TBigInt) : TBigInt;
40 class operator Dec(A: TBigInt) : TBigInt;
41 class operator Add(A, B: TBigInt): TBigInt;
42 class operator Subtract(A, B: TBigInt): TBigInt;
43 class operator Equal(A, B: TBigInt): Boolean;
44 class operator NotEqual(A, B: TBigInt): Boolean;
45 class operator LessThan(A, B: TBigInt): Boolean;
46 class operator LessThanOrEqual(A, B: TBigInt): Boolean;
47 class operator GreaterThan(A, B: TBigInt): Boolean;
48 class operator GreaterThanOrEqual(A, B: TBigInt): Boolean;
49 class operator BitwiseXor(A, B: TBigInt): TBigInt;
50 class operator BitwiseAnd(A, B: TBigInt): TBigInt;
51 class operator BitwiseOr(A, B: TBigInt): TBigInt;
52 class operator LeftShift(A: TBigInt; B: Integer): TBigInt;
53 class operator RightShift(A: TBigInt; B: Integer): TBigInt;
54 class operator Modulus(A, B: TBigInt): TBigInt;
55 class operator IntDivide(A, B: TBigInt): TBigInt;
56 procedure Shrink;
57 function IsNegative: Boolean;
58 function IsZero: Boolean;
59 function IsPositive: Boolean;
60 procedure Invert;
61 procedure SetByteArray(AData: TArrayOfByte; ASize: TBigIntSize);
62 procedure GetByteArray(var AData: TArrayOfByte; ASize: TBigIntSize);
63 function Copy(Size: TBigIntSize): TBigInt; overload;
64 function Copy: TBigInt; overload;
65 property Size: TBigIntSize read GetSize write SetSize;
66 property Data[Index: TBigIntSize]: Byte read GetData write SetData;
67 end;
68
69function TryStrToBigInt(const S: string; out I: TBigInt): Boolean;
70function IntToStr(Value: TBigInt): string; overload;
71function IntToHex(Value: TBigInt): string; overload;
72function IntToHex(Value: TBigInt; Digits: Integer): string; overload;
73
74
75implementation
76
77resourcestring
78 SUnsupportedByteSize = 'Unsupported byte size';
79 SOutOfRange = 'Out of range';
80
81const
82 HexDigits: array[0..15] of Char = '0123456789ABCDEF';
83
84function TryStrToBigInt(const S: string; out I: TBigInt): Boolean;
85var
86 Value: Int64;
87begin
88 Result := TryStrToInt64(S, Value);
89 I := Value;
90end;
91
92function IntToHex(Value: TBigInt): string;
93begin
94 Result := '';
95 while Value <> 0 do begin
96 Result := HexDigits[Value and 15] + Result;
97 Value := Value shr 4;
98 end;
99 if Result = '' then Result := '0';
100end;
101
102function IntToHex(Value: TBigInt; Digits: Integer): string;
103var
104 I: Integer;
105begin
106 if Digits = 0 then
107 Digits := 1;
108 Result := '';
109 SetLength(Result, Digits);
110 for I := 0 to Digits - 1 do
111 begin
112 Result[Digits - I] := HexDigits[Value and 15];
113 Value := Value shr 4;
114 end ;
115 while Value <> 0 do begin
116 Result := HexDigits[Value and 15] + Result;
117 Value := Value shr 4;
118 end;
119end;
120
121function IntToStr(Value: TBigInt): string;
122begin
123 Result := '';
124 if Value < 0 then begin
125 Value := -Value;
126 while Value > 9 do begin
127 Result := Chr(Ord('0') + (Value mod 10)) + Result;
128 Value := Value div 10;
129 end;
130 Result := '-' + Chr(Ord('0') + (Value mod 10)) + Result;
131 end else begin
132 while Value > 9 do begin
133 Result := Chr(Ord('0') + (Value mod 10)) + Result;
134 Value := Value div 10;
135 end;
136 Result := Chr(Ord('0') + Value) + Result;
137 end;
138end;
139
140{ TBigInt }
141
142function TBigInt.GetSize: TBigIntSize;
143begin
144 Result := Length(FData);
145end;
146
147function TBigInt.GetData(Index: TBigIntSize): Byte;
148begin
149 if Index < Size then Result := FData[Index]
150 else Result := 0;
151end;
152
153procedure TBigInt.SetData(Index: TBigIntSize; AValue: Byte);
154begin
155 if Index >= Integer(Size) then raise Exception.Create(SOutOfRange);
156 FData[Index] := AValue;
157end;
158
159procedure TBigInt.SetSize(AValue: TBigIntSize);
160var
161 LastSize: TBigIntSize;
162begin
163 LastSize := GetSize;
164 SetLength(FData, AValue);
165 if AValue > LastSize then
166 FillChar(FData[LastSize], AValue - LastSize, 0);
167end;
168
169class operator TBigInt.Implicit(A: Byte): TBigInt;
170begin
171 Result.Size := 1;
172 Result.FData[0] := A;
173end;
174
175class operator TBigInt.Implicit(A: Word): TBigInt;
176begin
177 Result.Size := 2;
178 PWord(@Result.FData[0])^ := A;
179 Result.Shrink;
180end;
181
182class operator TBigInt.Implicit(A: ShortInt): TBigInt;
183begin
184 Result.Size := 1;
185 PByte(@Result.FData[0])^ := A;
186 Result.Shrink;
187end;
188
189class operator TBigInt.Implicit(A: Integer): TBigInt;
190begin
191 Result.Size := 4;
192 PInteger(@Result.FData[0])^ := A;
193 Result.Shrink;
194end;
195
196class operator TBigInt.Implicit(A: QWord): TBigInt;
197begin
198 Result.Size := 8;
199 PQWord(@Result.FData[0])^ := A;
200 Result.Shrink;
201end;
202
203class operator TBigInt.Implicit(A: Int64): TBigInt;
204begin
205 Result.Size := 8;
206 PInt64(@Result.FData[0])^ := A;
207 Result.Shrink;
208end;
209
210class operator TBigInt.Implicit(A: TBigInt): UInt8;
211begin
212 if A.Size = 1 then Result := A.FData[0]
213 else raise Exception.Create(SUnsupportedByteSize);
214end;
215
216class operator TBigInt.Implicit(A: TBigInt): Int8;
217begin
218 if A.Size = 1 then Result := A.FData[0]
219 else raise Exception.Create(SUnsupportedByteSize);
220end;
221
222class operator TBigInt.Implicit(A: TBigInt): UInt16;
223begin
224 if A.Size = 2 then Result := PUInt16(@A.FData[0])^
225 else raise Exception.Create(SUnsupportedByteSize);
226end;
227
228class operator TBigInt.Implicit(A: TBigInt): Int16;
229begin
230 if A.Size = 2 then Result := PInt16(@A.FData[0])^
231 else raise Exception.Create(SUnsupportedByteSize);
232end;
233
234class operator TBigInt.Implicit(A: TBigInt): Int32;
235begin
236 case A.Size of
237 1: Result := PByte(@A.FData[0])^;
238 2: Result := PWord(@A.FData[0])^;
239 3: Result := PWord(@A.FData[0])^ or (PByte(@A.FData[2])^ shl 16);
240 4: Result := PDWord(@A.FData[0])^;
241 8: Result := PQWord(@A.FData[0])^;
242 else raise Exception.Create(SUnsupportedByteSize);
243 end;
244end;
245
246class operator TBigInt.Implicit(A: TBigInt): UInt32;
247begin
248 if A.Size = 4 then Result := PInt32(@A.FData[0])^
249 else raise Exception.Create(SUnsupportedByteSize);
250end;
251
252class operator TBigInt.Implicit(A: TBigInt): UInt64;
253begin
254 if A.Size = 1 then Result := PUInt8(@A.FData[0])^
255 else if A.Size = 2 then Result := PUInt16(@A.FData[0])^
256 else if A.Size = 4 then Result := PUInt32(@A.FData[0])^
257 else if A.Size = 8 then Result := PUInt64(@A.FData[0])^
258 else raise Exception.Create(SUnsupportedByteSize);
259end;
260
261class operator TBigInt.Implicit(A: TBigInt): Int64;
262begin
263 if A.Size = 1 then Result := PInt8(@A.FData[0])^
264 else if A.Size = 2 then Result := PInt16(@A.FData[0])^
265 else if A.Size = 4 then Result := PInt32(@A.FData[0])^
266 else if A.Size = 8 then Result := PInt64(@A.FData[0])^
267 else raise Exception.Create(SUnsupportedByteSize);
268end;
269
270class operator TBigInt.Implicit(A: TBigInt): PByte;
271begin
272 if A.Size = 4 then Result := PByte(@PInteger(@A.FData[0])^)
273 else raise Exception.Create(SUnsupportedByteSize);
274end;
275
276class operator TBigInt.Negative(A: TBigInt): TBigInt;
277begin
278 Result := A.Copy(A.Size);
279 Result.Invert;
280 Result := Result + 1;
281end;
282
283class operator TBigInt.Inc(A: TBigInt): TBigInt;
284begin
285 Result := A + 1;
286end;
287
288class operator TBigInt.Dec(A: TBigInt): TBigInt;
289begin
290 Result := A - 1;
291end;
292
293class operator TBigInt.Add(A, B: TBigInt): TBigInt;
294var
295 I: Integer;
296 V: SmallInt;
297 Carry: Byte;
298 Size: Byte;
299begin
300 Size := Max(A.Size, B.Size);
301 Result.Size := Size;
302 Carry := 0;
303 I := 0;
304 while (I < Size) or (Carry > 0) do begin
305 if I >= Result.Size then Result.Size := I + 1;
306 V := A.Data[I] + B.Data[I] + Carry;
307 if V >= 256 then begin
308 Carry := 1;
309 end else Carry := 0;
310 Result.Data[I] := V and $ff;
311 Inc(I);
312 end;
313end;
314
315class operator TBigInt.Subtract(A, B: TBigInt): TBigInt;
316var
317 Size: TBigIntSize;
318begin
319 Size := Max(A.Size, B.Size);
320 Result := A + -B;
321 Result.Size := Size;
322 Result.Shrink;
323end;
324
325class operator TBigInt.Equal(A, B: TBigInt): Boolean;
326var
327 I: Byte;
328begin
329 Result := A.Size = B.Size;
330 if not Result then Exit;
331 for I := 0 to A.Size - 1 do
332 if A.FData[I] <> B.FData[I] then begin
333 Result := False;
334 Break;
335 end;
336end;
337
338class operator TBigInt.NotEqual(A, B: TBigInt): Boolean;
339var
340 I: Byte;
341begin
342 Result := A.Size = B.Size;
343 if not Result then Exit;
344 for I := 0 to A.Size - 1 do
345 if A.FData[I] <> B.FData[I] then begin
346 Result := False;
347 Break;
348 end;
349 Result := not Result;
350end;
351
352class operator TBigInt.LessThan(A, B: TBigInt): Boolean;
353var
354 Temp: TBigInt;
355begin
356 Temp := A - B;
357 Result := Temp.IsNegative;
358end;
359
360class operator TBigInt.LessThanOrEqual(A, B: TBigInt): Boolean;
361var
362 Temp: TBigInt;
363begin
364 Temp := A - B;
365 Result := Temp.IsNegative or Temp.IsZero;
366end;
367
368class operator TBigInt.GreaterThan(A, B: TBigInt): Boolean;
369var
370 Temp: TBigInt;
371begin
372 Temp := A - B;
373 Result := Temp.IsPositive and not Temp.IsZero;
374end;
375
376class operator TBigInt.GreaterThanOrEqual(A, B: TBigInt): Boolean;
377var
378 Temp: TBigInt;
379begin
380 Temp := A - B;
381 Result := Temp.IsPositive;
382end;
383
384class operator TBigInt.BitwiseXor(A, B: TBigInt): TBigInt;
385var
386 I: TBigIntSize;
387begin
388 Result.Size := Max(A.Size, B.Size);
389 for I := 0 to Result.Size - 1 do
390 Result.Data[I] := A.Data[I] xor B.Data[I];
391 Result.Shrink;
392end;
393
394class operator TBigInt.BitwiseAnd(A, B: TBigInt): TBigInt;
395var
396 I: TBigIntSize;
397begin
398 Result.Size := Max(A.Size, B.Size);
399 for I := 0 to Result.Size - 1 do
400 Result.Data[I] := A.Data[I] and B.Data[I];
401 Result.Shrink;
402end;
403
404class operator TBigInt.BitwiseOr(A, B: TBigInt): TBigInt;
405var
406 I: TBigIntSize;
407begin
408 Result.Size := Max(A.Size, B.Size);
409 for I := 0 to Result.Size - 1 do
410 Result.Data[I] := A.Data[I] or B.Data[I];
411 Result.Shrink;
412end;
413
414class operator TBigInt.LeftShift(A: TBigInt; B: Integer): TBigInt;
415var
416 ByteShift: TBigIntSize;
417 BitShift: Byte;
418 I: Integer;
419begin
420 if (B and 7) = 0 then begin
421 // Full byte shift
422 ByteShift := B shr 3;
423 Result.Size := A.Size + ByteShift;
424 Move(A.FData[0], Result.FData[ByteShift], A.Size);
425 FillChar(Result.FData[0], ByteShift, 0);
426 end else begin
427 // Partial byte shift
428 ByteShift := B shr 3;
429 BitShift := B - ByteShift;
430 Result.Size := Result.Size + ByteShift + 1;
431 for I := 0 to A.Size - 1 do begin
432 Result.FData[I + ByteShift] := (A.FData[I] shl BitShift) and $ff;
433 if I > 0 then Result.FData[I + ByteShift] := Result.FData[I + ByteShift] or (A.FData[I] shl BitShift shl 8);
434 end;
435 end;
436 Result.Shrink;
437end;
438
439class operator TBigInt.RightShift(A: TBigInt; B: Integer): TBigInt;
440var
441 ByteShift: TBigIntSize;
442 BitShift: Byte;
443 I: Integer;
444begin
445 if (B and 7) = 0 then begin
446 // Full byte shift
447 ByteShift := B shr 3;
448 Result.Size := A.Size - ByteShift;
449 Move(A.FData[ByteShift], Result.FData[0], A.Size);
450 end else begin
451 // Partial byte shift
452 ByteShift := B shr 3;
453 BitShift := B - ByteShift;
454 Result.Size := Result.Size - ByteShift;
455 for I := 0 to A.Size - 1 do begin
456 Result.FData[I] := (A.FData[I + ByteShift] shr BitShift) and $ff;
457 if I < (A.Size - 1) then Result.FData[I] := Result.FData[I] or (((A.FData[I + ByteShift] shl 8) shr BitShift) and $ff);
458 end;
459 end;
460 Result.Shrink;
461end;
462
463class operator TBigInt.Modulus(A, B: TBigInt): TBigInt;
464begin
465
466end;
467
468class operator TBigInt.IntDivide(A, B: TBigInt): TBigInt;
469begin
470
471end;
472
473procedure TBigInt.Shrink;
474var
475 I: Byte;
476begin
477 I := Size - 1;
478 while (I > 0) and (FData[I] = 0) do
479 Dec(I);
480 Size := I + 1;
481end;
482
483function TBigInt.IsNegative: Boolean;
484begin
485 Result := (FData[Size - 1] and $80) = $80;
486end;
487
488function TBigInt.IsZero: Boolean;
489var
490 I: TBigIntSize;
491begin
492 Result := True;
493 for I := 0 to Size - 1 do
494 if FData[I] <> 0 then begin
495 Result := False;
496 Break;
497 end;
498end;
499
500function TBigInt.IsPositive: Boolean;
501begin
502 Result := (FData[Size - 1] and $80) = 0;
503end;
504
505procedure TBigInt.Invert;
506var
507 I: Byte;
508begin
509 for I := 0 to Size - 1 do
510 FData[I] := FData[I] xor $ff;
511end;
512
513procedure TBigInt.SetByteArray(AData: TArrayOfByte; ASize: TBigIntSize);
514begin
515 Size := ASize;
516 Move(AData[0], FData[0], Size);
517end;
518
519procedure TBigInt.GetByteArray(var AData: TArrayOfByte; ASize: TBigIntSize);
520begin
521 SetLength(AData, ASize);
522 Move(FData[0], AData[0], Size);
523end;
524
525function TBigInt.Copy(Size: TBigIntSize): TBigInt;
526begin
527 Result.Size := Size;
528 case Result.Size of
529 1: PByte(@Result.FData[0])^ := PByte(@FData[0])^;
530 2: PWord(@Result.FData[0])^ := PWord(@FData[0])^;
531 4: PDWord(@Result.FData[0])^ := PDWord(@FData[0])^;
532 8: PQWord(@Result.FData[0])^ := PQWord(@FData[0])^;
533 else Move(PByte(@FData[0])^, PByte(@Result.FData[0])^, Size);
534 end;
535end;
536
537function TBigInt.Copy: TBigInt;
538begin
539 Result := Copy(Size);
540end;
541
542end.
543
Note: See TracBrowser for help on using the repository browser.