рдШреБрдЯрдиреЗ рдкрд░ рдПрдХ рд╕реМ рдЕрд░рдм рддрдХ рдХрд╛ рдбреЗрдЯрд╛рдмреЗрд╕

рдЫрд╡рд┐

рдХрд┐рд╕реА рднреА рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╕рднреА рдЕрдкрд░рд╛рдзреЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдкреНрд░рд╕рд┐рджреНрдз рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо Eratosthenes рдХреА рдЪрд▓рдиреА рд╣реИ ред рдпрджрд┐ рдпрд╣ рдмрдбрд╝реЗ рдХрд░реАрдиреЗ рд╕реЗ рд▓рд┐рдЦрд╛ рдЬрд╛рдП рддреЛ рдпрд╣ рдЕрд░рдмреЛрдВ рддрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд╢рд╛рдпрдж рджрд╕рд┐рдпреЛрдВ рдЕрд░рдмреЛрдВ рддрдХред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╣рд░ рдХреЛрдИ рдЬреЛ рдкреНрд░рд╛рдЗрдо рдирдВрдмрд░реЛрдВ рдХреЗ рд╕рд╛рде рдорд╕реНрддреА рдХрд░рдирд╛ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реИ, рд╡рд╣ рдЬрд╛рдирддрд╛ рд╣реИ рдХрд┐ рдЖрдк рд╣рдореЗрд╢рд╛ рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЙрддрдирд╛ рд╕рдВрднрд╡ рд╣реИред рдПрдХ рдмрд╛рд░, рд╣реИрдХрд░реНрд░реИрдВрдХ рдкрд░ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдПрдХ рд╕реМ рдмрд┐рд▓рд┐рдпрди рддрдХ рдХреЗ рдЗрди-рдореЗрдореЛрд░реА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереАред рдореЗрдореЛрд░реА рджреНрд╡рд╛рд░рд╛ рдЕрдзрд┐рдХрддрдо рдЕрдиреБрдХреВрд▓рди рдХреЗ рд╕рд╛рде, рдЕрдЧрд░ рдЗрд░реЗрдЯреЛрд╕реНрдердиреАрдЬ рдХреА рдЫрд▓рдиреА рдереЛрдбрд╝реА рд╕реА рд╕рд░рдгреА рдХреЗ рд╕рд╛рде рд╡рд┐рд╖рдо рд╕рдВрдЦреНрдпрд╛рдПрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреА рд╣реИ, рддреЛ рдЗрд╕рдХрд╛ рдЖрдХрд╛рд░ рд▓рдЧрднрдЧ 6 рдЧреАрдЧрд╛рдмрд╛рдЗрдЯ рд╣реЛрдЧрд╛, рдЬреЛ рдореЗрд░реЗ рд▓реИрдкрдЯреЙрдк рдХреА рдореЗрдореЛрд░реА рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рдерд╛ред рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдПрдХ рд╕рдВрд╢реЛрдзрди рд╣реИ рдЬреЛ рд╕реНрдореГрддрд┐ рдореЗрдВ рдмрд╣реБрдд рдХрдо рдорд╛рдВрдЧ рд╣реИ (рд╕рдВрдЦреНрдпрд╛ рдХреА рдореВрд▓ рд╢реНрд░реЗрдгреА рдХреЛ рдХрдИ рдЯреБрдХрдбрд╝реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдирд╛ рдФрд░ рдПрдХ рд╕рдордп рдореЗрдВ рдПрдХ рдЯреБрдХрдбрд╝рд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд░рдирд╛) -рдПрд░рд╛рдЯреЛрд╕реНрдердиреАрдЬ рдХреА рдЦрдВрдбрд┐рдд рдЫрд▓рдиреА , рд▓реЗрдХрд┐рди рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдЕрдзрд┐рдХ рдХрдард┐рди рд╣реИ, рдФрд░ рдкреВрд░реЗ рдкрд░рд┐рдгрд╛рдо рд╡реИрд╕реЗ рднреА рд╕реНрдореГрддрд┐ рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рд╣реЛрдВрдЧреЗред рдиреАрдЪреЗ рдореИрдВ рдЖрдкрдХреЗ рдзреНрдпрд╛рди рдореЗрдВ рдПрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рд▓рд╛рдКрдВрдЧрд╛ рдЬреЛ рд▓рдЧрднрдЧ Eratosthenes рдХреА рдЫрд▓рдиреА рдХреА рддрд░рд╣ рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдЬреЛ рдореЗрдореЛрд░реА рд╕реЗ рдбрдмрд▓ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝реЗрд╢рди рджреЗрддрд╛ рд╣реИ (рдпрд╛рдиреА рдПрдХ рд╕реМ рдмрд┐рд▓рд┐рдпрди рддрдХ рдХреЗ рдкреНрд░рд╛рдЗрдо рдХрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рд▓рдЧрднрдЧ 3 рдЧреАрдЧрд╛рдмрд╛рдЗрдЯ рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд▓реЗрдЧрд╛, рдЬреЛ рдПрдХ рдорд╛рдирдХ рд▓реИрдкрдЯреЙрдк рдХреА рдореЗрдореЛрд░реА рдореЗрдВ рдлрд┐рдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП)ред

рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдЗрд░реЗрдЯреЛрд╕реНрдердиреАрдЬ рдХреА рдЫрд▓рдиреА рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддреА рд╣реИ: 1 рд╕реЗ рдПрди рддрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ, рджреЛ рд╕реЗ рд╡рд┐рднрд╛рдЬреНрдп рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдкрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлрд┐рд░ рд╕рдВрдЦреНрдпрд╛ 3 рд╕реЗ рд╡рд┐рднрд╛рдЬреНрдп рд╣реЛрддреА рд╣реИ, рдФрд░ рдЗрд╕реА рддрд░рд╣ред рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рдмрд╛рдж рд╢реЗрд╖ рд╕рдВрдЦреНрдпрд╛ рд╕рд░рд▓ рд╣реЛрдЧреА:

2 3 . 5 . 7 . 9 . 11 . 13 . 15 . 17 . 19 . 21 . 23 . 25 . 27  . 29  ...
2 3 . 5 . 7 . . . 11 . 13 .  . . 17 . 19 .  . . 23 . 25 .  .  . 29  ...
2 3 . 5 . 7 . . . 11 . 13 .  . . 17 . 19 .  . . 23 .  . .  .  . 29  ...

рд╕реА # рдХреЛрдб
class EratospheneSieve
{
    private bool[] Data;

    public EratospheneSieve(int length)
    {
        Data = new bool[length];

        for (int i = 2; i < Data.Length; i++) Data[i] = true;

        for (int i = 2; i * i < Length; i++)
        {
            if (!Data[i]) continue;
            for (int d = i * i; d < Length; d += i) Data[d] = false;
        }
    }

    public int Length => Data.Length;

    public bool IsPrime(int n) => Data[n];
}


рдореЗрд░реЗ рд▓реИрдкрдЯреЙрдк рдкрд░, рдпрд╣ 15 рдмрд┐рд▓рд┐рдпрди рд╕реЗрдХрдВрдб рддрдХ рдЧрд┐рдирд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдореЗрдореЛрд░реА рдХреА рдПрдХ рдЧреАрдЧрд╛рдмрд╛рдЗрдЯ рдЦрдкрдд рдХрд░рддрд╛ рд╣реИред

рд╣рдо рдЬрд┐рд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЙрд╕реЗ рд╡реНрд╣реАрд▓ рдлреИрдХреНрдЯрд░рд╛рдЗрдЬреЗрд╢рди рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдЗрд╕рдХреЗ рд╕рд╛рд░ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ 30 рдЯреБрдХрдбрд╝реЛрдВ рдХреА рдПрдХ рдЧреЛрд▓реА рдХреЗ рд╕рд╛рде рдкреНрд░рд╛рдХреГрддрд┐рдХ рд╕рдВрдЦреНрдпрд╛рдПрдБ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:

 0  1  2  3  4  5 ... 26 27 28 29
30 31 32 33 34 35 ... 56 57 58 59
60 61 62 63 64 65 ... 86 87 88 89
...

рдФрд░ 2, 3 рдФрд░ 5 рд╕реЗ рд╡рд┐рднрд╛рдЬреНрдп рд╕рднреА рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдкрд╛рд░ рдХрд░реЗрдВ:

.  1 . . . . .  7 . . . 11 . 13 . . . 17 . 19 . . . 23 . . . . . 29
. 31 . . . . . 37 . . . 41 . 43 . . . 47 . 49 . . . 53 . . . . . 59
. 61 . . . . . 67 . . . 71 . 73 . . . 77 . 79 . . . 83 . . . . . 89
...

рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╕рдорд╛рди рдкрджреЛрдВ рдкрд░ рд╕рдВрдЦреНрдпрд╛рдПрдБ рдкрд╛рд░ рдХреА рдЬрд╛рддреА рд╣реИрдВред рдЪреВрдВрдХрд┐ рд╣рдордиреЗ рдХреЗрд╡рд▓ рдорд┐рд╢реНрд░рд┐рдд рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдкрд╛рд░ рдХрд┐рдпрд╛ (рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╕рдВрдЦреНрдпрд╛ 2, 3, 5 рдХреЗ), рдлрд┐рд░ рдЕрднрд╛рдЬреНрдп рд╕рдВрдЦреНрдпрд╛рдПрдБ рдХреЗрд╡рд▓ рдЪрд┐рдиреНрд╣рд┐рдд рдкрджреЛрдВ рдореЗрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред

рдЪреВрдВрдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдЖрда рдРрд╕реА рд╕рдВрдЦреНрдпрд╛рдПрдБ рд╣реЛрддреА рд╣реИрдВ, рдпрд╣ рд╣рдореЗрдВ рдПрдХ рдмрд╛рдЗрдЯ рдХреЗ рд╕рд╛рде рдкреНрд░рддреНрдпреЗрдХ рддреАрд╕ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЖрда рдмрд┐рдЯреНрд╕ рд╕рдВрдЦреНрдпрд╛ рдХреА рд╕рд╛рджрдЧреА рдХреЛ рд╕рдВрдмрдВрдзрд┐рдд рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВрдЧреЗред рдпрд╣ рд╕рдВрдпреЛрдЧ рди рдХреЗрд╡рд▓ рд╕реМрдВрджрд░реНрдпрдкреНрд░рдж рд░реВрдк рд╕реЗ рд╕реБрдВрджрд░ рд╣реИ, рдмрд▓реНрдХрд┐ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рднреА рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ!

рдЫрд╡рд┐

рддрдХрдиреАрдХреА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдорд╛рд░рд╛ рд▓рдХреНрд╖реНрдп рдПрдХ рд╕реМ рдмрд┐рд▓рд┐рдпрди рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЪрд╛рд░ рдмрд╛рдЗрдЯ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдЕрдм рдирд╣реАрдВ рдЫреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдорд╛рд░рд╛ рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛:

class Wheel235
{
    private byte[] Data;

    public Wheel235(long length)
    {
        ...
    }
    public bool IsPrime(long n)
    {
        ...
    }
    ...
}

рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдЖрд╕рд╛рдиреА рдХреЗ рд▓рд┐рдП, рд╣рдо 30 рддрдХ рд╡рд┐рднрд╛рдЬреНрдп рдирд┐рдХрдЯрддрдо рд╕рдВрдЦреНрдпрд╛ рддрдХ рдЧреЛрд▓ рдХрд░реЗрдВрдЧреЗред рддрдм

class Wheel235
{
    private byte[] Data;

    public Wheel235(long length)
    {
        // ensure length divides by 30
        length = (length + 29) / 30 * 30; 
        Data = new byte[length/30];
        ...
    }

    public long Length => Data.Length * 30L;

    ...
}

рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рджреЛ рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: рдПрдХ рд╕реВрдЪрдХрд╛рдВрдХ 0..29 рдХреЛ рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд░рддрд╛ рд╣реИ, рджреВрд╕рд░рд╛, рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ рддреАрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВред рдЗрди рд╕рд░рдгрд┐рдпреЛрдВ рдФрд░ рдмрд┐рдЯ рдЕрдВрдХрдЧрдгрд┐рдд рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд╣рдо рдбреЗрдЯрд╛ рд╕рд░рдгреА рдореЗрдВ рдкреНрд░рд╛рдХреГрддрд┐рдХ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдФрд░ рдмрд┐рдЯреНрд╕ рдХреЗ рдмреАрдЪ рдПрдХ-рд╕реЗ-рдПрдХ рдкрддреНрд░рд╛рдЪрд╛рд░ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ рд╣реИрдВред рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рдХреЗрд╡рд▓ рджреЛ рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ: IsPrime (n), рдЬреЛ рдЖрдкрдХреЛ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╕рдВрдЦреНрдпрд╛ рдкреНрд░рдзрд╛рди рд╣реИ, рдФрд░ ClearPrime (n), рдЬреЛ рд╕рдВрдЧрдд рдмрд┐рдЯ рдХреЛ 0 рдкрд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рд╕рдВрдЦреНрдпрд╛ n рдХреЛ рдпреМрдЧрд┐рдХ рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд░рддрд╛ рд╣реИ:

class Wheel235
{
    private static int[] BIT_TO_INDEX = new int[] { 1, 7, 11, 13, 17, 19, 23, 29 };

    private static int[] INDEX_TO_BIT = new int[] {
        -1, 0,
        -1, -1, -1, -1, -1, 1,
        -1, -1, -1, 2,
        -1, 3,
        -1, -1, -1, 4,
        -1, 5,
        -1, -1, -1, 6,
        -1, -1, -1, -1, -1, 7,
    };

    private byte[] Data;

    ...

    public bool IsPrime(long n)
    {
        if (n <= 5) return n == 2 || n == 3 || n == 5;
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return false;
        return (Data[n / 30] & (1 << bit)) != 0;
    }

    private void ClearPrime(long n)
    {
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return;
        Data[n / 30] &= (byte)~(1 << bit);
    }
}

рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдпрджрд┐ рд╕рдВрдЦреНрдпрд╛ 2, 3 рдпрд╛ 5 рд╕реЗ рд╡рд┐рднрд╛рдЬреНрдп рд╣реИ, рддреЛ рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ -1 рд╣реЛрдЧреА, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕рдВрдЦреНрдпрд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рдордЧреНрд░ рд╣реИред рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рдо рдПрдХ рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ n = 5 рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдЕрдм, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рд╣реА, рдЬреЛ рд▓рдЧрднрдЧ рд╢рд╛рдмреНрджрд┐рдХ рд░реВрдк рд╕реЗ Eratosthenes рдХреА рдЪрд▓рдиреА рджреЛрд╣рд░рд╛рддрд╛ рд╣реИ:

    public Wheel235(long length)
    {
        length = (length + 29) / 30 * 30;
        Data = new byte[length / 30];
        for (long i = 0; i < Data.Length; i++) Data[i] = byte.MaxValue;

        for (long i = 7; i * i < Length; i++)
        {
            if (!IsPrime(i)) continue;
            for (long d = i * i; d < Length; d += i) ClearPrime(d);
        }
    }

рддрджрдиреБрд╕рд╛рд░, рдкреВрд░рд╛ рдкрд░рд┐рдгрд╛рдореА рд╡рд░реНрдЧ:

рдЬреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ
class Wheel235
{
    private static int[] BIT_TO_INDEX = new int[] { 1, 7, 11, 13, 17, 19, 23, 29 };

    private static int[] INDEX_TO_BIT = new int[] {
        -1, 0,
        -1, -1, -1, -1, -1, 1,
        -1, -1, -1, 2,
        -1, 3,
        -1, -1, -1, 4,
        -1, 5,
        -1, -1, -1, 6,
        -1, -1, -1, -1, -1, 7,
    };

    private byte[] Data;

    public Wheel235(long length)
    {
        // ensure length divides by 30
        length = (length + 29) / 30 * 30;
        Data = new byte[length / 30];
        for (long i = 0; i < Data.Length; i++) Data[i] = byte.MaxValue;

        for (long i = 7; i * i < Length; i++)
        {
            if (!IsPrime(i)) continue;
            for (long d = i * i; d < Length; d += i) ClearPrime(d);
        }
    }

    public long Length => Data.Length * 30L;

    public bool IsPrime(long n)
    {
        if (n >= Length) throw new ArgumentException("Number too big");
        if (n <= 5) return n == 2 || n == 3 || n == 5;
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return false;
        return (Data[n / 30] & (1 << bit)) != 0;
    }

    private void ClearPrime(long n)
    {
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return;
        Data[n / 30] &= (byte)~(1 << bit);
    }
}


рдХреЗрд╡рд▓ рдПрдХ рдЫреЛрдЯреА рд╕реА рд╕рдорд╕реНрдпрд╛ рд╣реИ: рдпрд╣ рдХреЛрдб рд▓рдЧрднрдЧ 65 рдмрд┐рд▓рд┐рдпрди рд╕реЗ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ! рдЬрдм рдЖрдк рдЗрд╕реЗ рдРрд╕реА рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдХреНрд░реИрд╢ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ:

