Portál AbcLinuxu, 25. října 2025 16:02
Když jsem se loni rozhodoval, jaké semináře si zvolit do 4. ročníku, programování byla moje jasná volba.
Měl jsem štěstí, že se našlo víc lidí a seminář se otevřel. Hned v první hodině jsme dostali za úkol napsat algoritmus pro výčet prvočísel, následně zakreslit jeho vývojový diagram a ti co už měli zkušenosti s programováním ho i napsat v nějakém programovacín jazyku. Tento úkol se mi velice líbil, a tak jsem se hned pustil do práce. První verze programu jsem měl za chvíli a fungovali dobře, jako jazyk jsem zvolil C++. Jedinou nevýhodou byla rychlost, kdyý jsem chtěl vypsat všechna prvočísla do 100 000, tak to trvalo +- 1 minutu. A tak jsem začal optimalizovat kód, nejprve sem dělal jen drobné změny, potom použil při kompilaci přepínač -O3, čímž jsem se dostal asi na dobu 32s pro prvočísla do 100 000.
Neuspokojilo mě to, ačkoliv to znamenalo zrychlení zhruba o 50%, a tak jsem nakonec celý program úplně přepsal a zvolil jinačí způsob hledání prvočísel. Což se ukázalo jako dobré řešení. Doba pro výčet prvočísel do 100 000 byla kolem 0.900s a po par optimalizacich jsem se dostal na 0.005s. Nakonec jsem se rozhodl to napsat i v ruby, ve kterem to jede sice pomaleji, ale i tak je to rychlejsi nez muj prvni navrh v C++.
Celkově z toho mám dobrý pocit, ale věřím, že by se to dalo ještě vylopšit, ačkoliv už nevím jak. No jediný problém jsou nároky na pamět pro výčet prvočísel do 1 000 000 000 si to vezme skoro 1GB paměti  
Kód v C++:
#include <cmath>
#include <iostream>
using namespace std;
typedef unsigned long long myInt;
int main ( int argc, char *argv[] ){
        myInt nRozsah = 100000;
        //cout << "Zadejte rozsah:" << endl;
        //cin >> nRozsah;
        nRozsah++;
        bool *polePravda = new bool[ nRozsah];
        long op = long(sqrt(nRozsah));
        for ( myInt j = 3; j < op; j += 2 ){
                        if(polePravda[j]==false){
                        for ( myInt k = j; k <= nRozsah/j; k += 2 ){
                                polePravda[ k * j ] = true;
                        }
                        }
        }
        cout << 2 << endl;
        for ( myInt l = 3; l < nRozsah; l += 2 ){
                if ( polePravda[l] == false){
                        cout << l;
                }
        }
        return 0;
 
Kód v Ruby:
#!/usr/bin/env ruby
$KCODE = 'UTF-8'
require 'mathn'
nRozsah = 1000000
polePravda = Array.new(nRozsah, 0)
op = Math.sqrt(nRozsah)
j = 3
         loop { 
  
                if polePravda[j] == 0 then 
                        k = j
                        loop do
                                polePravda[ k * j ] = 1
                                k +=2
                                break if k > nRozsah/j 
                        end
                end
  
                j += 2
                break if j >= op
        }
        x = 3
        loop {
                if polePravda[x] == 0 then
                        puts x
                end
                x += 2
                break if x > nRozsah
        }
Jinak časy byly meřeny pomocí příkazu time a výstup byl přesměrován do souboru.
        Tiskni
            
                Sdílej:
                 
                 
                 
                 
                 
                 
            
    
Diskuse byla administrátory uzamčena
 
             ))
))
             
            Generují náhodné číslo pro něž ověří je-lis jistou pravděpodobností
prvočíslo, pokud není generují znovu.
 
            ((prvočíslo * prvočíslo) + 1)věřím, že by se to dalo ještě vylopšit, ačkoliv už nevím jak
Wikipedie se u Eratosthenova síta zmiňuje o urychlování pomocí kruhové faktorizace, tak to můžeš zkusit 
Tvůj program je ± Eratosthenovo síto, to co je na wikipedii pod heslem wheel factorization je ale jedna z metod rychlých odhadů prvočíselnosti. (podobné používají třeba kryptografické programy při generování klíčů - teprve pokuď projde číslo některým z těchto testů, zkouší se dál, jestli je to skutečně prvočíslo)
#!/usr/bin/env ruby
nRozsah = 10000
puts (2..nRozsah).inject((2..nRozsah).to_a) {|res, i| res.select{|n|n==i||n%i!=0} }
             
            
#include <stdio.h>
#include <math.h>
#include "error.h"
#define N 100000000LU
#define UI \
  (unsigned int)
#define SIZE(num) \
  (num / (sizeof(long) * 8) + 2)
#define BITS \
  (sizeof(long) * 8)
#define BITPOS(index) \
  ((index % BITS) + 1)
#define ArrayPos(index) \
  (UI index/BITS+1)
#define OutArrayError(pole, index) \
  Error("Index %ld mimo rozsah 0..%ld", (long) index, (long) pole[0])
#define OutArray(pole, index) \
 (index < 0 || index > pole[0]) ? OutArrayError(pole, index),0 :
#define BitArray(jmeno_pole, velikost) \
  unsigned long jmeno_pole[SIZE(velikost)] = {0}; \
  jmeno_pole[0] = velikost
#ifndef USE_INLINE
#define GetBitIn(jmeno_pole, index) \
  (jmeno_pole[ArrayPos(index)] & (1LU << BITPOS(index)) ? 1 : 0)
#define GetBit(jmeno_pole, index) \
  OutArray(jmeno_pole, index) GetBitIn(jmeno_pole, index)
#define SetBit(pole, index, vyraz) \
  if(!(index >= 0U && index <= pole[0]))\
    OutArrayError(pole, index);\
  if(vyraz != 0) \
    pole[ArrayPos(index)] |= 1LU << BITPOS(index); \
  else \
    pole[ArrayPos(index)] ^= GetBit(pole, index) << BITPOS(index)
#endif
#ifdef USE_INLINE
inline int GetBit(unsigned long pole[], long index)
{
  if(index < 1 || index > pole[0])
    Error("Index %ld mimo rozsah 0..%ld", (long) index, (long) pole[0]);
  return pole[ArrayPos(index)] & ((1LU << BITPOS(index)) ? 1 : 0);
}
inline void SetBit(unsigned long pole[], long index, int vyraz)
{
  if(index < 0 || index > pole[0])
    Error("Index %ld mimo rozsah 0..%ld", (long) index, (long) pole[0]);
  if(vyraz != 0)
    pole[ArrayPos(index)] |= 1LU << BITPOS(index);
  else
    pole[ArrayPos(index)] ^= GetBit(pole, index) << BITPOS(index);
}
#endif
int main()
{
  BitArray(eSito, N);
  SetBit(eSito, 0, 1);
  SetBit(eSito, 1, 0);
  for(unsigned int i = 2; i < N; i++)
  { 
    SetBit(eSito, i, 0);
  }
  unsigned long sqrt_n = sqrt(N);
  for(unsigned int i = 2; i < sqrt_n; i++)
  {
    if(GetBit(eSito, i) == 0)
    {
      for(unsigned int j = i * i; j < N; j += i)
      {
        SetBit(eSito, j, 1);
      }
    }
  }
  int count = 0;
  int prvocisla[10] = {0};
  for(unsigned int i = N - 1; i > 1; i--)
  {
    if(GetBit(eSito, i) == 0)
    {
      prvocisla[count] = i;
      count += 1;
      if(count == 10)
        break;
    }
  }
  for(int i = 0; i < 10; i++)
    printf("%d\n", prvocisla[9-i]);
  return 0;
}
Funkcni by to byt melo, nejrychlejsi je to pri pouziti maker, inlive funkce jsou tam pro porovnani (bylo v zadani) a je to cca o 1s pomalejsi. Jeste dodam, ze se vypisuje jen poslednich 10prvocisel, vypisovat vsechno by bylo pochopitelne znacne pomalejsi, kuli io operacim.
            ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.