Abundant, deficient and perfect number classifications: Difference between revisions
Content added Content deleted
m (→{{header|Python}}: Doh! No sense checking factors > n / 2.) |
(→{{header|C sharp}}: added third method to comparison, added performance comparison.) |
||
Line 1,763: | Line 1,763: | ||
=={{header|C sharp}}== |
=={{header|C sharp}}== |
||
Three algorithms presented, the first is fast, but can be a memory hog when tabulating to larger limits. The second is slower, but doesn't have any memory issue. The third is quite a bit slower, but the code may be easier to follow. |
|||
First method: |
|||
:Initializes a large queue, uses a double nested loop to populate it, and a third loop to interrogate the queue.<br> |
|||
Second method: |
|||
:Uses a double nested loop with the inner loop only reaching to sqrt(i), as it adds both divisors at once, later correcting the sum when the divisor is a perfect square. |
|||
Third method: |
|||
:Uses a loop with a inner Enumerable.Range reaching to i / 2, only adding one divisor at a time. |
|||
<lang csharp>using System; |
<lang csharp>using System; |
||
using System.Linq; |
using System.Linq; |
||
Line 1,771: | Line 1,779: | ||
{ |
{ |
||
int abundant, deficient, perfect; |
int abundant, deficient, perfect; |
||
var sw = System.Diagnostics.Stopwatch.StartNew(); |
|||
⚫ | |||
ClassifyNumbers.UsingSieve(20000, out abundant, out deficient, out perfect); sw.Stop(); |
|||
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms"); |
|||
⚫ | |||
⚫ | |||
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms"); |
|||
⚫ | |||
ClassifyNumbers.UsingDivision(20000, out abundant, out deficient, out perfect); |
ClassifyNumbers.UsingDivision(20000, out abundant, out deficient, out perfect); |
||
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect}"); |
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms"); |
||
} |
} |
||
} |
} |
||
Line 1,781: | Line 1,793: | ||
public static class ClassifyNumbers |
public static class ClassifyNumbers |
||
{ |
{ |
||
//Fastest way |
//Fastest way, but uses memory |
||
public static void UsingSieve(int bound, out int abundant, out int deficient, out int perfect) { |
public static void UsingSieve(int bound, out int abundant, out int deficient, out int perfect) { |
||
abundant = perfect = 0; |
|||
//For very large bounds, this array can get big. |
//For very large bounds, this array can get big. |
||
int[] sum = new int[bound + 1]; |
int[] sum = new int[bound + 1]; |
||
for (int divisor = 1; divisor <= bound |
for (int divisor = 1; divisor <= bound >> 1; divisor++) |
||
for (int i = divisor |
for (int i = divisor << 1; i <= bound; i += divisor) |
||
sum[i] += divisor; |
sum[i] += divisor; |
||
⚫ | |||
⚫ | |||
for (int i = 1; i <= bound; i++) { |
for (int i = 1; i <= bound; i++) { |
||
if (sum[i] |
if (sum[i] > i) abundant++; |
||
else if (sum[i] |
else if (sum[i] == i) perfect++; |
||
⚫ | |||
} |
} |
||
deficient = bound - abundant - perfect; |
|||
⚫ | |||
⚫ | |||
} |
} |
||
⚫ | |||
// |
//Slower, optimized, but doesn't use storage |
||
public static void UsingOptiDivision(int bound, out int abundant, out int deficient, out int perfect) { |
|||
⚫ | |||
for (int i = 2, d, r = 1; i <= bound; i++) { |
|||
if ((d = r * r - i) < 0) r++; |
|||
for (int x = 2; x < r; x++) if (i % x == 0) sum += x + i / x; |
|||
if (d == 0) sum += r; |
|||
switch (sum.CompareTo(i)) { case 0: perfect++; break; case 1: abundant++; break; } |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
//Much slower, doesn't use storage and is un-optimized |
|||
public static void UsingDivision(int bound, out int abundant, out int deficient, out int perfect) { |
public static void UsingDivision(int bound, out int abundant, out int deficient, out int perfect) { |
||
abundant = perfect = 0; |
|||
for (int i = |
for (int i = 2; i <= bound; i++) { |
||
int sum = Enumerable.Range(1, (i + 1) / 2) |
int sum = Enumerable.Range(1, (i + 1) / 2) |
||
.Where(div => |
.Where(div => i % div == 0).Sum(); |
||
switch (sum.CompareTo(i)) { |
|||
case 0: perfect++; break; |
|||
case 1: abundant++; break; |
|||
⚫ | |||
} |
} |
||
deficient = bound - abundant - perfect; |
|||
⚫ | |||
⚫ | |||
} |
} |
||
}</lang> |
}</lang> |
||
{{out}} |
{{out|Output @ Tio.run}} |
||
We see the second method is about 10 times slower than the first method, and the third method more than 120 times slower than the second method. |
|||
<pre> |
<pre> |
||
Abundant: 4953, Deficient: 15043, Perfect: 4 |
Abundant: 4953, Deficient: 15043, Perfect: 4 0.7277 ms |
||
Abundant: 4953, Deficient: 15043, Perfect: 4 |
Abundant: 4953, Deficient: 15043, Perfect: 4 7.3458 ms |
||
Abundant: 4953, Deficient: 15043, Perfect: 4 1048.9541 ms |
|||
</pre> |
</pre> |
||