Recent

Author Topic: Contest: fastest IsAnagram function  (Read 18258 times)

Fibonacci

  • Hero Member
  • *****
  • Posts: 788
  • Internal Error Hunter
Re: Contest: fastest IsAnagram function
« Reply #120 on: October 26, 2024, 12:33:27 am »
Yes, collision possible :D Find one.
Easy:
Code: Pascal  [Select][+][-]
  1. var
  2.   s1, s2: String;
  3. begin
  4.   s1 := #42#64;
  5.   s2 := #106; // 42 Or 64
  6.   WriteLn(IsAnagram_Fibonacci4(s1, s2)); // TRUE
  7. end.

You could instead of byte use a bigger type like sizeint and use a (non cryptographic) hash to reduce the collisions. Then you basically implemented a bloom filter

Use real existing word at least :D There is room for improvement.

Warfley

  • Hero Member
  • *****
  • Posts: 2038
Re: Contest: fastest IsAnagram function
« Reply #121 on: October 26, 2024, 12:47:33 am »
Use real existing word at least :D There is room for improvement.
Like ok and im?

Fibonacci

  • Hero Member
  • *****
  • Posts: 788
  • Internal Error Hunter
Re: Contest: fastest IsAnagram function
« Reply #122 on: October 26, 2024, 12:49:06 am »
From Wikipedia
Quote
Eleven plus two — Twelve plus one
Clint Eastwood — Old West action

After replacing the '—' sign with '-' to pass the illegal characters check, it results in an actual collision. Algo broken :(

Fibonacci

  • Hero Member
  • *****
  • Posts: 788
  • Internal Error Hunter
Re: Contest: fastest IsAnagram function
« Reply #123 on: October 26, 2024, 01:26:55 am »
Now find collision ;D

Code: Text  [Select][+][-]
  1. *** ROUND 1 ***
  2. s1 = s tate
  3. s2 = t a  s t  e
  4.  
  5.             delphius IgnoreSpaces ExceptionOnError |  1016 ms | result 25000000
  6.                              delphius IgnoreSpaces |  1016 ms | result 25000000
  7.                                           delphius |    78 ms | result 0
  8.                                          
  9.          Fibonacci-4 IgnoreSpaces ExceptionOnError |   968 ms | result 25000000
  10.                           Fibonacci-4 IgnoreSpaces |   953 ms | result 25000000
  11.                                        Fibonacci-4 |    78 ms | result 0

Code: Pascal  [Select][+][-]
  1. function IsAnagram_Fibonacci4(const s1, s2: string; IgnoreSpaces: boolean=true; ExceptionOnError: boolean=false): boolean;
  2. var
  3.   c, x1, x2: byte;
  4.   h1, h2: word;
  5.   p1, p1e, p2, p2e: pchar;
  6. begin
  7.   if not IgnoreSpaces and (length(s1) <> length(s2)) then exit(false);
  8.  
  9.   p1 := @s1[1];
  10.   p1e := p1+length(s1);
  11.   x1 := 0;
  12.   h1 := 0;
  13.   while p1 < p1e do begin
  14.     c := pbyte(p1)^;
  15.     case c of
  16.       32: if not IgnoreSpaces then begin inc(h1, c); x1 := x1 xor c; end;
  17.       65..90: begin inc(h1, c or $20); x1 := x1 xor (c or $20); end;
  18.       33..64, 91..127: begin inc(h1, c); x1 := x1 xor c; end;
  19.       else
  20.         if ExceptionOnError then
  21.         raise ERangeError.Create('Illegal character in S1')
  22.         else exit(false);
  23.     end;
  24.     inc(p1);
  25.   end;
  26.  
  27.   p2 := @s2[1];
  28.   p2e := p2+length(s2);
  29.   x2 := 0;
  30.   h2 := 0;
  31.   while p2 < p2e do begin
  32.     c := pbyte(p2)^;
  33.     case c of
  34.       32: if not IgnoreSpaces then begin inc(h2, c); x2 := x2 xor c; end;
  35.       65..90: begin inc(h2, c or $20); x2 := x2 xor (c or $20); end;
  36.       33..64, 91..127: begin inc(h2, c); x2 := x2 xor c; end;
  37.       else
  38.         if ExceptionOnError then
  39.         raise ERangeError.Create('Illegal character in S2')
  40.         else exit(false);
  41.     end;
  42.     inc(p2);
  43.   end;
  44.  
  45.   result := (x1 = x2) and (h1 = h2);
  46. end;

silvercoder70

  • Full Member
  • ***
  • Posts: 200
    • Tim Coates
Re: Contest: fastest IsAnagram function
« Reply #124 on: October 26, 2024, 03:08:59 am »
My final version and hopefully fixed updated validation rules :)

