Task: Abundant, deficient and perfect number classifications



C#: using System;
using System.Linq;

public class Program
{
    public static void Main()
    {
        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");
        sw.Restart();
        ClassifyNumbers.UsingOptiDivision(20000, out abundant, out deficient, out perfect);
        Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect}  {sw.Elapsed.TotalMilliseconds} ms");
        sw.Restart();
        ClassifyNumbers.UsingDivision(20000, out abundant, out deficient, out perfect);
        Console.WriteLine($"Abundant: {abundant}, Deficient: {deficient}, Perfect: {perfect}  {sw.Elapsed.TotalMilliseconds} ms");
    }
}

public static class ClassifyNumbers
{
    
    public static void UsingSieve(int bound, out int abundant, out int deficient, out int perfect) {
        abundant = perfect = 0;
        
        int[] sum = new int[bound + 1];
        for (int divisor = 1; divisor <= bound >> 1; divisor++)
            for (int i = divisor << 1; i <= bound; i += divisor)
                sum[i] += divisor;
        for (int i = 1; i <= bound; i++) {
            if (sum[i] > i) abundant++;
            else if (sum[i] == i) perfect++;
        }
        deficient = bound - abundant - perfect;
    }

    
    public static void UsingOptiDivision(int bound, out int abundant, out int deficient, out int perfect) {
        abundant = perfect = 0; 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; }
            sum = 1;
        }
        deficient = bound - abundant - perfect;
    }

    
    public static void UsingDivision(int bound, out int abundant, out int deficient, out int perfect) {
        abundant = perfect = 0;
        for (int i = 2; i <= bound; i++) {
            int sum = Enumerable.Range(1, (i + 1) / 2)
                .Where(div => i % div == 0).Sum();
            switch (sum.CompareTo(i)) {
                case 0: perfect++; break;
                case 1: abundant++; break;
            }
        }
        deficient = bound - abundant - perfect;
    }
}








Fortran:       MODULE FACTORSTUFF	
Concocted by R.N.McLean, MMXV.
       INTEGER LOTS		
       PARAMETER (LOTS = 20000)
       INTEGER KNOWNSUM(LOTS)	
       CONTAINS		
        SUBROUTINE PREPARESUMF	
Convert the Sieve of Eratoshenes to have each slot contain the sum of the proper divisors of its slot number.
Changes to instead count the number of factors, or prime factors, etc. would be simple enough.
         INTEGER F		
          KNOWNSUM(1) = 0		
          KNOWNSUM(2:LOTS) = 1		
          DO F = 2,LOTS/2		
            FORALL(I = F + F:LOTS:F) KNOWNSUM(I) = KNOWNSUM(I) + F	
          END DO			
        END SUBROUTINE PREPARESUMF	
         PURE INTEGER FUNCTION SIGN3(N)	
Confounded by the intrinsic function SIGN distinguishing only two states: < 0 from >= 0. NOT three-way.
         INTEGER, INTENT(IN):: N	
          IF (N) 1,2,3	
    1     SIGN3 = -1	
          RETURN
    2     SIGN3 = 0	
          RETURN
    3     SIGN3 = +1	
        END FUNCTION SIGN3	
      END MODULE FACTORSTUFF	
       PROGRAM THREEWAYS	
       USE FACTORSTUFF		
       INTEGER I		
       INTEGER TEST(LOTS)	
        WRITE (6,*) "Inspecting sums of proper divisors for 1 to",LOTS
        CALL PREPARESUMF		
        FORALL(I = 1:LOTS) TEST(I) = SIGN3(KNOWNSUM(I) - I)	
        WRITE (6,*) "Deficient",COUNT(TEST .LT. 0)	
        WRITE (6,*) "Perfect
        WRITE (6,*) "Abundant ",COUNT(TEST .GT. 0)	
      END