OberonCore
https://forum.oberoncore.ru/

Решето Эратосфена.
https://forum.oberoncore.ru/viewtopic.php?f=72&t=1964
Страница 1 из 2

Автор:  Alexey Veselovsky [ Понедельник, 19 Октябрь, 2009 18:57 ]
Заголовок сообщения:  Решето Эратосфена.

А есть ли быстрые реализации оного решета на Haskell'e?

А то то, что я сотворил ни в какие ворота не лезло в плане производительности.

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 08:08 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Когда-то я баловался с этим делом, примерно такие результаты получил:
Код:
                  100000        1000000
Haskell          1.82 sec       47.7 sec
C GCC 3.4.5      0.44 sec       11.3 sec
ComponentPascal  0.65 sec       17.0 sec
Код:
primes'wheel :: [Int]
primes'wheel = 2:3:5:7:filter isPrime'wheel (spin wheel2357 11)
  where
    isPrime'wheel :: Int -> Bool
    isPrime'wheel !x = all (\p -> x `mod` p /= 0) $ takeWhile (\p -> p*p <= x) $ tail primes'wheel

    wheel2357 :: [Int]
    wheel2357 = 2:4:2:4:6:2:6:4:2:4:6:6:2:6:4:2:6:4:6:8:4:2:4:2:
                4:8:6:4:6:2:4:6:2:6:6:4:2:4:6:2:6:4:2:4:2:10:2:10:wheel2357

    spin :: [Int] -> Int -> [Int]
    spin (x:xs) n = n:spin xs (n + x)
Код:
#define maxn 1000000

int ps[maxn];

int primes_c (int n)
{
    int  i = 2, j, p = 5, f;
    ps[0] = 2; ps[1] = 3;
    while (i < n)
    {
        f = 1; j = 1;
        while (f && (ps[j]*ps[j] <= p))
        {
            f = (p % ps[j]);
            j++;
        }
        if (f)
        {
            ps[i] = p;
            i++;
        }
        p += 2;
    }
    return ps[i-1];
}
Код:
MODULE Primes;
IMPORT SL:=StdLog;

CONST nmax = 1000000;
VAR ps : ARRAY nmax OF INTEGER;

PROCEDURE Prime(n : INTEGER) : INTEGER;
VAR i, j, p : INTEGER;
    f : BOOLEAN;
BEGIN
  ps[0] := 2; ps[1] := 3;
  i := 2; p := 5;
  WHILE i < n DO
    f := TRUE;
    j := 1;
    WHILE f & (ps[j]*ps[j] <= p) DO
      f := (p MOD ps[j]) # 0;
      INC(j)
    END;
    IF f THEN
      ps[i] := p;
      INC(i)
    END;
    INC(p,2)
  END;
  RETURN ps[n-1]
END Prime;

PROCEDURE Do*;
BEGIN
  SL.Int(Prime(1000000)); SL.Ln;
END Do;

END Primes.

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 08:11 ]
Заголовок сообщения:  Re: Решето Эратосфена.

А вот версия, которая всего на 8% медленнее лучшей сишной:
Код:
{-# OPTIONS -O2 -optc-O -fbang-patterns #-}
--
-- The Computer Language Shootout
-- http://shootout.alioth.debian.org/
--
-- Contributed by Don Stewart
-- nsieve over an ST monad Bool array
--

import Control.Monad.ST
import Data.Array.ST
import Data.Array.Base
import System
import Control.Monad
import Data.Bits
import Text.Printf

main = do
    n <- getArgs >>= readIO . head :: IO Int
    mapM_ (sieve . (10000 *) . (2 ^)) [n, n-1, n-2]

sieve n = do
   let r = runST (do a <- newArray (2,n) True :: ST s (STUArray s Int Bool)
                     go a n 2 0)
   printf "Primes up to %8d %8d\n" (n::Int) (r::Int) :: IO ()

go !a !m !n !c
    | n == m    = return c
    | otherwise = do
          e <- unsafeRead a n
          if e then let loop !j
                          | j < m     = do
                              x <- unsafeRead a j
                              when x $ unsafeWrite a j False
                              loop (j+n)

                          | otherwise = go a m (n+1) (c+1)
                    in loop (n `shiftL` 1)
               else go a m (n+1) c

Автор:  Илья Ермаков [ Вторник, 20 Октябрь, 2009 08:21 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Хм, занятно-подозрительное название unsafeRead :) Какой-то прямой доступ к данным в памяти?

Автор:  Info21 [ Вторник, 20 Октябрь, 2009 08:31 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Не умеет программировать человек.

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 08:53 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Илья Ермаков писал(а):
Хм, занятно-подозрительное название unsafeRead :) Какой-то прямой доступ к данным в памяти?

Это вообще недокументированная функция, как и unsafeWrite. В них нет проверки индекса, которую делают документированные версии перед их вызовом этих низкоуровневых. То есть в данном случае максимальное приближение к Си.

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 08:54 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Info21 писал(а):
Не умеет программировать человек.

Кто именно? :lol: Можете привести вариант получше? :wink:

Автор:  vvp [ Вторник, 20 Октябрь, 2009 10:51 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Geniepro писал(а):
Info21 писал(а):
Не умеет программировать человек.

Кто именно? :lol: Можете привести вариант получше? :wink:


Эратосфен придумал свой алгоритм для того, чтобы избавиться от операций деления и умножения в любом виде. То есть от нахождения остатка тоже надо избавлятся. Там достаточно операций счета количества пройденных чисел. Сейчас кстати у меян идет занятия и на соседней машине мальчишка 9-классник завершает решето без делений. Это не в обиду сказано. Просто использование операций деления в решете достаточно типичная ошибка. Это я не как программист, это я как учитель.

Автор:  Info21 [ Вторник, 20 Октябрь, 2009 11:05 ]
Заголовок сообщения:  Re: Решето Эратосфена.

vvp писал(а):
Просто использование операций деления в решете достаточно типичная ошибка.
Как и неумение писать циклы.

Автор:  Alexey Veselovsky [ Вторник, 20 Октябрь, 2009 11:07 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Geniepro писал(а):
Info21 писал(а):
Не умеет программировать человек.

Кто именно? :lol: Можете привести вариант получше? :wink:


Вот вариант накиданый по быстрому по описанию с википедии (http://ru.wikipedia.org/wiki/Решето_Эратосфена):
Код:
#include <iostream>
#include <vector>

int main () {
    int n = 0;
    std::cin >> n;
    std::vector<bool> prime (n);
    for (int i=2; i<n; ++i) prime[i]=true;
    for (int i=2; (i*i)<=n; ++i) {
        if (prime[i])
            for (int j=(i*i); j<=n; j+=i)
                prime[j]=false;
    }

    for (int i=0; i<n; ++i) if (prime[i]) std::cout << " " << i;
    std::cout << std::endl;
    return 0;
}


Миллион считает сильно быстрее чем за секунду.

PS. Да, первые два элемента в векторе лишние. И да, можно было написать чуть красивей.

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 11:17 ]
Заголовок сообщения:  Re: Решето Эратосфена.

vvp писал(а):
Эратосфен придумал свой алгоритм для того, чтобы избавиться от операций деления и умножения в любом виде. То есть от нахождения остатка тоже надо избавлятся.
Ну значит у меня не решето Эратосфена вышло... :lol:

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 11:18 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Info21 писал(а):
Как и неумение писать циклы.

Ну а в циклах-то где проблема? :roll:

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 11:20 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Alexey Veselovsky писал(а):
А то то, что я сотворил ни в какие ворота не лезло в плане производительности.

А что Вы сотворили-то?

Автор:  Илья Ермаков [ Вторник, 20 Октябрь, 2009 11:22 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Если в цикле возникает "f: BOOLEAN" - флаг в условии, то это значит, что цикл составлен неверно. Эмуляция break через логический флаг. (Излюбленное возражение самоделкиных - "а если я буду без брейков, то мне нужны логические флаги..").

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 11:42 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Илья Ермаков писал(а):
Если в цикле возникает "f: BOOLEAN" - флаг в условии, то это значит, что цикл составлен неверно. Эмуляция break через логический флаг.

Вы имеете в виду этот кусок:
Код:
    f := TRUE;
    j := 1;
    WHILE f & (ps[j]*ps[j] <= p) DO
      f := (p MOD ps[j]) # 0;
      INC(j)
    END;
    IF f THEN
      ps[i] := p;
      INC(i)
    END;
Да, помню это место. Вначале так не было, приходилось дважды вычислять выражение (p MOD ps[j]) # 0, а так как оптимизатора в компиляторе BB нет, то это замедляло выполнение на 20%. Так что это просто оптимизация.
А вы тут сразу -- "не умеешь, не умеешь!!!" :lol: :lol: :lol:

Автор:  Илья Ермаков [ Вторник, 20 Октябрь, 2009 11:59 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Ну да, правда.

Автор:  Alexey Veselovsky [ Вторник, 20 Октябрь, 2009 14:52 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Geniepro писал(а):
Alexey Veselovsky писал(а):
А то то, что я сотворил ни в какие ворота не лезло в плане производительности.

А что Вы сотворили-то?


Вот такой вот ужоз:

Код:
prime' n = loop1 (listArray (2,n) (repeat True)) 2 n
           where
               loop1 arr i n | (i*i)>n  = arr
               loop1 arr i n | (arr ! i)= loop1 (loop2 arr (i*i) i n) (i+1) n
               loop1 arr i n            = loop1 arr (i+1) n
               loop2 arr j i n | j<=n = loop2 (arr//[(j,False)]) (j+i) i n
               loop2 arr j i n        = arr

main = do  s <- getLine
           cout (prime' $ read s) 2 (read s)

cout :: Array Int Bool -> Int -> Int -> IO ()
cout arr i n | i<=n && (arr ! i) = do print i
                                      cout arr (i+1) n
cout arr i n | i<=n = cout arr (i+1) n
cout arr i n        = print "--"

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 15:45 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Alexey Veselovsky писал(а):
Вот такой вот ужоз:

Массивы Array в GHC жутко тормозные, я это тоже замечал...

Автор:  Alexey Veselovsky [ Вторник, 20 Октябрь, 2009 15:46 ]
Заголовок сообщения:  Re: Решето Эратосфена.

Geniepro писал(а):
Alexey Veselovsky писал(а):
Вот такой вот ужоз:

Массивы Array в GHC жутко тормозные, я это тоже замечал...


Не думаю, что если этот же пример собрать каким-нибудь UHC, программа станет работать существенно быстрее ;-)

Автор:  Geniepro [ Вторник, 20 Октябрь, 2009 15:53 ]
Заголовок сообщения:  Re: Решето Эратосфена.

А попробуйте STUArray как в том примере с shootout -- может получше будет?

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/