Unhandled Exception: System.OverflowException: Array dimensions exceeded supported range.

рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рд╕реА # рд╕рд░рдгрд┐рдпреЛрдВ рдореЗрдВ 2 ^ 31 рд╕реЗ рдЕрдзрд┐рдХ рддрддреНрд╡ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ (рдЬрд╛рд╣рд┐рд░ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЖрдВрддрд░рд┐рдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЪрд╛рд░-рдмрд╛рдЗрдЯ рд╕рд░рдгреА рд╕реВрдЪрдХрд╛рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ)ред рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдмрд╛рдЗрдЯ [] рд╕рд░рдгреА рдХреЗ рдмрдЬрд╛рдп рдПрдХ рд▓рдВрдмрд╛ [] рд╕рд░рдгреА, рд▓реЗрдХрд┐рди рдпрд╣ рдереЛрдбрд╝рд╛ рдЕрдВрдХрдЧрдгрд┐рдд рдХреЛ рдереЛрдбрд╝рд╛ рдЬрдЯрд┐рд▓ рдХрд░реЗрдЧрд╛ред рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рджреВрд╕рд░реЗ рд░рд╛рд╕реНрддреЗ рдкрд░ рдЬрд╛рдПрдВрдЧреЗ, рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдЧ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВрдЧреЗ рдЬреЛ рд╡рд╛рдВрдЫрд┐рдд рд╕рд░рдгреА рдХрд╛ рдЕрдиреБрдХрд░рдг рдХрд░рддрд╛ рд╣реИ, рджреЛ рдЫреЛрдЯреА рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рдЕрдВрджрд░ рд░рдЦрддрд╛ рд╣реИред рдЙрд╕реА рд╕рдордп, рд╣рдо рдЙрд╕реЗ рдбрд┐рд╕реНрдХ рдкрд░ рдЦреБрдж рдХреЛ рдмрдЪрд╛рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рджреЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЖрдк рдПрдХ рдмрд╛рд░ primes рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХреЗрдВ, рдФрд░ рдлрд┐рд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:

    class LongArray
    {
        const long MAX_CHUNK_LENGTH = 2_000_000_000L;
        private byte[] firstBuffer;
        private byte[] secondBuffer;

        public LongArray(long length)
        {
            firstBuffer = new byte[Math.Min(MAX_CHUNK_LENGTH, length)];
            if (length > MAX_CHUNK_LENGTH) secondBuffer = new byte[length - MAX_CHUNK_LENGTH];
        }

        public LongArray(string file)
        {
            ...
        }

        public long Length => firstBuffer.LongLength + (secondBuffer == null ? 0 : secondBuffer.LongLength);

        public byte this[long index]
        {
            get => index < MAX_CHUNK_LENGTH ? firstBuffer[index] : secondBuffer[index - MAX_CHUNK_LENGTH];
            set
            {
                if (index < MAX_CHUNK_LENGTH) firstBuffer[index] = value; 
                else secondBuffer[index - MAX_CHUNK_LENGTH] = value;
            }
        }

        public void Save(string file)
        {
            ...
        }

    }


рдЕрдВрдд рдореЗрдВ, рд╕рднреА рдЪрд░рдгреЛрдВ рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░реЗрдВ

рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдг
class Wheel235
{
    class LongArray
    {
        const long MAX_CHUNK_LENGTH = 2_000_000_000L;
        private byte[] firstBuffer;
        private byte[] secondBuffer;

        public LongArray(long length)
        {
            firstBuffer = new byte[Math.Min(MAX_CHUNK_LENGTH, length)];
            if (length > MAX_CHUNK_LENGTH) secondBuffer = new byte[length - MAX_CHUNK_LENGTH];
        }

        public LongArray(string file)
        {
            using(FileStream stream = File.OpenRead(file))
            {
                long length = stream.Length;
                firstBuffer = new byte[Math.Min(MAX_CHUNK_LENGTH, length)];
                if (length > MAX_CHUNK_LENGTH) secondBuffer = new byte[length - MAX_CHUNK_LENGTH];
                stream.Read(firstBuffer, 0, firstBuffer.Length);
                if(secondBuffer != null) stream.Read(secondBuffer, 0, secondBuffer.Length);
            }
        }

