aktelle Werte in einer while schleife ausgeben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

Code: Alles auswählen

from mpmath import mp
import time

mp.dps = 1000000
euler = 1
x = 1
n = 1
i = 0

zeit1 = (time.strftime("%d.%m.%Y %H:%M:%S:%MS"))
test = time.clock()
while n < 200000:
    x = mp.fmul(x,n)
    euler = euler + mp.fdiv(1,x)
    n = n + 1  
    
    if time.clock() - test  > 1800:
        
        f = open("tmp.txt","w")
        f.truncate()
        f.write(str(euler))
        f.close()
        test = time.clock()


print(euler)
euler2 = euler + mp.fdiv(1,x*n)
print(euler2)

zeit2 =(time.strftime("%d.%m.%Y %H:%M:%S:%MS")) 

eulerdiv = 0
eulerdiv = mp.fsub(euler2,euler)
print(eulerdiv)

if eulerdiv > 0:
    while eulerdiv < 0.1:
        eulerdiv = eulerdiv * 10
        i += 1
    print(i)
    
    
zeit2 =(time.strftime("%d.%m.%Y %H:%M:%S:%MS"))    
print(zeit1)
print(zeit2)
was sagt ihr dazu ?
Zuletzt geändert von cofi am Mittwoch 8. Oktober 2014, 15:05, insgesamt 1-mal geändert.
Grund: Python Tags ergaenzt
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

@plotxy: warum die while-Schleife? Wenn Du feste Grenzen hast, dann nimm doch for.
Wenn Du Dateien mit 'w' öffnest, werden die automatisch auf 0 Bytes gestaucht, ein truncate ist überflüssig. Öffne Dateien mit dem with-Statement.
Hab mpmath noch nie benutzt, sieht aber ziemlich unpythonisch aus und scheint auch noch lahm zu sein, wenn Du tatsächlich mit dem Code mehr als 15 Minuten Rechenzeit hast, weil ich die mit dem quasi gleichen Algorithmus erreicht habe.
Zum Berechnen der Genauigkeit hilft Dir vielleicht der 10er Logarithmus.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

Welche bibliothek hast du denn genommen, um die entsprechende genauigkeit zu erreichen ?
BlackJack

@plotxy: ``f.truncate()`` ist überflüssig. Dateien sollte man zusammen mit der ``with``-Anweisung öffnen. Die ``while``-Schleife sollte wohl eigentlich eine ``for``-Schleife sein.

Namen sollte man erst definieren wenn man sie auch braucht und nicht alle am Anfang. Das `i` hatte mich zum Beispiel erst ein wenig verwirrt weil das erst sehr viel weiter unten auch tatsächlich verwendet wird.

`test` ist kein guter Namen für den Wert.

Funktionen machen den Quelltext nicht nur übersichtlicher sondern auch geringfügig schneller weil lokale Namen schneller aufgelöst werden als welche auf Modulebene.

Muss man `mpmath` tatsächlich als Funktionen verwenden? Sind das keine eigenen Typen mit überladenen Operatoren? Ich würde wahrscheinlich auch deutlich mehr mit Generatoren arbeiten.

Die Klammern um den Wert bei `zeit2` sind überflüssig. Die Zuweisung von 0 an `eulerdiv` ebenfalls, sowie die erste Zuweisung an `zeit2` die überhaupt nicht verwendet wird. Ausserdem sollte das wohl `eulerdiff` heissen!?

Eventuell gibt es eine schnellere Methode um an die Zehnerpotenz zu kommen als die Zahl tatsächlich wiederholt mit 10 zu multiplizieren!?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich würde mal behaupten, dass das einfach viel zu viele Divisionen sind. Dadurch verlierst du die ganze Performance von Integern. Hier mal mein Ansatz:

Code: Alles auswählen

import decimal
import sys
import time


def euler_fraction(N):
    numerator = denominator = 1
    
    for i in xrange(1, N):
        numerator = i*numerator + 1
        denominator *= i
    
    return numerator, denominator


def main():
    N = 205211
    PRECISION = 1000000
    
    filename = sys.argv[1]
    
    start = time.time()
    numerator, denominator = map(decimal.Decimal, euler_fraction(N))
    
    decimal.getcontext().prec = PRECISION
    with open(filename, "w") as fp:
        fp.write(str(numerator/denominator))
    
    end = time.time()
    
    print "total:", end - start, "seconds"
    

if __name__ == "__main__":
    main()
Das Leben ist wie ein Tennisball.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

