[c] liczby pierwsze

robin5hood
Użytkownik
Użytkownik
Posty: 1676
Rejestracja: 2 kwie 2007, o 14:43
Płeć: Mężczyzna
Lokalizacja: warszawa
Podziękował: 178 razy
Pomógł: 17 razy

[c] liczby pierwsze

Post autor: robin5hood »

jak napisac program .który znajduje wszystkie liczby pierwsze w zakresie 30 do 30000 takie, że zarówno
suma, jak i iloczyn ich cyfr są również liczbami pierwszymi. z góry dzieki
matshadow
Użytkownik
Użytkownik
Posty: 941
Rejestracja: 17 gru 2007, o 21:48
Płeć: Mężczyzna
Lokalizacja: Kingdom Hearts
Podziękował: 6 razy
Pomógł: 222 razy

[c] liczby pierwsze

Post autor: matshadow »

Kod: Zaznacz cały

#include <stdio.h>
int tablica[30001];
int ok(int i)
{
    int t[5],w=0,s=i,k,suma=0,iloczyn=1;
    while(s>0)
    {
        t[w]=s%10;
        s/=10;
        w++;
    }
    for(k=0;k<w;k++)
    {
        suma+=t[k];
        iloczyn*=t[k];
    }
    return (tablica[suma]&&tablica[iloczyn]);
}
int main()
{
	int i,j,t;
	for(i=1;i<=30000;i++) tablica[i]=1;
	for (i=2; i<=30000; i++)
	{
        if (tablica[i])
   		{
      	  	j = 2*i;
          	while (j<=30000)
      	  	{
         		tablica[j] = 0;
         		j += i;
          	}
   		}
	}
	for(i=30;i<30001;i++)
        if(tablica[i]&&ok(i)) printf("%d
",i);
	return 0;
}
Xitami

[c] liczby pierwsze

Post autor: Xitami »

Kod: Zaznacz cały

   for(i=3;i<=30000;i++) tablica[i]=i & 1;
   tablica[2]=1; tablica[0]=tablica[1]=0;
   for (i=2; i<=173; i++)
        if (tablica[i])    {
             j = i*i;
             while (j<=30000) {
               tablica[j] = 0;
               j += i;
             }
         }
spajder
Użytkownik
Użytkownik
Posty: 735
Rejestracja: 7 lis 2005, o 23:56
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 2 razy
Pomógł: 133 razy

[c] liczby pierwsze

Post autor: spajder »

Akurat tutaj to jest dużo prostsze. Skoro iloczyn cyfr ma być liczbą pierwszą to conajwyżej jedna cyfra może nie być jedynką. Tak więc mamy do sprawdzenia tylko kilkadziesiąt (może ze 150 max) liczb. Jeśli jako pierwsze sprawdzimy, czy suma cyfr jest pierwsza, potem to samo z iloczynem a na koniec samą liczbę to program wykona się kilkadziesiąt razy szybciej niż przy sicie eratostenesa.
Xitami

[c] liczby pierwsze

Post autor: Xitami »

Przy małym zakresie Sito jest jednak dobrym sposobem
W 70 sekund znalazłem 49 takich liczb, doszedłem do 112'111'111'111'111'111.

Kod: Zaznacz cały

#include <stdio.h>

int isprime(unsigned long long int n){    //  poprawka, dodałem "long long"
	unsigned int d;
	if (n<2) return 0;
	if (n<4) return 1;
	if (n%2==0 || n%3==0) return 0;
	d=5;
	while((unsigned long long int)d*d<=n){
		if (n%d==0) return 0;
		d+=2;
		if (n%d==0) return 0;
		d+=4;
	}
	return 1;
}

void g(int i, int p){
	unsigned long long s;
	int k,j;
	if(isprime(p+i)) 
		for(j=0; j<=i; j++) {
			s=0;
			for(k=i; k>=0; k--)
				if(k==j) s=s*10+p;
				else s=s*10+1;
			if (/*s<=30000 &&*/ isprime(s))
				printf("%I64d ", s);
		}
}

int main(){
	int i;
	for(i=0; i<18; i++) {
		if(i==0) g(0,2);
		if(i&1)  g(i, 2);
		else {
			g(i, 3);
			g(i, 5);
			g(i, 7);
		}
	}
	while(1);
}
Ostatnio zmieniony 11 maja 2009, o 20:12 przez Xitami, łącznie zmieniany 2 razy.
spajder
Użytkownik
Użytkownik
Posty: 735
Rejestracja: 7 lis 2005, o 23:56
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 2 razy
Pomógł: 133 razy

[c] liczby pierwsze

Post autor: spajder »

Moim zdaniem można to troszkę podrasować. Napisałem w C++, łatwo można zmienić zakres - program wyszukuje pierwsze 155 takich liczb, zajmuje mu to 0,15s:

Kod: Zaznacz cały

#include <cstdlib>
#include <iostream>
#include <ctime>

using namespace std;

const int nieparzyste[] = {1, 3, 5, 7};

bool czyPierwsza(int liczba)
{
    for(int i = 2; i*i <= liczba; i++)
        if(liczba % i == 0)
            return false;

    return true;
}


int main(int argc, char *argv[])
{
    long czas = clock();
    int licznik = 0;

    for(int i = 2; i < 20; i++)
        for(int j = 0; j < i; j++)
            if(i%2 == 0)
            {
                long long liczba = 0;
                for(int l = 0; l < i; l++)
                {
                    liczba *= 10;
                    if(l == j) liczba += 2;
                    else liczba += 1;
                } 
                if(czyPierwsza(i+1) && czyPierwsza(liczba))
                {
                    cout << liczba << endl; 
                    licznik++;
                }
            } else
                for(int k = 0; k < 4; k++)
                {
                    long long liczba = 0;
                    for(int l = 0; l < i; l++)
                    {
                        liczba *= 10;
                        if(l == j) liczba += nieparzyste[k];
                        else liczba += 1;
                    } 
                    if(czyPierwsza(i - 1 + nieparzyste[k]) && czyPierwsza(liczba))
                    {
                        cout << liczba << endl;
                        licznik++;
                    }
               }

    czas = clock() - czas;
    float s = static_cast<float>(czas) / CLOCKS_PER_SEC;
    cout << "Znalazlem " << licznik << " liczb" << endl;
    cout << "Zejelo mi to " << s << " sekund" << endl;
    system("PAUSE>>null");
    return EXIT_SUCCESS;
}
Xitami

[c] liczby pierwsze

Post autor: Xitami »

Jeszcze nie przeczytałem do końca, ale...
isprime(111111111121111111) == 0
a rozumiem, że powinna być pierwsza

Dla wszystkich odpowiednich liczb (pierwsza suma i iloczyn cyfr), poza dwójką,
wystarczy sprawdzić czy 2 jest świadkiem w teście Rabina-Millera
(sprawdziłem do 1e100),
mam takiego cosia

Kod: Zaznacz cały

uint64 mul_mod1(uint64 a, uint64 b, uint64 m) {
  uint64 y = (uint64)((float64)a*(float64)b/m+(float64)1/2); // floor(a*b/m)
  y = y * m; // m*floor(a*b/m) mod z
  uint64 x = a * b; // a*b mod z
  uint64 r = x - y; // a*b mod z - m*floor(a*b/m) mod z
  if ( (int64)r < 0 ) // normalization needed ?
  {
    r = r + m;
    y = y - 1; // (a*b)/m quotient, omit line if not needed
  }
  return r; // (a*b)%m remnant
}
teoretycznie liczy a^b%n, a,b,n<2^60, czyli można by przyśpieszyć.
Ale coś nie chce działać.

49 liczb, tyle mieści się w long long int.
  • 2,3,5,7,113,131,311,151,2111, 11113, 11131, 11311, 11117, 11171, 111121, 111211, 112111, 1111151, 1111711, 1117111,
    1171111, 111111113, 111111131, 111113111, 131111111, 115111111, 1111111121, 1111211111, 1121111111, 11111111113,
    11111111131, 11113111111, 11131111111, 31111111111, 17111111111, 111111211111, 111211111111, 1111151111111,
    5111111111111, 1111171111111, 111111151111111, 111151111111111, 11111111113111111, 11111111111111171,
    11111111171111111, 111111111111112111, 111111112111111111, 111111211111111111, 112111111111111111
następna to dopiero 131111111111111111111

zmieniłem trochę swój kod, teraz 62 sekundy

Kod: Zaznacz cały

void g(int i, uint64 j, uint64 p){
	uint64 w;
	int k;
	if(isprime(p+i))	{
		k=i; w=p;
		while(k>0) { 
			w*=10; k--;
		}
		p--;
		while(w>p) {
			if(isprime(p+j)) {
                printf("%19I64d ", p+j);
				m++;
			}
			p*= 10;
		}
	}
}

int main(){
	unsigned int i,c;
	uint64 j;
	c=clock(); m=0;
	j=1;
	for(i=0; i<10; i++) {
		//printf("
(%d) ",i);
		if(i==0) g(0, j, 2);
		if(i &1) g(i, j, 2);
		else {
			g(i, j, 3);
			g(i, j, 5);
			g(i, j, 7);
		}
		j=j*10+1;
	}
	c=clock()-c;
	printf("
koniec
%d sztuk
%4d.%03d sekund",m,c/1000,c%100);while(1);
}
już wiem, poprawiłem twoją funkcję

Kod: Zaznacz cały

bool czyPierwsza(long long int liczba)
{
    for(int i = 2; (unsigned long long int)i*i <= liczba; i++)
        if(liczba % i == 0)
            return false;

    return true;
}
Popatrz jak ja to robię, jestem jakieś 3 razy szybszy
spajder
Użytkownik
Użytkownik
Posty: 735
Rejestracja: 7 lis 2005, o 23:56
Płeć: Mężczyzna
Lokalizacja: Łódź
Podziękował: 2 razy
Pomógł: 133 razy

[c] liczby pierwsze

Post autor: spajder »

Znam kilka testów pierwszości, natomiast chodziło mi tu o to, że program można baaaaardzo przyspieszyć zauważając kilka prostych rzeczy - moja wersja działa tak, że generuje jedynie liczby pewnej postaci (posiadające poza jedynką max jedną cyfrę - do tego nie sprawdzam wszystkich możliwych cyfry). Następnie dla każdej tak utworzonej liczby sprawdzam, czy suma jej cyfr jest pierwsza. Dopiero ostatnie sprawdzenie to sprawdzenie pierwszości tej liczby - wykonuje się ono (w przedziale 30-30000) kilkadziesiąt razy, więc to działa bardzo szybko.

Co do zakresu - nie wiem, eksperymentowałem. Na pewno więcej już przekracza zakres.
Xitami

[c] liczby pierwsze

Post autor: Xitami »

Zauważ, że robię tak samo.
Nie pomijam 2, 3, 5, 7, ale to drobiazg.
Popraw for(int i = 2; i < 20; i++) na for(int i = 2; i < 19; i++) tyle można dla long long.
po zmianie testu pierwszości na mój, twój program liczy minimalnie wolniej, 65 sekund.
ODPOWIEDZ