        public long Length => firstBuffer.LongLength + (secondBuffer == null ? 0 : secondBuffer.LongLength);

        public byte this[long index]
        {
            get => index < MAX_CHUNK_LENGTH ? firstBuffer[index] : secondBuffer[index - MAX_CHUNK_LENGTH];
            set
            {
                if (index < MAX_CHUNK_LENGTH) firstBuffer[index] = value; 
                else secondBuffer[index - MAX_CHUNK_LENGTH] = value;
            }
        }

        public void Save(string file)
        {
            using(FileStream stream = File.OpenWrite(file))
            {
                stream.Write(firstBuffer, 0, firstBuffer.Length);
                if (secondBuffer != null) stream.Write(secondBuffer, 0, secondBuffer.Length);
            }
        }

    }

    private static int[] BIT_TO_INDEX = new int[] { 1, 7, 11, 13, 17, 19, 23, 29 };

    private static int[] INDEX_TO_BIT = new int[] {
        -1, 0,
        -1, -1, -1, -1, -1, 1,
        -1, -1, -1, 2,
        -1, 3,
        -1, -1, -1, 4,
        -1, 5,
        -1, -1, -1, 6,
        -1, -1, -1, -1, -1, 7,
    };

    private LongArray Data;

    public Wheel235(long length)
    {
        // ensure length divides by 30
        length = (length + 29) / 30 * 30;
        Data = new LongArray(length / 30);
        for (long i = 0; i < Data.Length; i++) Data[i] = byte.MaxValue;

        for (long i = 7; i * i < Length; i++)
        {
            if (!IsPrime(i)) continue;
            for (long d = i * i; d < Length; d += i) ClearPrime(d);
        }
    }

    public Wheel235(string file)
    {
        Data = new LongArray(file);
    }

    public void Save(string file) => Data.Save(file);

    public long Length => Data.Length * 30L;

    public bool IsPrime(long n)
    {
        if (n >= Length) throw new ArgumentException("Number too big");
        if (n <= 5) return n == 2 || n == 3 || n == 5;
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return false;
        return (Data[n / 30] & (1 << bit)) != 0;
    }

    private void ClearPrime(long n)
    {
        int bit = INDEX_TO_BIT[n % 30];
        if (bit < 0) return;
        Data[n / 30] &= (byte)~(1 << bit);
    }

}


рдирддреАрдЬрддрди, рд╣рдореЗрдВ рдПрдХ рдРрд╕рд╛ рд╡рд░реНрдЧ рдорд┐рд▓рд╛, рдЬреЛ рдПрдХ рд╕реМ рдЕрд░рдм рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдЕрдкрд░рд╛рдзреЛрдВ рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдбрд┐рд╕реНрдХ рдкрд░ рд╕рд╣реЗрдЬ рд╕рдХрддрд╛ рд╣реИ (рдореЗрд░реЗ рдкрд╛рд╕ 50 рдорд┐рдирдЯ рдХреЗ рд▓рд┐рдП рдореЗрд░реЗ рд▓реИрдкрдЯреЙрдк рдкрд░ рдпрд╣ рдХреЛрдб рдерд╛; рдмрдирд╛рдИ рдЧрдИ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЖрдХрд╛рд░ рд▓рдЧрднрдЧ 3 рдЧреАрдЧрд╛рдмрд╛рдЗрдЯ рдерд╛, рдЬреИрд╕рд╛ рдХрд┐ рдЕрдкреЗрдХреНрд╖рд┐рдд рдерд╛):

        long N = 100_000_000_000L;
        Wheel235 wheel = new Wheel235(N);
        wheel.Save("./primes.dat");

рдФрд░ рдлрд┐рд░ рдбрд┐рд╕реНрдХ рд╕реЗ рдкрдврд╝реЗрдВ рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:

        DateTime start = DateTime.UtcNow;
        Wheel235 loaded = new Wheel235("./primes.dat");
        DateTime end = DateTime.UtcNow;
        Console.WriteLine($"Database of prime numbers up to {loaded.Length:N0} loaded from file to memory  in {end - start}");
        long number = 98_000_000_093L;
        Console.WriteLine($"{number:N0} is {(loaded.IsPrime(number) ? "prime" : "not prime")}!");

All Articles