Ich habe mal deinen Ansatz genommen und ein wenig umgeschrieben. Er schaffte es in 8 sec stat 42.
also lag es bei mir wirklich am zu komplizierten code. Danke für die hilfe.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nicht ganz so schnell wie Mathematica, aber die C++-Lösung braucht bei mir keine 20 Sekunden:

Code: Alles auswählen

#include <iostream>
#include <fstream>

#include <boost/multiprecision/gmp.hpp>


typedef boost::multiprecision::mpf_float Float;
typedef boost::multiprecision::mpz_int Int;
typedef boost::multiprecision::mpq_rational Rational;


Rational euler_fraction(
    const unsigned int n)
{
    Int numerator = 1;
    Int denominator = 1;
    
    for(unsigned int i=1; i<n; ++i) {
        numerator = numerator*i + 1;
        denominator *= i;
    }
    
    return Rational(numerator, denominator);
}


int main(
    int argc,
    char **argv)
{
    static const unsigned int PRECISION = 1000000;
    static const unsigned int N = 205211;
    
    Float::default_precision(PRECISION);
    
    std::ofstream stream(argv[1]);
    stream.precision(PRECISION);
    stream << Float(euler_fraction(N));
    stream.close();
    
    return 0;
}
Das Leben ist wie ein Tennisball.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

@EyDu gibt es eine möglichkeit numerator und denuminator parallel auszurechnen und dann anschließend zu subtrahieren ?
somit würde man nur die hälfte der rechenzeit brauchen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja, du könntest das multiprocessing-Modul verwenden. Damit wird es noch etwas schneller. Es werden bei mir aus fast genau vier Minuten knapp unter drei. Allerdings solltest du mal genauer nachschauen, was nun tatsächlich welchen Anteil an Zeit frisst. Das umwandeln in Decimal und die Division machen sicher einen riesen Batzen aus.

Code: Alles auswählen

import multiprocessing as mp
import operator

def calculate_numerator(N, result):
    numerator = 1
    
    for i in xrange(1, N):
        numerator = i*numerator + 1
    
    result.put(numerator)


def calculate_numerator2(N, result):
    result.put(reduce(operator.mul, xrange(1, N)))


def calculate_denominator(N, result):
    denominator = 1
    
    for i in xrange(1, N):
        denominator *= i
    
    result.put(denominator)


def calculate_denominator2(N, result):
    result.put(math.factorial(N))


def euler_parallel(N):
    numerator = mp.Queue()
    denominator = mp.Queue()
    
    pn = mp.Process(target=calculate_numerator2, args=(N, numerator))
    pd = mp.Process(target=calculate_denominator2, args=(N, denominator))
    
    pn.start()
    pd.start()
    
    return numerator.get(), denominator.get()
Das Leben ist wie ein Tennisball.
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

Meine Variante, die gleich von großen Zahlen nach kleinen rechnet, spart sich die zweite Multiplikation gleich. Aber einen großen Teil der Zeit verschlingt die abschließende Division.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

Code: Alles auswählen

from mpmath import mp
from math import log10, factorial
import time
from multiprocessing import Process, Queue

  
def get_p(n, queue):
    print("get_p ...")
    p = 1
    for i in range(1, n+1):
        p = i*p + 1
    queue.put(p)
    print("get_p done!")
     
def get_q(n, queue):
    print("get_q ...")
    q = factorial(n)
    queue.put(q)
    print("get_q done!")
  
def get_p_q_multiprocess(n):
    p_queue = Queue()
    q_queue = Queue()

    p_process = Process(target=get_p, args=(n, p_queue))
    q_process = Process(target=get_q, args=(n, q_queue))

    p_process.start()
    q_process.start()

    q = q_queue.get()
    p = p_queue.get()

    q_process.join()
    p_process.join()
    
    return p, q
    
def main():
    
    n = 1*10**4
    
    t1 = time.time()
    p, q = get_p_q_multiprocess(n)
    t2 = time.time()
    
    print("calc p and q in"(t2-t1))

    p_mag_10 = int(log10(p))+1
    prec = p_mag_10
    print("precicion:", prec)
    

    mp.dps = prec + 10
    
    time3 = time.time()
    euler = mp.fdiv(p, q)
    time4 = time.time()
    print(time4 - time3)


    s = str(euler)[:prec+1]
    print(s[3])    

main()
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

