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.