using System, System.Reflection, System.Text; namespace Freya.Demos; public <DefaultMember('Items')> BitsArray = class public constructor(Min, Max: Integer); constructor(Max: Integer) : Self(0, Max); property Min, Max: Integer; readonly; property Items[Index: Integer]: Boolean; property Count: Integer; readonly; iterator GetItems: Integer; method Invert; method ToString: String; override; end; Sieve = static class public method GetPrimes(Max: Integer): BitsArray; end; implementation for Sieve is method GetPrimes(Max: Integer): BitsArray; begin Result := new BitsArray(2, Max); for i in 2 .. Max div 2 : not Result[i] begin var j := i + i; while j <= Max begin Result[j] := true; j += i; end; end; Result.Invert; end; implementation for BitsArray is Bits: Array[Integer]; High: Integer; constructor(Min, Max: Integer); begin Self.Min := Min; Self.Max := Max; Self.High := Max - Min; var Len := Math.Max((Max - Min + 32) div 32, 0); Bits := new Array[Integer](Len); end; property Count: Integer; begin for j in Bits using k: Integer := 1 repeat if j & k <> 0 then Result++; // I do prefer C style shift operators, // but you can use shr and shl if you like it. k := k << 1; until k = 0; end; iterator GetItems: Integer; begin for i in Min .. Max : Self[i] yield i; end; property Items(Index: Integer): Boolean; begin Index -= Min; if Index < 0 or Index > High raise new ArgumentException('Index'); Result := (Bits[Index div 32] & (1 << (Index mod 32))) <> 0; end; property Items(Index: Integer; Value: Boolean); begin Index -= Min; if Index < 0 or Index > High raise new ArgumentException('Index'); if Value then Bits[Index div 32] |= 1 << (Index mod 32) else Bits[Index div 32] &= ~(1 << (Index mod 32)); end; method Invert; begin for i in 0..Bits.Length - 1 do Bits[i] := ~Bits[i]; end; method ToString: String; begin var sb := new StringBuilder; sb.Append('{'); for i in Min..Max : Self[i] if sb.Length = 1 then sb.Append(i) else sb.Append(',').Append(i); Result := sb.Append('}').ToString; end;
implementation method Main; begin const TIMES = 1_000_000; var bits := Sieve.GetPrimes(TIMES); Console.WriteLine( String.Format('{0:#,0} prime numbers before {1:#,0}', bits.Count, TIMES)); // Try this: // Console.WriteLine(Sieve.GetPrimes(1000)); end; end.