Summe berechnen?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet
C++:

#include <iostream>

bool isPrime( __int64 );

void main()
{
 __int64 zahl,summe;

 /* 
 isPrime() erkennt Primzahlen ab 5, 
 deshalb bei 5 beginnen, und die Summe schon mal auf 2+3
 setzen. Es werden nur ungerade Zahlen getestet.
 */
 for (summe=2+3, zahl=5; zahl <= 4294967296 ; zahl+=2)
 {
   if ( isPrime(zahl))
     summe += zahl;
 }

 printf("Die Summe aller Primzahlen beträgt %I64d\n", summe);
}

bool isPrime
(
 __int64 zahl
)
{
 if (zahl <= 1) 
   return false;

 if (zahl % 2 == 0 || zahl % 3 == 0) 
   return false;

 for (__int64 i = 5; i * i <= zahl; i += 6)
   if (zahl % i == 0 || zahl % (i + 2) == 0) 
     return false;

 return true;
}
ralphdieter  16.02.2024, 16:22

Du hast die 2 vergessen und die 3 nicht erkannt:

summe=2+3;

 // bei 5 beginnen und nur ungerade Zahlen testen
 for (zahl = 5;  ...

Und __int64 ist kein Standard-Typ. So geht's aber:

typedef int64_t __int64;

Und für die ersten 10% bekomme ich:

> g++ -O2 -DNDEBUG sumprimes.c++ && time ./a.out 
Die Summe aller 22822681 Primzahlen bis 429496729 beträgt 2161808136
real   11m8,340s
user   11m7,928s

Das volle Programm sollte also ca. in 24 Stunden durch sein.

2
ralphdieter  16.02.2024, 22:05
@ralphdieter

Wenn man die berechneten Primzahlen speichert und in isPrime() benutzt, geht es deutlich schneller:

> g++ -O2 -DNDEBUG listprimes.c++ && time ./a.out
Sum of primes up to 4294967296
Estimated count is 4294967296/17=252645135.
Die Summe aller 203280221 Primzahlen bis 4294967296 beträgt 425649736193687430

real   103m10,940s
user    103m8,121s
sys     0m0,592s
0
ralphdieter  16.02.2024, 22:07
@rixtwix007

Ich empfehle GNU's g++. Der kostet nix und produziert flotte Executables.

0
ralphdieter  17.02.2024, 09:52
@rixtwix007

Ja, der sollte gehen (falls er keine Laufzeitbegrenzung hat). Kopiere einfach den korrigierten Quelltext rein, klicke auf „Run“ und lehn Dich zurück.

Hier hast Du eine lauffähige Version mit Zwischenausgaben und de Möglichkeit, in Zeile 9 eine kleinere Obergrenze zu setzen (zum Testen):

#include <iostream>
typedef uint64_t __int64;

bool isPrime( __int64 );

int main()
{
 __int64 zahl,summe;
 const __int64 limit = 4294967296lu/100;

 /*
 isPrime() erkennt Primzahlen ab 5,
 deshalb bei 5 beginnen, und die Summe schon mal auf 2+3
 setzen. Es werden nur ungerade Zahlen getestet.
 */
 for (summe=2+3, zahl=5; zahl <= limit ; zahl+=2)
 {
   if ( isPrime(zahl))
     summe += zahl;

   if ( zahl % 10000000 == 1 || zahl==limit )
   {
      printf( "%10lu \r", zahl );
      fflush(stdout);
   }
 }

 printf("Die Summe aller Primzahlen bis %lu beträgt %lu\n", limit, summe);
 return true;
}

bool isPrime
(
 __int64 zahl
)
{
 if (zahl <= 1)
   return false;

 if (zahl % 2 == 0 || zahl % 3 == 0)
   return false;

 for (__int64 i = 5; i * i <= zahl; i += 6)
   if (zahl % i == 0 || zahl % (i + 2) == 0)
     return false;

 return true;
}
1
rixtwix007 
Fragesteller
 17.02.2024, 09:43

Wie findest du meinen Code? #include <iostream>

#include <vector>

#include <cmath>

bool istPrim(unsigned long long n) {

  if (n <= 1) return false;

  if (n == 2) return true;

  if (n % 2 == 0) return false;

  for (unsigned long long i = 3; i <= sqrt(n); i += 2) {

    if (n % i == 0) return false;

  }

  return true;

}

int main() {

  unsigned long long summe = 0;

  for (unsigned long long i = 2; i <= 4294967296; ++i) {

    if (istPrim(i)) {

      summe += i;

    }

  }

  std::cout << "Die Summe aller Primzahlen von 2 bis 4294967296 ist: " << summe << std::endl;

  return 0;

}

1
ralphdieter  17.02.2024, 10:16
@rixtwix007
#include <vector>

Wozu das?

for (unsigned long long i = 3; i <= sqrt(n); i += 2) {

i<=sqrt(n) hat Rundungsprobleme: sqrt(p²) könnte einen Wert liefern, der ganz knapp unter p liegt, und ein großer int64 kann nicht exakt in einen double umgewandelt werden. Deine Schleife wird also manche Quadratzahlen als prim erkennen, weil sie zu früh endet.

Rammstein prüft stattdessen i*i<=n. Das ist sicher und vermutlich auch schneller.

Außerdem testest Du jeden Teiler 2k+1. Das sind 50% mehr Tests als mit Rammsteins 6k±1.

0
ralphdieter  17.02.2024, 10:21
@rixtwix007

Erste Antwort: Deinen eigenen natürlich!

Aber ich habe dich gewarnt: Er könnte falsche Ergebnisse liefern. Probiere also beide aus (oder verbessere Deinen eigenen Code).

1
rixtwix007 
Fragesteller
 17.02.2024, 10:25
@ralphdieter

Dann nehme ich den korrigierten von Rammstein. Was ist mit deinem?

0
ralphdieter  17.02.2024, 11:04
@rixtwix007

Meiner? Ich habe nur Rammsteins Code umgeschrieben und teste nur Primteiler. Das ist nur 1/16 aller Zahlen (bei Rammstein 1/3, bei dir 1/2).

Dazu muss ich aber alle berechneten Primzahlen speichern, was im vollen Lauf 2 GB speicher frisst. Ich weiss nicht, ob der Onlinecompiler das erlaubt, aber Du kannst ja mal testen:

#include <iostream>
#include <cmath>

typedef uint64_t number;

bool isPrime( number zahl ) // zahl >= 5
{
  if ( zahl % 3 == 0 )
    return false;

  for ( number i = 5; i*i <= zahl; i += 6 )
    if ( zahl % i == 0 || zahl % (i + 2) == 0 )
      return false;

  return true;
}

const number step = 1000000
           , limit = 4294967293lu/10;

number *primes;


bool isPrime2 ( number zahl ) // zahl >= 5
{
  for ( number i = 0; primes[i] && primes[i]*primes[i] <= zahl; ++i )
    if ( zahl % primes[i] == 0 )
    {
      //printf( "                     %lu teilt %lu\n", primes[i], zahl );
      return false;
    }
  return true;
}


int log ( number n )
{
    int l=1;
    while ( n >>= 2 )
      ++l;
    return l;
}


int main()
{
  printf( "Sum of primes up to  %lu\n", limit );
  printf( "Estimated count is %'lu/%d=%'ld.\n", limit, log(limit), limit/log(limit) );
  primes = (number*)calloc(limit/log(limit), sizeof *primes);  // ~N/log N
  primes[0] = 2, primes[1] = 3;

  number zahl, summe=2+3, count=2;

  // bei 5 beginnen und nur ungerade Zahlen testen
  for (zahl = 5; zahl <= limit; zahl += 2)
  {
    if ( isPrime2(zahl) )
    {
      summe += zahl;
      primes[count] = zahl;
      ++count;
      //printf( "       primes[%10lu]=%10lu\n", count, zahl );
    }

    if ( zahl % step == 1 || zahl==limit )
    {
      printf( "\r%10lu %10lu ", zahl-1, count );
      fflush(stdout);
    }
  }

  printf("\nDie Summe aller %lu Primzahlen bis %lu beträgt %lu\n", count, limit, summe);
  return 0;
}
1
rixtwix007 
Fragesteller
 17.02.2024, 11:10
@ralphdieter

Ich habe den Code von Rammstein eingegeben, akzeptiert er nicht 🤷‍♂️

0
Rammstein53  17.02.2024, 11:21
@rixtwix007

Ich nutze Visual Studio 2022 von Microsoft. Die Community-Version ist voll funktionsfähig und kostenlos.

1
ralphdieter  17.02.2024, 11:30
@rixtwix007

Der Code in der Antwort funktioniert nur mit dem Compiler von Microsoft. Ich habe Dir weiter oben schon eine Korrektur gepostet, die dem C++-Standard entspricht (und zusätzlich noch Zwischenausgaben ausspuckt).

Nur die letzte Version von mir ist anders: Sie verwaltet ein Array von Primzahlen und ist dadurch deutlich schneller, braucht aber auch viel mehr Speicherplatz.

1
rixtwix007 
Fragesteller
 17.02.2024, 11:36
@ralphdieter

Super, danke dir! Ich probiere mal meinen (korrigiert) und Rammsteins (von dir korrigiert) aus. Muss ich bei deinen noch auf 4294967296 setzen und wann merke ich, wann er fertig ist?

0
Rammstein53  17.02.2024, 11:43
@rixtwix007

Mit einer "normalen" CPU ist der Rechner sicher mehrere Stunden beschäftigt. Abschätzungen aufgrund kleinerer Endwerte sind ungenau, weil die Laufzeit von isPrime() immer weiter ansteigt. Da kann man aber noch viel optimieren.

0
Rammstein53  17.02.2024, 11:53
@rixtwix007

Mein Code war nur als Vorschlag gedacht. Man könnte z.B. ein Bit-Array mit 4294967296 Elementen aufbauen und dann das Sieb von Eratosthenes anwenden. Das läuft sicher schneller.

1
rixtwix007 
Fragesteller
 17.02.2024, 12:06
@Rammstein53

Ich benutze jetzt mein Code. Mal sehen, wie lange es dauert 😅

0
rixtwix007 
Fragesteller
 17.02.2024, 13:19
@Rammstein53

Das von dir kommt bloß auf 54057787600298. Ich weiß echt nicht, wie ich auf die echte Zahl kommen soll 🤷‍♂️

1
ralphdieter  17.02.2024, 13:30
@rixtwix007
Du:    4762888964838152
Ich: 425649736193687430

Wahrscheinlich hast Du noch das „/10“ zum Testen drin.

Achtung: Bei zehnfachem Wert läuft das Programm vermutlich hundertmal so lang! Nur meine Version verhält sich etwas besser, weil die Dichte der Primzahlen langfristig gegen 0 geht.

1
rixtwix007 
Fragesteller
 17.02.2024, 13:31
@ralphdieter

Ist dein Wert der genaue oder wurde dort auch abgebrochen?

0
ralphdieter  17.02.2024, 13:44
@rixtwix007

In meiner Version steht sowas wie „limit=4294967293lu / 10;“, um den Zahlenbereich und damit die Rechenzeit zu begrenzen. Das ist nur zum Testen gedacht. Bei „/10“ ist die Summe nur 4762888964838152, und bei „/100“ nur 54057787600298.

Die Summe über alle Primzahlen bis 2³² ist exakt 425649736193687430. Das dauert halt etwas (auf meinem Rechner knapp 2 Stunden, der Online-Rechner ist vielleicht schneller).

Achtung: Bei mir stoppt der Onlinerechner, wenn ich in ein anderes Fenster wechsle. Du wirst also während der Berechnung nichts anderes am Computer machen können.

0
rixtwix007 
Fragesteller
 17.02.2024, 13:51
@ralphdieter

Das ist der exakte Wert? Ich habe jetzt die exakte Summe?

0
rixtwix007 
Fragesteller
 17.02.2024, 14:11
@ralphdieter

Ich habe es gerade in die Aufgabe eingetippt. Es stimmt einfach

1