Computerhilfen.de Logo
Forum
Tipps
News
Frage stellen

Primzahlen: Was läßt sich verbessern?

Ich habe ein wenig mit C angefangen. Was macht man als erstes Programm? Was wohl jeder schon mal programmiert hat: Primzahlberechnung.

Was lässt sich an diesem Programm verbessern? Besonders der Switch gefällt mir nicht:

Wenn ich nicht mehr weiter kann,
mach' ich einen Schalter an.

#include <stdio.h>
#define MAX 500000

int main()
{
long int z[MAX], iz, i, i2, j, k, l;
int sw;
/* in z[] werden die gefundenen Primzahlen
    gespeichert. Jede weitere Zahl kann
    nur dann eine Primzahl sein, wenn sie
    sich durch eine der gefundenen Primzah-
    len teilen läßt. Diese Prüfung braucht
    aber nur bis zum halben Wert der aktuell
    zu prüfenden Zahl i durchgeführt werden
    (Um Widerspruch wird gebeten).

   i=aktuell auf Primzahl zu prüfende Zahl
   j=Index(z) für Primzahlprüfung
   k=aktuelle Primzahl für Prüfung mit i */
iz=2;
z[1]=2;
z[2]=3;
printf ("2,3");
/* maximal MAX Primzahlen berechnen */
for (i=1; iz<MAX && i<2147483647 ; i++)
{
   k=z[1];
   i2=i/2;
   sw=0;
/* Prüfe, ob i durch bisherige Primzahlen
                  bis max. i/2 teilbar ist */

   for (j=1; k<=i2 ; j++, k=z[j])
   {
      sw=1;
      l=(i/k);
      if (l*k==i)
      {
          sw=0;
          break;
      };
   };
   if (sw)
   {
      z[++iz]=i;
      printf (",%d",i);
   };  
};
printf ("\nAnzahl=%d \n", iz);
return 0;
}

« Letzte Änderung: 21.05.05, 23:58:24 von cottonwood »

Antworten zu Primzahlen: Was läßt sich verbessern?:

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Diesen Teil:

 for (j=1; k<=i2 ; j++, k=z[j])
  {
      sw=1;
      l=(i/k);
      if (l*k==i)
      {
          sw=0;
          break;
      };
  };
kannst Du durch eine Do-While-Schleife eleganter machen:
int j = 1;
bool sw = true; //bool ist als "Schalter" besser
do
{
  k = z[j];
  l = i/k;
  if (l*k == i) sw = false;
  j++;
}
while((flag)&&(k<=i2));

Ansonsten ist doch nicht schlecht. Du kannst noch ggf die long durch int ersetzen, und dann mit a = (int)(b/c); Nachkommastellen abschneiden. Das macht einige Rechenoperationen schneller (wenn nicht sogar alle).

Natürlich gibt es bessere und schnellere Algorithmen, aber die sind wahrscheinlich nix zum Programmieren Lernen. Insofern ist das Ding doch gut. Scheint zu funktionieren und es stecken sogar einige Optmierungsideen drin.

Gruß Spawn

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Danke für die Hinweise. Ich habe dazu noch ein paar Fragen (wie Anfänger so sind). Doch erst mal das geänderte Programm:

#include <stdio.h>
#define MAX 500000
int main()
{
long int z[MAX], iz, i, i2, j, k, l;
// int sw; ** muss hier jetzt natürlich raus.
/* in z[] werden die gefundenen Primzahlen
    gespeichert. Jede weitere Zahl kann
    nur dann eine Primzahl sein, wenn sie
    sich durch eine der gefundenen Primzah-
    len teilen läßt. Diese Prüfung braucht
    aber nur bis zum halben Wert der aktuell
    zu prüfenden Zahl i durchgeführt werden.
   i=aktuell auf Primzahl zu prüfende Zahl
   j=Index(z) für Primzahlprüfung
   k=aktuelle Primzahl für Prüfung mit i */
iz=2;
z[1]=2;
z[2]=3;
printf ("2,3");
/* maximal MAX Primzahlen berechnen */
for (i=1; iz<MAX && i<2147483647 ; i++)
{
   k=z[1];
   i2=i/2;
//   sw=0;  ** muss hier jetzt natürlich auch raus.
/* Prüfe, ob i durch bisherige Primzahlen
                  bis max. i/2 teilbar ist */

  int j = 1;
   bool sw = true; //bool ist als "Schalter" besser
   do
   {
      k = z[j];
      l = i/k;
      if (l*k == i) sw = false;
      j++;
   }
   while((flag)&&(k<=i2));
   if (sw)
   {
      z[++iz]=i;
      printf (",%d",i);
   };  
};
printf ("\nAnzahl=%d \n", iz);
return 0;
}


1) Was ist (flag)? Sollte das (sw) heissen? Bei der Übersetzung bekomme ich folgende Fehlermeldung.

   F:\C\York\main.cpp   In function `int main()':
41  F:\C\York\main.cpp   `flag' undeclared (first use this function)


2) Ist das

  int j = 1;
   bool sw = true; //bool ist als "Schalter" besser


   ausführbar oder reine Definition? Das steht nämlich in der äusseren Schleife und muss dort jedes Mal gesetzt werden.

3) Kann ich dann die Zeilen

     l = i/k;
      if (l*k == i) sw = false;


   auch gleich durch

     if ((int)(i/k)*k == i) sw = false;

   ersetzen? Oder kann ich sogar

     if (i/k*k == i) sw = false;

   schreiben, weil das ja sowieso int ist?

Ich habe auch noch mal über den Algorithms nachgedacht. Ich glaube, ich muss nur bis zur Wurzel von "i" prüfen.

« Letzte Änderung: 22.05.05, 12:27:26 von cottonwood »

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button
Die umgestellte Schleife funktioniert leider nicht. Das liegt m.E. daran, dass die Schleife jetzt mindestens einmal durchlaufen wird.

Ansonsten habe ich alles übernommen, allerdings nach Ansi-C-Regeln.

#include <stdio.h>
#include <math.h>
#define MAX 500000

int main()
{
long int z[MAX], iz, i, i2, j, k;
bool sw;
/* in z[] werden die gefundenen Primzahlen
    gespeichert. Jede weitere Zahl kann
    nur dann eine Primzahl sein, wenn sie
    sich durch eine der gefundenen Primzah-
    len teilen läßt. Diese Prüfung braucht
    aber nur bis zur Wurzel der aktuell
    zu prüfenden Zahl i durchgeführt werden.
   i=aktuell auf Primzahl zu prüfende Zahl
   j=Index(z) für Primzahlprüfung
   k=aktuelle Primzahl für Prüfung mit i */
iz=2;
z[1]=2;
z[2]=3;
printf ("2,3");
/* maximal MAX Primzahlen berechnen */
for (i=1; iz<MAX && i<2147483647 ; i++)
{
   k=z[1];
   i2=(long) sqrt((float)(i));
   sw=false;
/* Prüfe, ob i durch bisherige Primzahlen
             bis max. sqrt(i) teilbar ist */

   for (j=1; k<=i2 ; j++, k=z[j])
   {
      sw=true;
      if (i/k*k==i)
      {
          sw=false;
          break;
      };
   };
   if (sw)
   {
      z[++iz]=i;
      printf (",%d",i);
   };  
};
printf ("\nAnzahl=%d \n", iz);
return 0;
}


Das Programm lief mit "i2=i/2;" noch ca. 29 Minuten.
Jetzt (mit "i2=(long) sqrt((float)(i));") läuft es nur noch wenige Sekunden.

Was lässt sich noch verbessern?
« Letzte Änderung: 22.05.05, 13:42:41 von cottonwood »

Standardanfängerprimzahlenoptimierung: Alle geraden Zahlen sind keine Primzahlen ;-)

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button
Standardanfängerprimzahlenoptimierung: Alle geraden Zahlen sind keine Primzahlen ;-)
Danke. Habe ich auch gerade bemerkt.

Mir ist auch noch aufgefallen, dass ich die errechneten Primzahlen ja auch nur bis zur Wurzel der höchsten zu berechnenden Primzahl zwischenspeichern muss. Umkehrschluss: Ich kann die Primzahlen (jetzt) bis zum Quadrat der größten gespeicherten Primzahl berechnen. Damit kann ich jetzt alle Primzahlen berechnen, die ich mit long int darstellen kann.

Leider kann ich das Ergebnis nicht mehr überprüfen. Ich kann mir die Datei nicht mehr anschauen. Ausserdem dauert das jetzt etwa 3 Std und 15 Min.

#include <stdio.h>
#include <math.h>
#define MAXMAX 2147483647
#define MAX 46341 //sqrt(MAXMAX)

int main()
{
long int z[MAX], iz, i, i2, j, k, max2;
bool sw;
/* in z[] werden die gefundenen Primzahlen
    gespeichert. Jede weitere Zahl kann
    nur dann eine Primzahl sein, wenn sie
    sich durch eine der gefundenen Primzah-
    len teilen läßt. Diese Prüfung braucht
    aber nur bis zur Wurzel der aktuell
    zu prüfenden Zahl i durchgeführt werden.
   i=aktuell auf Primzahl zu prüfende Zahl
   j=Index(z) für Primzahlprüfung
   k=aktuelle Primzahl für Prüfung mit i
*/
/* neu (23.5.2005): Es werden die Primzahlen
   bis zu MAXMAX errechnet, aber nur bis MAX
   zwischengespeichert.
*/
iz=2;
z[1]=2;
z[2]=3;
printf ("2,3");

for (i=3; i<MAXMAX ; i=i+2)
{
   k=z[1];
   i2=(long) sqrt((float)(i));
   sw=false;
/* Prüfe, ob i durch bisherige Primzahlen
             bis max. sqrt(i) teilbar ist */

   for (j=1; k<=i2 ; j++, k=z[j])
   {
      sw=true;
      if (i/k*k==i)
      {
          sw=false;
          break;
      };
   };
   if (sw)
   {
      iz++;
      if (iz<=MAX) z[iz]=i;
      printf (",%d",i);
   };  
};
printf ("\nAnzahl=%d \n", iz);
return 0;
}


hier ein paar Zahlen zwischendurch:

73686373,73686397,73686421,73686433,73686439,
73686451,73686493,73686497,73686521,73686577,
73686607,73686623,73686629,73686637,73686673,
73686677,73686751,73686757,73686761,73686763,
73686787,73686791,73686793,73686839,73686931,
73686971,73687001,73687021,73687037,73687049,
73687063,73687087,73687099,73687109,73687123,
73687139,73687181,73687199,73687219,73687241,
73687249,73687261,73687267,73687307,73687321,
73687343,73687349,73687357,73687363,73687381,
73687417,73687429,73687433,73687459,73687489,
73687499,73687501,73687553,73687577,73687591,
73687613,73687633,73687667,73687687,73687697,
73687709,73687727,73687759,73687769,73687777,
73687799,73687819,73687841


Diese Zahlen habe ich mit dem Ergebnis von  dieser Seite verglichen. Sind identisch.
« Letzte Änderung: 24.05.05, 00:08:44 von cottonwood »

Du hast geschrieben, dass du nur bis zu einer bestimmten Zahl die Primzahlen ermitteln musst, weil die folgenden immer das doppelte oder so ist! Aber eine Primzahl lässt sich nur durch 1 und sich selbst restlos teilen! Deswegen musst du das nochmal überdenken!

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button
Du hast geschrieben, dass du nur bis zu einer bestimmten Zahl die Primzahlen ermitteln musst, weil die folgenden immer das doppelte oder so ist! Aber eine Primzahl lässt sich nur durch 1 und sich selbst restlos teilen! Deswegen musst du das nochmal überdenken!
Die Regel heisst m.E., dass sich eine Primzahl genau durch zwei Zahlen (restlos) teilen lässt. Sonst wäre 1 ja auch eine. Aber ich habe inzwischen irgendwo im Web gefunden, dass ich wirklich nur durch alle Primzahlen bis zur Wurzel der zu testenden Zahl prüfen muss.

Du musst nur bis zur Wurzel prüfen, weil:

- Wenn X die zu überprüfende Zahl ist, und X keine Primzahl wäre weil X = y*z und y > sqrt(X) ist, dann ist z < sqrt(X) und wäre schon zuerst geprüft worden.

Du musst nur Primzahlen prüfen weil:

- Ist X die zu prüfende Zahl mit X = y*z und y ist keine Primzahl also y = a*b würde ja auch gelten X = a*(b*z) und a < y und wäre schon geprüft.

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Du hast bestimmt Recht.

Ich prüfe bis zur Wurzel, weil es ja egal ist, ob ich 5x7 oder 7x5 prüfe und

ich prüfe nur Primzahlen, weil alle anderen Zahlen sich ja schon durch Primzahlen teilen lassen.

Ist das dasselbe?


« Eigenes sytemFunktion im SQL-Server mit Query-Analyzer »
 

Schnelle Hilfe: Hier nach ähnlichen Fragen und passenden Tipps suchen!

Fremdwörter? Erklärungen im Lexikon!
Grundstrich
Der Begriff des Grundstrichs im Bereich der Typografie, bezeichnet den senkrechten Strich der Buchstaben. Bei Schriftarten mit variabler Strichstärke, wie zum Beispi...

Haarstrich
Der Begriff Haarstrich stammt aus dem Bereich der Typographie. Bei Schriften, wie zum Beispiel der Antiquaschrift mit unterschiedlichen Strichstärken, wird zwischen ...

Internet-Zugriffsprogramm
Ein Internet-Zugriffsprogramm, auch Browser genannt, stellt Internetseiten für den Benutzer dar. Am bekanntesten ist der Microsoft Internet Explorer, gefolgt vom kos...