MathgeomGLS
570 строк · 12.1 Кб
1unit Velthuis.Numerics;
2
3interface
4
5(*
6Compare
7CompareTo
8HashCode
9HighestOneBit
10LowestOneBit
11Reverse
12ReverseBytes
13RotateLeft
14RotateRight
15Sign
16ToBinaryString
17ToHexString
18ToOctalString
19ToString
20ToString(base)
21*)
22
23// For Delphi XE3 and up:
24{$IF CompilerVersion >= 24.0 }
25{$LEGACYIFEND ON}
26{$IFEND}
27
28// For Delphi XE and up:
29{$IF CompilerVersion >= 22.0}
30{$CODEALIGN 16}
31{$ALIGN 16}
32{$IFEND}
33
34uses
35Math, Types;
36
37function BitCount(U: UInt8): Integer; overload;
38function BitCount(U: UInt16): Integer; overload;
39function BitCount(S: Int32): Integer; overload;
40function BitCount(U: UInt32): Integer; overload;
41
42function BitLength(S: Int32): Integer; overload;
43function BitLength(U: UInt32): Integer; overload;
44
45function HighestOneBit(S: Int32): Int32; overload;
46function HighestOneBit(U: UInt32): UInt32; overload;
47
48function IsPowerOfTwo(S: Int32): Boolean; overload;
49function IsPowerOfTwo(U: UInt32): Boolean; overload;
50
51function LowestOneBit(S: Int32): Int32; overload;
52function LowestOneBit(U: UInt32): UInt32; overload;
53
54function NumberOfLeadingZeros(U: UInt16): Integer; overload;
55function NumberOfLeadingZeros(S: Int32): Integer; overload;
56function NumberOfLeadingZeros(U: UInt32): Integer; overload;
57function NumberOfTrailingZeros(U: UInt32): Integer; overload;
58
59function Reverse(U: UInt8): UInt8; overload;
60function Reverse(U: UInt16): UInt16; overload;
61function Reverse(S: Int32): Int32; overload;
62function Reverse(U: UInt32): UInt32; overload;
63
64function ReverseBytes(S: Int32): Int32; overload;
65function ReverseBytes(U: UInt32): UInt32; overload;
66
67function RotateLeft(S: Int32; Distance: Integer): Int32; overload;
68function RotateLeft(U: UInt32; Distance: Integer): UInt32; overload;
69
70function RotateRight(S: Int32; Distance: Integer): Int32; overload;
71function RotateRight(U: UInt32; Distance: Integer): UInt32; overload;
72
73function Sign(S: Int32): TValueSign;
74
75function ToBinaryString(S: Int32): string; overload;
76function ToBinaryString(U: UInt32): string; overload;
77
78function ToHexString(S: Int32): string; overload;
79function ToHexString(U: UInt32): string; overload;
80
81function ToOctalString(S: Int32): string; overload;
82function ToOctalString(U: UInt32): string; overload;
83
84function ToString(S: Int32; Base: Byte): string; overload;
85function ToString(U: UInt32; Base: Byte): string; overload;
86
87implementation
88
89// https://en.wikipedia.org/wiki/Find_first_set
90
91uses
92SysUtils;
93
94const
95// Currently not used.
96NLZDeBruijn32Mult = $07C4ACDD;
97NLZDeBruijn32: array[0..31] of Byte =
98(
9931, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
10023, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
101);
102
103NTZDeBruijn32Mult = $077CB531;
104NTZDeBruijn32: array[0..31] of Byte =
105(
1060, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
10731, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
108);
109
110BitCounts: array[0..15] of Byte = (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
111
112function BitCount(U: UInt8): Integer;
113begin
114Result := BitCounts[U and $0F] + BitCounts[U shr 4];
115end;
116
117function BitCount(U: UInt16): Integer;
118{$IF DEFINED(WIN32)}
119asm
120MOV DX,AX
121SHR DX,1
122AND DX,$5555
123SUB AX,DX
124MOV DX,AX
125AND AX,$3333
126SHR DX,2
127AND DX,$3333
128ADD AX,DX
129MOV DX,AX
130SHR DX,4
131ADD AX,DX
132AND AX,$0F0F
133MOV DX,AX
134SHR AX,8
135ADD AX,DX
136AND EAX,$7F
137end;
138{$ELSEIF DEFINED(WIN64)}
139asm
140.NOFRAME
141
142MOV AX,CX
143SHR CX,1
144AND CX,$5555
145SUB AX,CX
146MOV CX,AX
147AND AX,$3333
148SHR CX,2
149AND CX,$3333
150ADD AX,CX
151MOV CX,AX
152SHR CX,4
153ADD AX,CX
154AND AX,$0F0F
155MOV CX,AX
156SHR AX,8
157ADD AX,CX
158AND EAX,$7F
159end;
160{$ELSE PUREPASCAL}
161begin
162U := U - ((U shr 1) and $5555);
163U := (U and $3333) + ((U shr 2) and $3333);
164U := (U + (U shr 4)) and $0F0F;
165U := U + (U shr 8);
166Result := U and $7F;
167end;
168{$IFEND PUREPASCAL}
169
170function BitCount(S: Int32): Integer;
171begin
172Result := BitCount(UInt32(S));
173end;
174
175// Faster than 16 bit table lookups
176function BitCount(U: UInt32): Integer;
177{$IF DEFINED(WIN32)}
178asm
179MOV EDX,EAX
180SHR EDX,1
181AND EDX,$55555555
182SUB EAX,EDX
183MOV EDX,EAX
184AND EAX,$33333333
185SHR EDX,2
186AND EDX,$33333333
187ADD EAX,EDX
188MOV EDX,EAX
189SHR EDX,4
190ADD EAX,EDX
191AND EAX,$0F0F0F0F
192MOV EDX,EAX
193SHR EAX,8
194ADD EAX,EDX
195MOV EDX,EAX
196SHR EDX,16
197ADD EAX,EDX
198AND EAX,$7F
199end;
200{$ELSEIF DEFINED(WIN64)}
201asm
202.NOFRAME
203
204MOV EAX,ECX
205SHR ECX,1
206AND ECX,$55555555
207SUB EAX,ECX
208MOV ECX,EAX
209AND EAX,$33333333
210SHR ECX,2
211AND ECX,$33333333
212ADD EAX,ECX
213MOV ECX,EAX
214SHR ECX,4
215ADD EAX,ECX
216AND EAX,$0F0F0F0F
217MOV ECX,EAX
218SHR EAX,8
219ADD EAX,ECX
220MOV ECX,EAX
221SHR ECX,16
222ADD EAX,ECX
223AND EAX,$7F
224end;
225{$ELSE PUREPASCAL}
226begin
227U := U - ((U shr 1) and $55555555);
228U := (U and $33333333) + ((U shr 2) and $33333333);
229U := (U + (U shr 4)) and $0F0F0F0F;
230U := U + (U shr 8);
231U := U + (U shr 16);
232Result := U and $7F;
233end;
234{$IFEND PUREPASCAL}
235
236function BitLength(S: Int32): Integer;
237begin
238Result := BitLength(UInt32(S));
239end;
240
241function BitLength(U: UInt32): Integer;
242begin
243Result := 32 - NumberOfLeadingZeros(U);
244end;
245
246function IsPowerOfTwo(S: Int32): Boolean;
247begin
248Result := IsPowerofTwo(UInt32(Abs(S)));
249end;
250
251function IsPowerOfTwo(U: UInt32): Boolean;
252begin
253Result := (U and (U - 1)) = 0;
254end;
255
256function HighestOneBit(S: Int32): Int32;
257begin
258Result := Int32(HighestOneBit(UInt32(S)));
259end;
260
261function HighestOneBit(U: UInt32): UInt32;
262begin
263if U = 0 then
264Result := 0
265else
266Result := UInt32(1) shl (31 - NumberOfLeadingZeros(U));
267end;
268
269function LowestOneBit(S: Int32): Int32;
270begin
271Result := Int32(LowestOneBit(UInt32(S)));
272end;
273
274function LowestOneBit(U: UInt32): UInt32;
275begin
276Result := U and -Int32(U);
277end;
278
279function NumberOfLeadingZeros(U: UInt16): Integer;
280{$IF DEFINED(WIN32)}
281asm
282MOVZX EAX,AX
283BSR EDX,EAX
284JNZ @Invert
285MOV EAX,16
286RET
287
288@Invert:
289
290MOV EAX,15
291SUB EAX,EDX
292end;
293{$ELSEIF DEFINED(WIN64)}
294asm
295.NOFRAME
296
297MOVZX EAX,CX
298BSR ECX,EAX
299JNZ @Invert
300MOV EAX,16
301RET
302
303@Invert:
304
305MOV EAX,15
306SUB EAX,ECX
307end;
308{$ELSE PUREPASCAL}
309begin
310if U = 0 then
311Result := 16
312else
313begin
314Result := 0;
315if U <= High(Word) shr 8 then
316begin
317Result := Result + 8;
318U := U shl 8;
319end;
320if U <= High(Word) shr 4 then
321begin
322Result := Result + 4;
323U := U shl 4;
324end;
325if U <= High(Word) shr 2 then
326begin
327Result := Result + 2;
328U := U shl 2;
329end;
330if U <= High(Word) shr 1 then
331Result := Result + 1;
332end;
333end;
334{$IFEND PUREPASCAL}
335
336function NumberOfLeadingZeros(S: Int32): Integer;
337begin
338Result := NumberOfLeadingZeros(UInt32(S));
339end;
340
341function NumberOfLeadingZeros(U: UInt32): Integer;
342{$IF DEFINED(WIN32)}
343asm
344BSR EDX,EAX
345JNZ @Invert
346MOV EAX,32
347RET
348
349@Invert:
350
351MOV EAX,31
352SUB EAX,EDX
353
354@Exit:
355end;
356{$ELSEIF DEFINED(WIN64)}
357asm
358.NOFRAME
359
360BSR EDX,ECX
361JNZ @Invert
362MOV EAX,32
363RET
364
365@Invert:
366
367MOV EAX,31
368SUB EAX,EDX
369
370@Exit:
371end;
372{$ELSE PUREPASCAL}
373
374// Faster than X := X or X shr 1..16; Result := NLZDeBruijn32[...];
375
376begin
377if U = 0 then
378Result := 32
379else
380begin
381Result := 0;
382if U <= High(Cardinal) shr 16 then
383begin
384Result := Result + 16;
385U := U shl 16;
386end;
387if U <= High(Cardinal) shr 8 then
388begin
389Result := Result + 8;
390U := U shl 8;
391end;
392if U <= High(Cardinal) shr 4 then
393begin
394Result := Result + 4;
395U := U shl 4;
396end;
397if U <= High(Cardinal) shr 2 then
398begin
399Result := Result + 2;
400U := U shl 2;
401end;
402if U <= High(Cardinal) shr 1 then
403Result := Result + 1;
404end;
405end;
406{$IFEND PUREPASCAL}
407
408// Faster than NumberOfTrailingZeros2().
409function NumberOfTrailingZeros(U: UInt32): Integer;
410{$IF DEFINED(WIN32)}
411asm
412BSF EAX,EAX
413JNZ @Exit
414MOV EAX,32
415
416@Exit:
417end;
418{$ELSEIF DEFINED(WIN64)}
419asm
420.NOFRAME
421
422BSF EAX,ECX
423JNZ @Exit
424MOV EAX,32
425
426@Exit:
427end;
428{$ELSE PUREPASCAL}
429begin
430if U = 0 then
431Result := 32
432else
433Result := NTZDeBruijn32[((U and (-Integer(U))) * NTZDeBruijn32Mult) shr 27];
434end;
435{$IFEND PUREPASCAL}
436
437function Reverse(U: UInt8): UInt8;
438begin
439U := ((U shr 1) and $55) or ((U and $55) shl 1);
440U := ((U shr 2) and $33) or ((U and $33) shl 2);
441U := (U shr 4) or (U shl 4);
442Result := U;
443end;
444
445function Reverse(U: UInt16): UInt16;
446begin
447U := ((U shr 1) and $5555) or ((U and $5555) shl 1);
448U := ((U shr 2) and $3333) or ((U and $3333) shl 2);
449U := ((U shr 4) and $0F0F) or ((U and $0F0F) shl 4);
450U := Swap(U);
451Result := U;
452end;
453
454function Reverse(S: Int32): Int32;
455begin
456Result := Int32(Reverse(UInt32(S)));
457end;
458
459// See http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c too.
460// http://stackoverflow.com/a/9144870/95954
461function Reverse(U: UInt32): UInt32;
462begin
463U := ((U shr 1) and $55555555) or ((U and $55555555) shl 1); // Swap adjacent bits.
464U := ((U shr 2) and $33333333) or ((U and $33333333) shl 2); // Swap adjacent bit pairs.
465U := ((U shr 4) and $0F0F0F0F) or ((U and $0F0F0F0F) shl 4); // Swap nibbles.
466U := ((U shr 8) and $00FF00FF) or ((U and $00FF00FF) shl 8); // Swap bytes.
467U := (U shr 16) or (U shl 16); // Swap words.
468Result := U;
469end;
470
471function ReverseBytes(S: Int32): Int32;
472begin
473Result := Int32(ReverseBytes(UInt32(S)));
474end;
475
476// Byte and word swaps of Reverse(U).
477function ReverseBytes(U: UInt32): UInt32;
478begin
479U := ((U shr 8) and $00FF00FF) or ((U and $00FF00FF) shl 8); // Swap bytes.
480U := (U shr 16) or (U shl 16); // Swap words.
481Result := U;
482end;
483
484function RotateLeft(S: Int32; Distance: Integer): Int32;
485begin
486Result := Int32(RotateLeft(UInt32(S), Distance));
487end;
488
489function RotateLeft(U: UInt32; Distance: Integer): UInt32;
490begin
491Distance := Distance and 31;
492Result := (U shl Distance) or (U shr (32 - Distance));
493end;
494
495function RotateRight(S: Int32; Distance: Integer): Int32;
496begin
497Result := Int32(RotateRight(UInt32(S), Distance));
498end;
499
500function RotateRight(U: UInt32; Distance: Integer): UInt32;
501begin
502Distance := Distance and 31;
503Result := (U shr Distance) or (U shl (32- Distance));
504end;
505
506function Sign(S: Int32): TValueSign;
507begin
508Result := Math.Sign(S);
509end;
510
511function ToBinaryString(S: Int32): string;
512begin
513Result := ToString(S, 2);
514end;
515
516function ToBinaryString(U: UInt32): string;
517begin
518Result := ToString(U, 2);
519end;
520
521function ToHexString(S: Int32): string;
522begin
523Result := ToString(S, 16);
524end;
525
526function ToHexString(U: UInt32): string;
527begin
528Result := ToString(U, 16);
529end;
530
531function ToOctalString(S: Int32): string;
532begin
533Result := ToString(S, 8);
534end;
535
536function ToOctalString(U: UInt32): string;
537begin
538Result := ToString(U, 8);
539end;
540
541const
542Digits: array[0..35] of Char = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
543
544function ToString(S: Int32; Base: Byte): string;
545begin
546if S < 0 then
547Result := '-' + ToString(UInt32(Abs(S)), Base)
548else
549Result := ToString(UInt32(S), Base);
550end;
551
552function ToString(U: UInt32; Base: Byte): string;
553begin
554if not (Base in [2..36]) then
555raise Exception.Create('Error Message'); // convert error? argument error?
556
557if U = 0 then
558Result := '0'
559else
560begin
561Result := '';
562while U > 0 do
563begin
564Result := Digits[U mod Base] + Result;
565U := U div Base;
566end;
567end;
568end;
569
570end.
571