diff options
| author | James Smith <baggy@baggy.me.uk> | 2021-07-26 23:40:52 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-26 23:40:52 +0100 |
| commit | 4f8ee21584432dc56c9df610b40b5dc921135f54 (patch) | |
| tree | 9fd654442dcb34d8b3bec95089ec4e353acf6299 | |
| parent | 9534e35f83498ba998b23afdad57c633e20adad2 (diff) | |
| download | perlweeklychallenge-club-4f8ee21584432dc56c9df610b40b5dc921135f54.tar.gz perlweeklychallenge-club-4f8ee21584432dc56c9df610b40b5dc921135f54.tar.bz2 perlweeklychallenge-club-4f8ee21584432dc56c9df610b40b5dc921135f54.zip | |
Update README.md
| -rw-r--r-- | challenge-123/james-smith/README.md | 60 |
1 files changed, 27 insertions, 33 deletions
diff --git a/challenge-123/james-smith/README.md b/challenge-123/james-smith/README.md index fca2d170b8..3d6e446896 100644 --- a/challenge-123/james-smith/README.md +++ b/challenge-123/james-smith/README.md @@ -31,10 +31,9 @@ Any Ugly number is either a multiple of 2, 3 or 5 of another Ugly number. So to ```perl sub nth_ugly { my $n = shift; - my @uglies = (1); + state @uglies = (1); while(1) { return $uglies[$n-1] if $n <= @uglies; - ## Get the next ugly.... my $next = 0; foreach my $l (5,3,2) { foreach(@uglies) { @@ -46,7 +45,6 @@ sub nth_ugly { push @uglies, $next; } } - ``` We cache the values internally in the function - in the `state` variable `@uglies` @@ -58,23 +56,17 @@ We can speed this up by short-cutting the inner loop - by remembering which was ```perl sub nth_ugly_opt { my $n = shift; - my @uglies = (1); - my @starts = (0,0,0,0,0,0); - while(1) { - return $uglies[$n-1] if $n <= @uglies; - ## Get the next ugly.... - my $next = 0; - foreach my $l (5,3,2) { - foreach ( $starts[$l] .. $#uglies ) { - next if $uglies[$_] * $l <= $uglies[-1]; - $starts[$l]=$_; - $next = $uglies[$_]*$l if !$next || $next > $uglies[$_]*$l; - last; - } - } - push @uglies, $next; + state ($l2,$l3,$l5,$v2,$v3,$v5,@uglies)=(0,0,0,2,3,5,1); + return $uglies[$n-1] if $n <= @uglies; + while( @uglies < $n ) { + push @uglies, my $next = ($v2 < $v3 && $v2 < $v5) ? $v2 : ($v3 < $v5) ? $v3 : $v5; + $v2 = $uglies[++$l2]*2 if $v2 == $next; + $v3 = $uglies[++$l3]*3 if $v3 == $next; + $v5 = $uglies[++$l5]*5 if $v5 == $next; } + return $uglies[-1]; } + ``` The extra overhead causes the optimized method to be slower than the simple method for low values of `$n` - but as `$n` goes up it saves many loop evaluations. Flip happens when `$n` is around `18` or `19`. By the time we get to `$n` as 1000 the optimized version is around 50 times faster than the naive one. For `$n = 10_0000` one of the largest values for which the ugly is less than 2^64 (and so all calculations are integer based) in around 600 times faster. @@ -82,21 +74,23 @@ The extra overhead causes the optimized method to be slower than the simple meth Below shows these comparisons - against a simple scan algorithm (with caching of uglies). We can see that for values up to around 20-30 the scan method (because of it's simplicity is fastest) and the uglies are relatively dense. But soon the advantage of our message is seen - by the time `$n` reaches 500 (Ugly is 937,500) to optimized method is around 2000x faster than the scan method. -| n | Ugly(n) | Scan | Simple | Optimized | Opt v simple | Opt v scan | Simple v scan | -| -----: | ----------------------: | ----------: | ----------: | ----------: | -----------: | ------------: | ------------: | -| 1 | 1 | 1,693,446/s | 3,131,931/s | 1,922,126/s | -39% | 14% | 14% | -| 2 | 2 | 844,419/s | 1,019,073/s | 537,358/s | -47% | -36% | 21% | -| 5 | 5 | 294,998/s | 287,307/s | 167,641/s | -42% | -43% | -3% | -| 10 | 12 | 121,349/s | 109,978/s | 78,936/s | -28% | -35% | -11% | -| 20 | 36 | 40,792/s | 35,257/s | 38,068/s | 5% | -7% | -11% | -| 50 | 243 | 6,098/s | 6,656/s | 15,056/s | 126% | 148% | 10% | -| 100 | 1,536 | 941/s | 1,653/s | 7,423/s | 349% | 688% | 76% | -| 200 | 16,200 | 83.5/s | 395/s | 3,700/s | 843% | 4,333% | 374% | -| 500 | 937,500 | 0.8/s | 58.8/s | 1,479/s | 2,417% | 185,492% | 7,273% | -| 1,000 | 51,200,000 | | 13.8/s | 687/s | 4,866% | - | - | -| 2,000 | 8,062,156,800 | | 3.35/s | 352/s | 10,402% | - | - | -| 5,000 | 50,837,316,566,580 | | 0.49/s | 138/s | 28,036% | - | - | -| 10,000 | 288,325,195,312,500,000 | | 0.11/s | 67.6/s | 57,754% | - | - | +| n | Ugly(n) | scan /s | simple /s | opt /s | opt vs sim % | sim vs scn % | opt vs scn % | +| -----: | -------------------------: | ------: | --------: | --------: | -----------: | -----------: | -----------: | +| 1 | 1 | 938,492 | 3,005,191 | 1,799,451 | -40 | 220 | 92 | +| 2 | 2 | 536,552 | 816,345 | 1,089,848 | 34 | 52 | 103 | +| 5 | 5 | 234,116 | 238,716 | 455,051 | 91 | 2 | 94 | +| 10 | 12 | 98,061 | 77,865 | 250,411 | 222 | -21 | 155 | +| 20 | 36 | 32,105 | 21,225 | 130,707 | 516 | -34 | 307 | +| 50 | 243 | 4,289 | 5,504 | 43,065 | 682 | 28 | 904 | +| 100 | 1,536 | 724 | 1,203 | 24,768 | 1,959 | 66 | 3,321 | +| 200 | 16,200 | 63.50 | 272 | 12,470 | 4,485 | 328 | 19,538 | +| 500 | 937,500 | 0.57 | 48 | 4,639 | 9,565 | 8,306 | 812,334 | +| 1,000 | 51,200,000 | - | 10.60 | 2,503 | 23,513 | - | - | +| 2,000 | 8,062,156,800 | - | 2.75 | 1,187 | 43,064 | - | - | +| 5,000 | 50,837,316,566,580 | - | 0.41 | 375 | 91,812 | - | - | +| 10,000 | 288,325,195,312,500,000 | - | 0.08 | 230 | 273,710 | - | - | +| 13,282 | 18,432,000,000,000,000,000 | - | 0.05 | 148 | 302,757 | - | - | + # Task 2 - Square Points |