Code: Pascal  [Select][+][-]
  1. function IsAnagram_silvercoder70B(const S1, S2: String;
  2.                    IgnoreSpaces: Boolean = True;
  3.                    ExceptionOnError: Boolean = False): Boolean;
  4.  
  5.   function IsValidChar(C: Byte): Boolean; inline;
  6.   begin
  7.     Result := C in [$20..$7F];
  8.   end;
  9.  
  10.   function ByteToIndex(C: Byte): Byte; inline;
  11.   const
  12.     UpperCase_A = Byte('A');
  13.     LowerCase_A = Byte('a');
  14.     OffSet      = LowerCase_A - UpperCase_A;
  15.   begin
  16.     Result := C;
  17.     if C in [$41..$5A] then
  18.       Result := Result + OffSet;
  19.   end;
  20.  
  21. var
  22.   CharCount: array[0..255] of Integer;
  23.   Ptr, PtrStart, PtrEnd: ^Byte;
  24.   i: Integer;
  25. begin
  26.   Result := False;
  27.  
  28.   FillChar(CharCount, SizeOf(CharCount), #0);
  29.  
  30.   // update array based on S1...
  31.   PtrStart := Addr(S1[1]);
  32.   PtrEnd := PtrStart + Length(S1);
  33.   Ptr := PtrStart;
  34.   while Ptr < PtrEnd do
  35.   begin
  36.     if not IsValidChar(Ptr^) then
  37.     begin
  38.       if ExceptionOnError then
  39.         raise Exception.Create('Invalid character in S1 at: ' + IntToStr(Ptr - PtrStart));
  40.       Exit;
  41.     end;
  42.     Inc(CharCount[ByteToIndex(Ptr^)]);
  43.     Inc(Ptr);
  44.   end;
  45.  
  46.   // now checked elements in S2...
  47.   PtrStart := Addr(S2[1]);
  48.   PtrEnd := PtrStart + Length(S2);
  49.   Ptr := PtrStart;
  50.   while Ptr < PtrEnd do
  51.   begin
  52.     if not IsValidChar(Ptr^) then
  53.     begin
  54.       if ExceptionOnError then
  55.         raise Exception.Create('Invalid character in S1 at: ' + IntToStr(Ptr - PtrStart));
  56.       Exit;
  57.     end;
  58.  
  59.     // Convert to lowercase and decrement count
  60.     Dec(CharCount[ByteToIndex(Ptr^)]);
  61.     Inc(Ptr);
  62.   end;
  63.  
  64.   if IgnoreSpaces then
  65.     CharCount[32] := 0;
  66.  
  67.   for i := 32 to 128 do
  68.   begin
  69.     if CharCount[i] <> 0 then
  70.       Exit;
  71.   end;
  72.  
  73.   Result := True;
  74. end;  
  75.  
🔥 Pascal Isn’t Dead -> See What It Can Do: @silvercoder70 on YouTube

delphius

  • Jr. Member
  • **
  • Posts: 83
Re: Contest: fastest IsAnagram function
« Reply #125 on: October 26, 2024, 10:15:12 am »
Now find collision ;D

I also took up xor. This method effectively reduces string comparison to two simple operations with fixed values x1/x2 and h1/h2, making it fast and easy. However, its weakness is possible hash collisions: theoretically, there may be different combinations of characters that will give the same x and h.
p.s. ah, it has already been discussed  :-[

By using logarithms to check if the sum of the frequencies matches and XOR to check the character balance, the function can accurately determine whether the strings are anagrams. But logarithms are very voracious  :D
Code: Pascal  [Select][+][-]
  1. function IsAnagram_Logarithmic(const S1, S2: string; IgnoreSpaces: Boolean = True; ExceptionOnError: Boolean = False): Boolean;
  2. var
  3.   s1c, s1e, s2c, s2e: PChar;
  4.   ch: Byte;
  5.   logSum1, logSum2: Double;
  6.   xor1, xor2: Byte;
  7. begin
  8.   if not IgnoreSpaces and (Length(S1) <> Length(S2)) then
  9.     Exit(False);
  10.  
  11.   logSum1 := 0;
  12.   logSum2 := 0;
  13.   xor1 := 0;
  14.   xor2 := 0;
  15.  
  16.   s1c := PChar(S1);
  17.   s1e := s1c + Length(S1);
  18.   while s1c < s1e do
  19.   begin
  20.     ch := Ord(s1c^);
  21.     case ch of
  22.       32: if not IgnoreSpaces then begin
  23.             logSum1 := logSum1 + Ln(ch);
  24.             xor1 := xor1 xor ch;
  25.           end;
  26.       65..90: begin
  27.             logSum1 := logSum1 + Ln(ch or $20);
  28.             xor1 := xor1 xor (ch or $20);
  29.           end;
  30.       33..64, 91..127: begin
  31.             logSum1 := logSum1 + Ln(ch);
  32.             xor1 := xor1 xor ch;
  33.           end;
  34.       else
  35.         if ExceptionOnError then
  36.           raise ERangeError.CreateFmt('Illegal character in S1 at position %d', [s1c - PChar(S1) + 1])
  37.         else
  38.           Exit(False);
  39.     end;
  40.     Inc(s1c);
  41.   end;
  42.  
  43.   s2c := PChar(S2);
  44.   s2e := s2c + Length(S2);
  45.   while s2c < s2e do
  46.   begin
  47.     ch := Ord(s2c^);
  48.     case ch of
  49.       32: if not IgnoreSpaces then begin
  50.             logSum2 := logSum2 + Ln(ch);
  51.             xor2 := xor2 xor ch;
  52.           end;
  53.       65..90: begin
  54.             logSum2 := logSum2 + Ln(ch or $20);
  55.             xor2 := xor2 xor (ch or $20);
  56.           end;
  57.       33..64, 91..127: begin
  58.             logSum2 := logSum2 + Ln(ch);
  59.             xor2 := xor2 xor ch;
  60.           end;
  61.       else
  62.         if ExceptionOnError then
  63.           raise ERangeError.CreateFmt('Illegal character in S2 at position %d', [s2c - PChar(S2) + 1])
  64.         else
  65.           Exit(False);
  66.     end;
  67.     Inc(s2c);
  68.   end;
  69.  
  70.   Result := (Abs(logSum1 - logSum2) < 1e-9) and (xor1 = xor2);
  71. end;
  72.  

A guaranteed reliable method is the multiplication of a sequence of prime numbers that can be matched to each character from the set, but we are limited by the bit depth of the product calculations
« Last Edit: October 26, 2024, 01:27:38 pm by delphius »
fpmtls - ssl/tls 1.3 implementation in pure pascal
fpmailsend - sending a simple email message
pascal-webui - use web browser as gui and fpc as backend

avk

  • Hero Member
  • *****
  • Posts: 825
Re: Contest: fastest IsAnagram function
« Reply #126 on: October 26, 2024, 02:17:54 pm »
I am replacing the previous submissions with the new one.
In the attached archive, in addition to the new version, there is also the code of a small benchmark that was used to estimate performance.
On my machine it shows roughly such results:
Code: Text  [Select][+][-]
  1.   ****  Anagram length 10 ****
  2.  
  3. IsAnagram_Bart           1247
  4. IsAnagramASerge          1009
  5. IsAnagram_Fibonacci2     667
  6. IsAnagram_Martin         468
  7. IsAnagram_BrunoK         424
  8. IsAnagram_silvercoder70B 680
  9. IsAnagram_Avk            219
  10.  
  11.   ****  Anagram length 20 ****
  12.  
  13. IsAnagram_Bart           1144
  14. IsAnagramASerge          846
  15. IsAnagram_Fibonacci2     597
  16. IsAnagram_Martin         361
  17. IsAnagram_BrunoK         397
  18. IsAnagram_silvercoder70B 606
  19. IsAnagram_Avk            265
  20.  
  21.   ****  Anagram length 50 ****
  22.  
  23. IsAnagram_Bart           1552
  24. IsAnagramASerge          1116
  25. IsAnagram_Fibonacci2     763
  26. IsAnagram_Martin         427
  27. IsAnagram_BrunoK         618
  28. IsAnagram_silvercoder70B 777
  29. IsAnagram_Avk            296
  30.  
  31.   ****  Anagram length 100 ****
  32.  
  33. IsAnagram_Bart           1131
  34. IsAnagramASerge          726
  35. IsAnagram_Fibonacci2     497
  36. IsAnagram_Martin         244
  37. IsAnagram_BrunoK         430
  38. IsAnagram_silvercoder70B 524
  39. IsAnagram_Avk            250
  40.  
  41.   ****  Anagram length 200 ****
  42.  
  43. IsAnagram_Bart           1068
  44. IsAnagramASerge          605
  45. IsAnagram_Fibonacci2     412
  46. IsAnagram_Martin         178
  47. IsAnagram_BrunoK         379
  48. IsAnagram_silvercoder70B 442
  49. IsAnagram_Avk            182
  50.  
  51.   ****  Anagram length 500 ****
  52.  
  53. IsAnagram_Bart           1261
  54. IsAnagramASerge          570
  55. IsAnagram_Fibonacci2     655
  56. IsAnagram_Martin         150
  57. IsAnagram_BrunoK         369
  58. IsAnagram_silvercoder70B 434
  59. IsAnagram_Avk            152
  60.  
  61.   ****  Anagram length 1000 ****
  62.  
  63. IsAnagram_Bart           1325
  64. IsAnagramASerge          835
  65. IsAnagram_Fibonacci2     1139
  66. IsAnagram_Martin         139
  67. IsAnagram_BrunoK         362
  68. IsAnagram_silvercoder70B 522
  69. IsAnagram_Avk            139
  70.  

Fibonacci

  • Hero Member
  • *****
  • Posts: 788
  • Internal Error Hunter
Re: Contest: fastest IsAnagram function
« Reply #127 on: October 26, 2024, 02:20:21 pm »
I am replacing the previous submissions with the new one.
In the attached archive, in addition to the new version, there is also the code of a small benchmark that was used to estimate performance.
On my machine it shows roughly such results:
Code: Text  [Select][+][-]
  1.   ****  Anagram length 10 ****
  2.  
  3. IsAnagram_Bart           1247
  4. IsAnagramASerge          1009
  5. IsAnagram_Fibonacci2     667
  6. IsAnagram_Martin         468
  7. IsAnagram_BrunoK         424
  8. IsAnagram_silvercoder70B 680
  9. IsAnagram_Avk            219
  10.  
  11.   ****  Anagram length 20 ****
  12.  
  13. IsAnagram_Bart           1144
  14. IsAnagramASerge          846
  15. IsAnagram_Fibonacci2     597
  16. IsAnagram_Martin         361
  17. IsAnagram_BrunoK         397
  18. IsAnagram_silvercoder70B 606
  19. IsAnagram_Avk            265
  20.  
  21.   ****  Anagram length 50 ****
  22.  
  23. IsAnagram_Bart           1552
  24. IsAnagramASerge          1116
  25. IsAnagram_Fibonacci2     763
  26. IsAnagram_Martin         427
  27. IsAnagram_BrunoK         618
  28. IsAnagram_silvercoder70B 777
  29. IsAnagram_Avk            296
  30.  
  31.   ****  Anagram length 100 ****
  32.  
  33. IsAnagram_Bart           1131
  34. IsAnagramASerge          726
  35. IsAnagram_Fibonacci2     497
  36. IsAnagram_Martin         244
  37. IsAnagram_BrunoK         430
  38. IsAnagram_silvercoder70B 524
  39. IsAnagram_Avk            250
  40.  
  41.   ****  Anagram length 200 ****
  42.  
  43. IsAnagram_Bart           1068
  44. IsAnagramASerge          605
  45. IsAnagram_Fibonacci2     412
  46. IsAnagram_Martin         178
  47. IsAnagram_BrunoK         379
  48. IsAnagram_silvercoder70B 442
  49. IsAnagram_Avk            182
  50.  
  51.   ****  Anagram length 500 ****
  52.  
  53. IsAnagram_Bart           1261
  54. IsAnagramASerge          570
  55. IsAnagram_Fibonacci2     655
  56. IsAnagram_Martin         150
  57. IsAnagram_BrunoK         369
  58. IsAnagram_silvercoder70B 434
  59. IsAnagram_Avk            152
  60.  
  61.   ****  Anagram length 1000 ****
  62.  
  63. IsAnagram_Bart           1325
  64. IsAnagramASerge          835
  65. IsAnagram_Fibonacci2     1139
  66. IsAnagram_Martin         139
  67. IsAnagram_BrunoK         362
  68. IsAnagram_silvercoder70B 522
  69. IsAnagram_Avk            139
  70.  

Why v2? Use the lastest v4, post #123

avk

  • Hero Member
  • *****
  • Posts: 825
Re: Contest: fastest IsAnagram function
« Reply #128 on: October 26, 2024, 02:26:05 pm »
Just take the archive and put in the version you like best.

Fibonacci

  • Hero Member
  • *****
  • Posts: 788
  • Internal Error Hunter
Re: Contest: fastest IsAnagram function
« Reply #129 on: October 26, 2024, 02:31:26 pm »
You know what... I did, and it crashed when coming close to 1000 chars len :o Also the times were so different, like some algos were faster in my run than in your run.

Also in trunk version you cant raise an exception in subrountine with noreturn so I commented it all out.

Code: Text  [Select][+][-]
  1. bench.lpr(67,75) Error: Raise in subroutines declared as noreturn is not allowed

avk

  • Hero Member
  • *****
  • Posts: 825
Re: Contest: fastest IsAnagram function
« Reply #130 on: October 26, 2024, 03:01:28 pm »
... Also the times were so different, like some algos were faster in my run than in your run.

I adjusted the number of repetitions so that the execution time was about the same for different anagram lengths, but I have a pretty ancient Intel, so it would be interesting to see the results on your machine.

Also in trunk version you cant raise an exception in subrountine with noreturn so I commented it all out.

Code: Text  [Select][+][-]
  1. bench.lpr(67,75) Error: Raise in subroutines declared as noreturn is not allowed

Bart compiles with 3.2.2 so it's not a problem.

avk

  • Hero Member
  • *****
  • Posts: 825
Re: Contest: fastest IsAnagram function
« Reply #131 on: October 26, 2024, 03:11:29 pm »
Same bench compiled with 3.3.1:
Code: Text  [Select][+][-]
  1.   ****  Anagram length 10 ****
  2.  
  3. IsAnagram_Bart           450
  4. IsAnagramASerge          323
  5. IsAnagram_Fibonacci2     217
  6. IsAnagram_Martin         232
  7. IsAnagram_BrunoK         369
  8. IsAnagram_silvercoder70B 520
  9. IsAnagram_Avk            215
  10.  
  11.   ****  Anagram length 20 ****
  12.  
  13. IsAnagram_Bart           486
  14. IsAnagramASerge          340
  15. IsAnagram_Fibonacci2     247
  16. IsAnagram_Martin         196
  17. IsAnagram_BrunoK         355
  18. IsAnagram_silvercoder70B 463
  19. IsAnagram_Avk            254
  20.  
  21.   ****  Anagram length 50 ****
  22.  
  23. IsAnagram_Bart           868
  24. IsAnagramASerge          614
  25. IsAnagram_Fibonacci2     451
  26. IsAnagram_Martin         264
  27. IsAnagram_BrunoK         567
  28. IsAnagram_silvercoder70B 643
  29. IsAnagram_Avk            301
  30.  
  31.   ****  Anagram length 100 ****
  32.  
  33. IsAnagram_Bart           722
  34. IsAnagramASerge          464
  35. IsAnagram_Fibonacci2     365
  36. IsAnagram_Martin         181
  37. IsAnagram_BrunoK         398
  38. IsAnagram_silvercoder70B 451
  39. IsAnagram_Avk            229
  40.  
  41.   ****  Anagram length 200 ****
  42.  
  43. IsAnagram_Bart           665
  44. IsAnagramASerge          434
  45. IsAnagram_Fibonacci2     335
  46. IsAnagram_Martin         147
  47. IsAnagram_BrunoK         344
  48. IsAnagram_silvercoder70B 382
  49. IsAnagram_Avk            173
  50.  
  51.   ****  Anagram length 500 ****
  52.  
  53. IsAnagram_Bart           792
  54. IsAnagramASerge          444
  55. IsAnagram_Fibonacci2     363
  56. IsAnagram_Martin         137
  57. IsAnagram_BrunoK         337
  58. IsAnagram_silvercoder70B 391
  59. IsAnagram_Avk            148
  60.  
  61.   ****  Anagram length 1000 ****
  62.  
  63. IsAnagram_Bart           941
  64. IsAnagramASerge          777
  65. IsAnagram_Fibonacci2     432
  66. IsAnagram_Martin         131
  67. IsAnagram_BrunoK         329
  68. IsAnagram_silvercoder70B 453
  69. IsAnagram_Avk            138
  70.  

BrunoK

  • Hero Member
  • *****
  • Posts: 766
  • Retired programmer
Re: Contest: fastest IsAnagram function
« Reply #132 on: October 26, 2024, 03:29:02 pm »
Do your IsAnagram_avk a favor, add
Code: Pascal  [Select][+][-]
  1.   if not aIgnoreSpaces and (Length(S1) <> Length(S2)) then
  2.     exit(False);
at the beginning of your function.

Martin's algo still break on :
Code: Text  [Select][+][-]
  1. *** ROUND 5: Long invalid chars ***
  2. s1 = !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~âO'
  3. s2 = âO'~}|{zyxw vutsrqpon mlkjihgfe dcba`_^]\ [ZYXWVUTS RQPONMLKJ IHGFEDCBA @?>=<;:98 76543210/ .-,+*)('& %$#"!
  4.                                  Bart IgnoreSpaces |  94.010 ms | result 0
  5.                                ASerge IgnoreSpaces |  67.701 ms | result 0
  6.                                BrunoK IgnoreSpaces |  45.009 ms | result 0
  7.                               BrunoKb IgnoreSpaces |  42.430 ms | result 0
  8.                               BrunoK2 IgnoreSpaces |  47.318 ms | result 0
  9.                              Delphius IgnoreSpaces |  67.006 ms | result 0
  10.                                Martin IgnoreSpaces |  68.583 ms | result 500000
  11.                                PawelD IgnoreSpaces |  51.886 ms | result 0
  12.                            Fibonacci2 IgnoreSpaces |  56.884 ms | result 0
  13.                            Fibonacci4 IgnoreSpaces |  94.147 ms | result 0
  14.                        Silvercoder70B IgnoreSpaces |  65.021 ms | result 0
  15.                                   Avk IgnoreSpaces |  29.793 ms | result 0
  16.  

Congrats for you implementation.

avk

  • Hero Member
  • *****
  • Posts: 825
Re: Contest: fastest IsAnagram function
« Reply #133 on: October 26, 2024, 03:53:23 pm »
Do your IsAnagram_avk a favor, add
...
 at the beginning of your function.
...

Indeed, thank you.

BeniBela

  • Hero Member
  • *****
  • Posts: 955
    • homepage
Re: Contest: fastest IsAnagram function
« Reply #134 on: October 26, 2024, 05:34:43 pm »
Here is another version:

Code: Pascal  [Select][+][-]
  1. function IsAnagram_benibela(const S1, S2: String; IgnoreSpaces: Boolean = True; ExceptionOnError: Boolean = False): Boolean;
  2. const ALWAYS_RETURN_FALSE_ON_INVALID_INPUT = true;
  3. type
  4.   TFreqLittle = array [0..255] of byte;
  5.   TFreqBig = array [0..255] of integer;
  6.   TLowTableEntry = byte;
  7.   TLowTable = array [0..255] of TLowTableEntry;
  8.   PLowTableEntry = ^TLowTableEntry;
  9. const
  10.   FLow: TLowTable = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  11.                  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
  12.                  61, 62, 63, 64,
  13.                  97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
  14.                  121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
  15.                  114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  16.                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  17.   var isinvalid: boolean = false;
  18.   procedure err(const s: string);
  19.   begin
  20.     isinvalid := ALWAYS_RETURN_FALSE_ON_INVALID_INPUT;
  21.     if ExceptionOnError then
  22.       Raise ERangeError.CreateFmt('IsAnagram: illegal character in string: %s', [s]);
  23.   end;
  24.   procedure countLittle(var F: TFreqLittle; const s: string);
  25.   var
  26.     p,palign,pend: pchar;
  27.     block: DWord;
  28.     low: PLowTableEntry;
  29.     buf: PQWord;
  30.   begin
  31.     buf := @F[32];
  32.     buf[0] := 0; buf[1] := 0; buf[2] := 0; buf[3] := 0;
  33.     buf[4] := 0; buf[5] := 0; buf[6] := 0; buf[7] := 0;
  34.     buf[8] := 0; buf[9] := 0; buf[10] := 0; buf[11] := 0;
  35.  
  36.     F[0]:=0;
  37.     low := @flow[0];
  38.     p := pointer(s);
  39.     pend := p + length(s);
  40.     if p + 32 < pend then begin
  41.       palign := pointer(ptruint(pend) and not (sizeof(block) - 1));
  42.       while p < palign do begin
  43.         block := PUInt32(p)^;
  44.         inc(F[low[block and $FF]]);
  45.         inc(F[low[( block shr 8 ) and $FF]]);
  46.         inc(F[low[( block shr 16 ) and $FF]]);
  47.         inc(F[low[( block shr 24 ) and $FF]]);
  48.         inc(p,sizeof(block));
  49.       end;
  50.     end;
  51.     while p < pend do
  52.     begin
  53.       inc(F[low[ord(p^)]]);
  54.       inc(p);
  55.     end;
  56.     if ALWAYS_RETURN_FALSE_ON_INVALID_INPUT or ExceptionOnError then
  57.       if F[0] > 0 then err(s);
  58.   end;
  59.   procedure countBig(var F: TFreqBig; const s: string);
  60.   var
  61.     p,palign,pend: pchar;
  62.     block: {$ifdef cpu64} QWord {$else} DWord{$endif};
  63.     c: Integer;
  64.   begin
  65.     f := default(TFreqBig);
  66.     p := pointer(s);
  67.     pend := p + length(s);
  68.     if p + 32 < pend then begin
  69.       palign := pointer(ptruint(pend) and not (sizeof(block) - 1));
  70.       while p < palign do begin
  71.         block := {$ifdef cpu64} PUInt64(p)^ {$else} PUInt32(p)^{$endif};
  72.         inc(F[block and $FF]);
  73.         inc(F[( block shr 8 ) and $FF]);
  74.         inc(F[( block shr 16 ) and $FF]);
  75.         inc(F[( block shr 24 ) and $FF]);
  76.         {$ifdef cpu64}
  77.         inc(F[( block shr 32 ) and $FF]);
  78.         inc(F[( block shr 40 ) and $FF]);
  79.         inc(F[( block shr 48 ) and $FF]);
  80.         inc(F[( block shr 56 ) and $FF]);
  81.         {$endif}
  82.  
  83.         inc(p,sizeof(block));
  84.       end;
  85.     end;
  86.     while p < pend do
  87.     begin
  88.       inc(F[ord(p^)]);
  89.       inc(p);
  90.     end;
  91.     for c := ord('a') to ord('z') do begin
  92.       F[c and not $20] += F[c];
  93.       F[c] := 0;
  94.     end;
  95.  
  96.     if ALWAYS_RETURN_FALSE_ON_INVALID_INPUT or ExceptionOnError then begin
  97.       for c := 0 to ord(' ') - 1 do if F[c] <> 0 then err(s);
  98.       for c := 128 to 255 do if F[c] <> 0 then begin err(s); break; end;
  99.     end;
  100. end;
  101.  
  102.  
  103. var
  104.   F1l,F2l: TFreqLittle;
  105.   buf1l,buf2l: PQWord;
  106.   F1b,F2b: TFreqBig;
  107.   i: Integer;
  108. begin
  109.   if (IgnoreSpaces = false) and (ExceptionOnError = false) and (length(s1) <> length(s2)) then
  110.     exit(false);
  111.   if (length(s1) < 255) and (length(s2) < 255) then begin
  112.     countLittle(F1l, S1);
  113.     countLittle(F2l, S2);
  114.     if isinvalid then exit(false);
  115.     if IgnoreSpaces then F1l[ord(' ')] := F2l[ord(' ')];
  116.     buf1l := @F1l[32]; buf2l := @F2l[32];
  117.     result := (buf1l[0] = buf2l[0]) and (buf1l[1] = buf2l[1]) and (buf1l[2] = buf2l[2]) and (buf1l[3] = buf2l[3])
  118.              and (buf1l[4] = buf2l[4]) and (buf1l[5] = buf2l[5]) and (buf1l[6] = buf2l[6]) and (buf1l[7] = buf2l[7])
  119.              and (buf1l[8] = buf2l[8]) and (buf1l[9] = buf2l[9]) and (buf1l[10] = buf2l[10]) and (buf1l[11] = buf2l[11]);
  120. ;
  121.  
  122.   end else begin
  123.     countBig(F1b, S1);
  124.     countBig(F2b, S2);
  125.     if isinvalid then exit(false);
  126.     for i := ord(' ')+ord(IgnoreSpaces) to 127 do
  127.       if f1b[i] <> f2b[i] then exit(false);
  128.     result := true
  129.  
  130.   end;
  131. end;
  132.  

 

TinyPortal © 2005-2018