Abundant, deficient and perfect number classifications: Difference between revisions

→‎{{header|C sharp}}: added third method to comparison, added performance comparison.
m (→‎{{header|Python}}: Doh! No sense checking factors > n / 2.)
(→‎{{header|C sharp}}: added third method to comparison, added performance comparison.)
Line 1,763:
 
=={{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;
using System.Linq;
Line 1,771 ⟶ 1,779:
{
int abundant, deficient, perfect;
var sw = System.Diagnostics.Stopwatch.StartNew();
ClassifyNumbers.UsingSieve(20000, out abundant, out deficient, out perfect);
ConsoleClassifyNumbers.WriteLineUsingSieve($"Abundant:20000, out {abundant}, Deficient:out {deficient}, Perfect:out {perfect}"); sw.Stop();
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms");
 
else p++sw.Restart();
ClassifyNumbers.UsingSieveUsingOptiDivision(20000, out abundant, out deficient, out perfect);
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms");
perfect = psw.Restart();
ClassifyNumbers.UsingDivision(20000, out abundant, out deficient, out perfect);
Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect} {sw.Elapsed.TotalMilliseconds} ms");
}
}
Line 1,781 ⟶ 1,793:
public static class ClassifyNumbers
{
//Fastest way, but uses memory
public static void UsingSieve(int bound, out int abundant, out int deficient, out int perfect) {
int aabundant = 0, d = 0, pperfect = 0;
//For very large bounds, this array can get big.
int[] sum = new int[bound + 1];
for (int divisor = 1; divisor <= bound />> 21; divisor++) {
for (int i = divisor +<< divisor1; i <= bound; i += divisor) {
sum[i] += divisor;
}
}
for (int i = 1; i <= bound; i++) {
if (sum[i] <> i) dabundant++;
else if (sum[i] >== i) aperfect++;
else p++;
}
abundantdeficient = abound - abundant - perfect;
deficient = d;
perfect = p;
}
 
//MuchSlower, sloweroptimized, but doesn't use storage
public static void UsingOptiDivision(int bound, out int abundant, out int deficient, out int perfect) {
abundant = perfect = p0; int sum = 0;
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; }
deficient sum = d1;
}
deficient = dbound - abundant - perfect;
}
 
//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) {
int aabundant = 0, d = 0, pperfect = 0;
for (int i = 12; i <= 20001bound; i++) {
int sum = Enumerable.Range(1, (i + 1) / 2)
.Where(div => div != i && i % div == 0).Sum();
ifswitch (sum < .CompareTo(i)) d++;{
else if (sum > i)case a0: perfect++; break;
else p case 1: abundant++; break;
}
}
abundantdeficient = abound - abundant - perfect;
deficient = d;
perfect = p;
}
}</lang>
{{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>
Abundant: 4953, Deficient: 15043, Perfect: 4 0.7277 ms
Abundant: 4953, Deficient: 15043, Perfect: 4 7.3458 ms
Abundant: 4953, Deficient: 15043, Perfect: 4 1048.9541 ms
</pre>