@EyDu wenn ich den prozess starte passiert nichts. der prozess ist zwar unter taksmaneger zu finden. Doch nur mit einer auslastung von max 00.03. woran liegt das ? bei meinem bruder funktioniert es auch.
BlackJack

@plotxy: Das Modul mit dem das Programm gestartet wird muss zumindest unter Windows importiert werden können ohne das dabei irgendwas ”passiert”. Sonst funktioniert `multiprocessing` nicht. Du musst den `main()`-Aufruf also mit einem ``if __name__ == '__main__':`` schützen.
plotxy
User
Beiträge: 20
Registriert: Dienstag 7. Oktober 2014, 18:04

@EyDu viel dank! jetzt läuft es echt schön. (:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hmm, das habe ich jetzt schnell hingehackt aber von der Performance ist der Code recht unterirdisch :?

Code: Alles auswählen

let one = Gmp.F.from_int 1
let prec = 1_000_000
let fmul = Gmp.F.mul_prec_ui ~prec
let fdiv = Gmp.F.div_prec ~prec
let fadd = Gmp.F.add_prec ~prec
let to_string = Gmp.F.to_string_base_digits ~base:10 ~digits:1000

let f () =
  let x = ref one in
  let euler = ref one in
  for n = 1 to 205_211 do
    x := fmul !x n;
    euler := fadd !euler @@ fdiv one !x;
  done;
  print_endline @@ to_string !euler

let _ =
  f ()
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Sirius3
User
Beiträge: 18266
Registriert: Sonntag 21. Oktober 2012, 17:20

@Leonidas: warum gehst Du nur bis 20000! ?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Sirius3 hat geschrieben:@Leonidas: warum gehst Du nur bis 20000! ?
Versehen, hab das von hier übernommen und eine Null übersehen. In dem Fall ist die Performance noch viel schlimmer, was ja eigentlich gar nicht sein kann. Frag mich ob das Gmp-Binding so unterirdisch ist oder mein Code. Vielleicht mal Profiler anwerfen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich tippe mal auf deinen Code ;-) Die Berechnung mit Floats sollte eine Ecke langsamer sein als mit Integern und die ganzen rechenintensiven Divisionen ziehen das ganze wahrscheinlich so richtig runter. Es reicht eine Division ganz am Ende. Hinzu kommt dann noch das Problem der Genauigkeit. Du rechnest zwar mit einer Millionen Stellen Genauigkeit pro Operation, das garantiert aber keine korrekten eine Millionen Stellen im Endergebnis.
Das Leben ist wie ein Tennisball.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

In 20 Sekunden kann man sich ja nicht mal mehr einen Kaffee holen :-(

Code: Alles auswählen

#include <iostream>
#include <fstream>
#include <thread>

#include <boost/multiprecision/gmp.hpp>


typedef boost::multiprecision::mpf_float Float;
typedef boost::multiprecision::mpz_int Int;
typedef boost::multiprecision::mpq_rational Rational;


void numerator_thread(
    const unsigned int n,
    Int & numerator)
{
    numerator = 1;
    
    for(unsigned int i=1; i<n; ++i) {
        numerator = numerator*i + 1;
    }
}


void denominator_thread(
    const unsigned int n,
    Int & denominator)
{
    denominator = 1;
    
    for(unsigned int i=1; i<n; ++i) {
        denominator *= i;
    }
}


Rational euler_parallel(
    const unsigned int n)
{
    Int numerator = 1;
    Int denominator = 1;
    
    std::thread nt(&numerator_thread, n, std::ref(numerator));
    std::thread dt(&denominator_thread, n, std::ref(denominator));
    
    nt.join();
    dt.join();
    
    return Rational(numerator, denominator);
}


int main(
    int argc,
    char **argv)
{
    static const unsigned int PRECISION = 1000000;
    static const unsigned int N = 205211;
    
    Float::default_precision(PRECISION);
    
    std::ofstream stream(argv[1]);
    stream.precision(PRECISION);
    stream << Float(euler_parallel(N));
    stream.close();
    
    return 0;
}
Das Leben ist wie ein Tennisball.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

EyDu hat geschrieben:Ich tippe mal auf deinen Code ;-)
Da hast du durchaus recht, das war aber auch eine runde missverstehen dabei. Hatte den Eindruck dass

Code: Alles auswählen

from mpmath import mp

mp.dps = 1000000
euler = 1
x = 1
n = 1

while n < 205211:
    x = mp.fmul(x,n)
    euler = euler + mp.fdiv(1,x)
    n = n + 1

print(euler)
in 40 Sekunden abläuft.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten