Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Primzahlen Problem

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 < [ 3 ]
010
28.09.2003, 14:04 Uhr
Pablo
Supertux
(Operator)


So, das ist das letzt was mir einfällt. Natürlich kann man das eine oder andere verbessern, aber ich hab es so gemacht, damit es jeder verstehen kann, auch wenn man wenig Erfahrung hat.
Das ist dynamisch, die Art, wie man das Array erstellt kann man verbessern, werde ich aber nicht tun, vielleicht hat hier der eine oder der andere eine bessere Idee als meine und postet auch seine Lösung. Meine wäre:

C++:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <malloc.h>

int* array;
int arrcount;
int istprim(unsigned int zahl)
{
    int i=1, j; // angegeben, die Zahl ist prim.
    if(zahl==0) return -1;
    if(zahl==1) return 0; // 1 ist keine primzahl
    if(zahl==2 || zahl==3 || zahl==5) return 1; //damit for schleife keine Probleme kriegt
    if(!(zahl%2)) return 0; // wenn positiv außer 2, dann ist nicht prim
    for (j=3; j<zahl/2; j=j+2) // wir brauchen nur bis zur Hälfte gehen
        i *= (zahl % j > 0);
    return i;
}

int erfuellt_eigenschaft(unsigned int zahl, int* a, int *b)
{
  int i, counter=0, z=pow(zahl,2)-1;

  // ich gehe davon aus, dass 0 nicht übergeben wird, sonst kann das eklig werden

  // für die Primzahlen 2, 3 wissen wir, dass sie die Eigenschaft nicht erfüllen (1)
  // für die Primzah und 5 folgt aus (1) dass sie die Eigenschaft nicht erfüllen, weil
  // 5^2=25 ist weder von 2, 3 teilbar ist, also können wir diese sofort ausgeben
  if(zahl == 2 || zahl == 3 || zahl == 5) return 0;
  // wenn wir hier ankommen, ist weil die Primzahl >= 7 ist, also mindestens 3 Primzahlen
  for(i=0; i<arrcount; ++i) {
     if(!(z % array[i])) {
       if(counter==0) *a=array[i];
       if(counter==1) *b=array[i];
       counter++; // zahl^2-1 ist diese Primzahl teilbar
      }
    
    if (counter>2) return 0; //wenn es mehr als 2 sind, brauche wir nicht mehr alle andere Primzahlen
  }
  return 1;
}
int main(int args, char** argv)
{
        int i, j=0,x,y, a,b, begin;

        if (args != 3) {
          printf("usage: %s x y\nx und y sind die Grenzen des Intervalls. Das Interval soll eine Teilmenge der Natürlichen Zahlen |N sein\n", argv[0]);
          return 0;
        }

        // das Programm wird nicht untersuchen, ob die Parameter zahlen sind
        // ich geh davon aus, dass sie Zahlen sind, hoffe ich :)
        x=atoi(argv[1]);
        y=atoi(argv[2]);
        if(y<x) {
          printf("Das eingebene Interval [%d,%d] ist mathematisch nicht korrekt.\n", x,y);
          return 0;
        }
        
        // Das array wird zuerst initialisiert, das Array wird mindestens 1Feld haben
        array = (int*)malloc(sizeof(int));
        arrcount=0;

        // Hier fängt alles an

        // array initialisieren:
        printf("Creating array....\n");
        for(i=1;i<=y; ++i) {
          if(istprim(i)==1) {
            array=realloc(array, (++arrcount)*sizeof(int));
            array[arrcount-1] = i;
            if (x > i) begin=arrcount;
          }
        }
        if (x<=2) begin=0;
        printf("Array created\n");


        for(i=begin; i<arrcount; ++i) {
            j = erfuellt_eigenschaft(array[i],&a,&b);
            if(j)
              printf("Die Primzahl %d erfüllt die Eigenschaft. Die anderen Primzahlen sind %d und %d\n",array[i],a,b);
            j=0;
        }
        
        /*for(i=begin; i<arrcount; ++i)
                printf("array[%d] = %d\n", i, array[i]);*/

        free(array);
        return 0;
}



Für das Interval [0; 10000] rechnet mein Rechner 1 Sekunde.
Für das Interval [0; 100000] hat mein Rechner aber 38 Sekunden gebraucht, und die Ausgabe hat 4802 Zeilen, also 4802 Primzahlen gefunden.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!

Dieser Post wurde am 28.09.2003 um 14:08 Uhr von Pablo Yanez Trujillo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
28.09.2003, 14:55 Uhr
~Mathias
Gast


In Zeile:
array=realloc(array, (++arrcount)*sizeof(int));
schmeißt mir Borland 3.1 einen Fehler aus:
Error: Cannot convert 'void *' to 'int *'
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
28.09.2003, 14:59 Uhr
Pablo
Supertux
(Operator)


Dann versuche so:


C++:
array = (int*) realloc(array, (++arrcount)*sizeof(int));



oder nur

C++:
realloc(array, (++arrcount)*sizeof(int));


ohne array =
so funktioniert auch, weil das ertse Parameter von realloc ein void* ist.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
28.09.2003, 15:09 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
Pablo Yanez Trujillo postete

C++:
  [...]
    for (j=3; j<zahl/2; j=j+2) // wir brauchen nur bis zur Hälfte gehen



[/i]

Du brauchst sogar nur bis zur Wurzel:

C++:
    for (j=3; j*j<zahl; j=j+2)


wäre also folglich komplett ausreichend

--edit: Pablo. Ein i zu viel in [ cpp ] tags --
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 28.09.2003 um 15:12 Uhr von Pablo Yanez Trujillo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
28.09.2003, 15:34 Uhr
Pablo
Supertux
(Operator)


Das ist richtig, stimmt, das hab ich nicht gemerkt, aber die Schleife muss dann

C++:
for (j=3; j*j-1<zahl; j=j+2)



sein, weil sonst 9, 25, 49, .... auch dabei sind und dann falsch wäre, aber mit -1 vor dem < Zeichen funktioniert es richtig.

Und das Programm läuft dann viel viel schneller, für das Interval [0; 100000] brauche ich nun nur 5 Sekunden. 33 Sekunden schneller, das ist besser.
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
015
28.09.2003, 21:55 Uhr
~Mathias
Gast


Also Pablo ich bin echt begeistert, alle Achtung !!!
Ich bin grad noch am rätzeln wie (genauer wo) man einen Zähler einbaut der alle gefundenen Primzahlen die in der Ausgabe angezeigt werden zählt und ganz unten noch mit anzeigt, zb:
Insgesammt wurden im Zahlenbereich x bis y soundsoviel Primzahlen gefunden.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
016
28.09.2003, 22:49 Uhr
Pablo
Supertux
(Operator)


Das lässt sich sehr einfach einbauen.

Deklarieren in int main() eine int / long Variable names zaehler.

C++:
int main(int args, char** argv)
{
    int zaehler=0;
    ...
}



Dann verändere die Zeile j = erfuellt_eigenschaft(array[ i ],&a,&b); so:


C++:
int main(int args, char** argv)
{
    ...
    for(i=begin; i<arrcount; ++i) {
        zaehler += j = erfuellt_eigenschaft(array[ i ],&a,&b);
}



Wenn die for-Schleife beendet wird, d.h. i==arrcount dann hat zaehler die Anzahl der gefundenen Primzahlen.


Bearbeitung:
erfuellt_eigenschaft liefert 0 oder 1 zurück. Sie liefert 1, wenn die Primzahl die Bedingung erfüllt, sonst 0. Das Zuweisen einer Variable liefert den Zuweisungswert zurück, und da j entweder mit 0 oder 1 zugewisen wird, dann können wir zaehler um 1 oder um 0 inkrementieren.

--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!

Dieser Post wurde am 28.09.2003 um 22:54 Uhr von Pablo Yanez Trujillo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
017
29.09.2003, 09:31 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
Pablo Yanez Trujillo postete
Dann versuche so:


C++:
array = (int*) realloc(array, (++arrcount)*sizeof(int));



oder nur

C++:
realloc(array, (++arrcount)*sizeof(int));


ohne array =
so funktioniert auch, weil das ertse Parameter von realloc ein void* ist.



Nein, das ist Schrott. Du standest wegen dieser Annahme bereits schonmal vor einem Problem: www.fun-soft.de/showtopic.php?threadid=3830

Bitte mal im Forum die unzähligen beiträge zum Thema realloc lesen.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
018
29.09.2003, 11:41 Uhr
NemoEimi




Zitat:
~Mathias postete
Da ist mir wohl ein kleiner Fehler unterlaufen.
Also nochmal:
1.) Primzahlen berechnen, nach Eingabe des Anfangs- und Endwertes
2.) gefundene Primzahl^2-1
3.) Nun überprüfen ob der errechnete Wert das Produkt von maximal 2 kleineren Primzahlen ergibt.
4.) Falls ja, Ausgabe der gefundenen Primzahl und der beiden kleineren Primzahlen



Ok, sei p also eine Primzahl, ohne nennenswerte Beschränkung der Allgemeinheit ausserdem p > 3. Dann ist p^2 - 1 = (p + 1)(p - 1), und weil darin p ungerade war, sind p - 1 und p + 1 teilbar durch 2, weil p nicht durch drei teilbar war, ist entweder p - 1 oder p + 1 teilbar durch drei. Insgesamt haben wir also für p^2 - 1 im Fall p > 3 schonmal _mindestens_ zwei verschiedene Primteiler.
Angenommen nun, p^2 - 1 hat noch andere Primfaktoren, dann ist mindestens einer davon kleinergleich (p + 1)/2, also insbesondere wie verlangt kleiner als p. Um festzustellen, ob eine gegebene Primzahl p die gewünschte Eigenschaft hat, müssen wir also nur aus p^2 - 1 die höchstmöglichen Potenzen von zwei bzw. drei ausdividieren und schauen, ob das was übrig bleibt größer als eins ist oder nicht, bzw. das gleiche für p - 1 und p + 1 tun, was aus Gründen der besseren Kompatibilität zur Maschinenarithmetik vorzuziehen ist, denn p+1 erzeugt seltener Überlauffehler als p^2 - 1.
Hier ist mal eine Implementierung des ganzen in Java (das entsprechende in C machen darfst Du ):


C++:
class Prim_tester {
  private int num_small_primes;
  private int max_div;
  private int[] test_div;
  private void init_test_arr(int grenze) {
    int[] tmp = new int[grenze/2];
    int zaehler = 2;
    tmp[0] = 2; tmp[1] = 3; int p = 5;
    while (p < grenze) {
      boolean is_prime = true; int test_num = 1; int test_teiler = 3;
      while (is_prime && test_teiler * test_teiler <= p) {
        if (p % test_teiler == 0) is_prime = false;
    test_num = test_num + 1;
    test_teiler = tmp[test_num];
    }
      if (is_prime) {
        tmp[zaehler] = p;
        zaehler = zaehler + 1;
        }
      p = p + 2;
      }
    test_div = new int[zaehler];
    num_small_primes = zaehler; if (grenze%2 == 1) max_div = grenze; else max_div = grenze + 1;
    System.arraycopy(tmp, 0, test_div, 0, zaehler);
    }
  public int small_divisor(long n) {
    if (n%2 == 0) return(2);
    int test_teiler = 3; int k = 1;
    while (test_teiler * test_teiler <= n) {
      if (n % test_teiler == 0) return(test_teiler);
      k = k + 1;
      if (k == num_small_primes) return(0);
      test_teiler = test_div[k];
      }
    return(0);
    }
  public boolean simple_prime_test(long n) {
    int small_test = small_divisor(n);
    if (small_test != 0) return(false);
    if (max_div * max_div > n) return(true);
    long test_teiler = max_div;
    while (test_teiler * test_teiler <= n) {
      if (n % test_teiler == 0) return(false);
      test_teiler = test_teiler + 2;
      }
    return(true);
    }
  public Prim_tester(int max_test) {
    init_test_arr(max_test);
    }
  }

public class prog_primes {
  public static long dividiere_zwei_aus(long n) {
    while (n%2==0) {
      n = n / 2;
      }
    return(n);
    }
  public static long dividiere_drei_aus(long n) {
    while (n%3==0) {
      n = n / 3;
      }
    return(n);
    }
  public static boolean hat_gewünschte_eigenschaft(long p) {
    long pminuseins = p - 1;
    long ppluseins = p + 1;
    if (ppluseins < 0) System.out.println("Überlauf bei Long-Addition! Vorsicht!");
    long x = dividiere_zwei_aus(pminuseins); x = dividiere_drei_aus(x);
    long y = dividiere_zwei_aus(ppluseins); y = dividiere_drei_aus(y);
    if (x > 1  || y > 1) return(false); else return(true);
    }
  public static void main(String[] args) {
    long anfang = Long.parseLong(args[0]); long ende = Long.parseLong(args[1]);
    Prim_tester test = new Prim_tester(64000);
    if (anfang%2 == 0) anfang = anfang + 1;
    for (long i = anfang; i < ende; i = i + 2) {
      if (test.simple_prime_test(i) && hat_gewünschte_eigenschaft(i)) System.out.println(i);
      }
    }
  }




Grüße,
Nemo

P.S.: Das obige Programm läßt sich natürlich ganz leicht noch viel effizienter machen, denn da nur _entweder_ p+1 oder p-1 durch drei teilbar sein können, muss jedes p, das die gewünschte Eigenschaft hat, von der Form 2^n + 1 oder 2^n - 1 sein, also entweder eine Fermat'sche oder eine Mersenne'sche Primzahl. Von den Fermatzahlen vermutet man, daß sie äußerst abzählbar sind (sozusagen an einer Hand abzählbar), und sowohl für Mersenne- als auch für Fermatzahlen existieren sehr effiziente einfach zu implementierende deterministische Suchverfahren.

Dieser Post wurde am 29.09.2003 um 21:58 Uhr von Pablo Yanez Trujillo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
019
29.09.2003, 21:39 Uhr
~Anfänger
Gast


Tolles Programm, sehr interessant um was zu lernen :-)
Wo oben nach einer Abänderung gefragt wurde, kannst du mir erklären wie das Funktioniert, das man den .exe Namen gefolgt von den Paramtern eingeben kann ?
Und wie man das in das Programm einbaut, das man gefragt wird welche Parameterbereiche man durchsuchen möchte ?
MfG
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 < [ 3 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: