Ein np.array vorne mit 1en befüllen, hinten zuschneiden

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Sirius3
User
Beiträge: 18217
Registriert: Sonntag 21. Oktober 2012, 17:20

Programmieren bedeutet zum großen Teil Sorgfältigkeit. Dazu gehört, dass man immer mit 4 Leerzeichen pro Ebene einrückt, nicht mal 4 und dann wieder 3 oder gar 12 und dann wieder nur 1 Leerzeichen. Vor einem Leerzeichen kommt maximal ein Leerzeichen.
Die Schreibweise von Variablennamen ist klein_mit_unterstrich.
String stückelt man nicht mit str und + zusammen sondern benutzt Stringformatierung.

Die weißt was die Bedingung in `kontrolle` bedeutet? Würde man so nicht schreiben, weil man es nicht sofort versteht, besser:

Code: Alles auswählen

def kontrolle(p):
    """Kontrolle eines Wertes"""
    if p % 3 == 0 or p % 5 == 0 or p % 7 == 0 or p % 13 == 0:
        print(factors(p))
Was der Sinn der Funktion ist, kann ich aber nicht erkennen.

`zusatz_aussiebung` enthält auch Schludrigkeiten. Die Parameter pmin und pmax werden nicht verwendet, sondern die globalen Variablen pMin und pMax. Ein Glück, dass die Funktion nicht benutzt wird. Daneben benutzt die Funktion noch weitere globale Variablen, die Funktion ist also unverständlich.

`mach_die_pList` benutzt `isprime` statt ein Sieb, was Du ja eigentlich implementieren wolltest. Das Argument `p` ist ziemlich rätselhaft.

Das was unter "Hauptparameter" steht, sind eigentlich Konstanten sollten KOMPLETT_GROSS geschrieben werden und am Anfang der Datei stehen.
Statt `Sieblaenge` mit einem Dummy-Wert zu belegen, damit die while-Schleife überhaupt loslaufen kann, macht man normalerweise eine while-True-Schleife und verläßt sie per break.
Hier kann man den Wert aber auch einfach ausrechnen:

Code: Alles auswählen

kE -= (kE - kA) // 2 % -4620
Sieblaenge  = (kE - kA) // 2
Die for-Schleife ab "Hier gehts los" ist viel, viel zu lang. Das muß dringend in viele Funktionen aufgeteilt werden. Statt ein Sieb zu benutzen benutzt Du schon wieder `isprime`.
Warum rechnest Du XList und YList so kompliziert aus, wo Du doch numpy benutzt?

`ndarray.item` habe ich noch nie in Benutzung gesehen. Ist hier auch nicht nötig, gegenüber einem einfachen Index-Zugriff.

Alles in allem sind da viele Dinge drin, die den Code nur umständlicher aber nicht wirklich schneller machen.

Code: Alles auswählen

import re
import time
import numpy
from sympy import isprime

START_EXPONENT = 6007000000
END_EXPONENT = 6008000000
FAKTORS = 55    # in 2er Potenz
MAX_PRIME = 1000  # Wert zwischen 900 und 1100 ist gut
SIEVE_LENGTH = (2 ** FAKTORS // START_EXPONENT + 2) // 2

def get_odd_primes(size):
    sieve = numpy.ones(size//2, dtype=bool)
    sieve[0] = False
    for i in range(3, int(size**0.5)+2, 2):
        sieve[i*i//2::i] = False
    result = numpy.nonzero(sieve)[0]
    return result*2+1

def get_primes_range(odd_primes, start, stop):
    if odd_primes[-1]**2 < stop:
        raise RuntimeError("too few primes {} <-> {}".format(odd_primes[-1]**2, stop))
    max_idx = numpy.searchsorted(odd_primes, stop**0.5)
    primes = odd_primes[:max_idx]
    n = (start + primes - 1) // primes
    n += (n+1)&1
    start_indices = primes * numpy.maximum(primes, n) - start
    sieve = numpy.ones((stop-start)//2, dtype=bool)
    for i, prime in zip(start_indices, primes):
        sieve[i//2::prime] = False
    return numpy.nonzero(sieve)[0]*2+1 + start

def get_factor_primes(exponent, odd_primes):
    sieve = numpy.ones(SIEVE_LENGTH, dtype=bool)
    for prime in odd_primes[:MAX_PRIME]:
        i = numpy.nonzero((exponent * 2 * numpy.arange(prime) + 1) % prime == 0)[0][0]
        sieve[i::prime] = False
    return numpy.nonzero(sieve)[0] * (2 * exponent) + 1

def main():
    odd_primes = get_odd_primes(int(END_EXPONENT**0.5) + 100) # brauche noch die nächst größere Primzahl
    print("Sieblaenge: {}".format(SIEVE_LENGTH))
    print("Wert von pMax = {}".format(odd_primes[MAX_PRIME]))
    exponents = get_primes_range(odd_primes, START_EXPONENT, END_EXPONENT)
    for exponent in exponents.tolist():
        start_time = time.time()
        factor_primes = get_factor_primes(exponent, odd_primes)
        factors = []
        for prime in factor_primes.tolist():
            if pow(2, exponent, prime) == 1 and isprime(prime):
                factors.append(prime)
        end_time = time.time()
        print("Habe für M{} {:.2f} Sekunden gebraucht. ({} Faktoren gefunden: {})".format(exponent, end_time - start_time, len(factors), factors))

if __name__ == '__main__':
    main()
Das einzig langsame an diesem Code ist `pow(2, exponent, prime)` und das bekommst Du mit einer Graphikkarte nicht schneller.
Karl-Heinz Hofmann
User
Beiträge: 20
Registriert: Dienstag 12. November 2019, 15:34

Wow, wow, wow, da hast du dir aber Arbeit gemacht, Sirius3. Vielen lieben Dank. Ja, mein Programierstil ist lausig, ich weiß.
Ich habe mal spaßeshalber die Siebliste von 1000 auf 20000 Primzahlen hochgeschraubt. Das `pow(2, exponent, prime)`
ändert sich dadurch von 11 sek. auf 9,5 sek.(bei Sieb im Interval von 2^57 zu 2^58) Extremes Sieben bringt also nur wenig.
Der Bottleneck ist wirklich bei dieser Funktion. Wenn ich eine Funktion wüsste, die mir "möglicher Faktor" oder " gar nicht
möglicher Faktor" liefert und schneller ist, dann ginge noch was. Auch wäre es möglich bei meinem Programm, immer wenn
Class == True ist, ein Multiprocessing Modul aufzurufen.
Die "kontrolle" habe ich beim konstruieren mal an verschiedenen Stellen aufgerufen, daß ich sehen kann, daß ich beim Siebbau
keine Fehler gemacht habe. Jo, ich muß noch viel lernen. Danke, danke Kalli
Antworten