Berechnung der Eulerschen Zahl

Code-Stücke können hier veröffentlicht werden.
Antworten
lmn1
User
Beiträge: 2
Registriert: Mittwoch 15. November 2023, 16:47

Code: Alles auswählen

def ezahl():
    Gesamtzahl = 2
    o = 2
    o2 = 2
    o3 = 2
    z = 0
    d = 0
    Genauigkeit = 0
    while True:
        Genauigkeit = input('Bitte gebe hier an wie genau die Zahl berechnet werden soll: ')
        try:
            int(Genauigkeit)
        except:
            print('Bitte gebe nur eine Zahl ein!')
        else:
            print('Berechne...')
            break
    Genauigkeit2 = int(Genauigkeit)
    while Genauigkeit2 >= 0:
        n = o2
        fact = 1
        for i in range(1,n+1): 
            o = o * i 
        o3 = o
        z = 1 / o3
        Gesamtzahl += z
        Genauigkeit2 -= 1
    print('Das Programm ist auf das Ergebnis',Gesamtzahl,' gekommen.')
    ezahl()
ezahl()
Ich habe versucht ein Programm zu machen das die Eulersche Zahl generiert. Ich habe es auch geschafft aber habe nun ein Problem: Wenn ich die Genauigkeit auf zum Beispiel auf 100 oder größer stelle dann fängt Python an zu runden also es kommt dann plötzlich 2,5 raus.
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der eingebaute Zahldatentyp hier ist ein double, also eine 64 Bit Fliesskommazahl nach IEEE754. Die hat "nur" 68 oder so Stellen Genauigkeit (kann auch anders sein, aber beschraenkt ist sie auf jeden Fall). Den Algorithmus habe ich mir jetzt nicht angeschaut, aber daran kann es gut liegen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: das sind 15 Dezimalstellen.

@lmn1: Funktionen sollten nach Tätigkeiten benannt sein und keine Abkürzungen enthalten, also calculate_euler_number.
Nackte Excepts darf man niemals verwenden, in Deinem Fall willst du nur einen ValueError abfangen. So eine Funktion würde aber die Genauigkeit als Parameter erwarten und nicht selbst von der Konsole abfragen.
Variablennamen werden komplett klein geschrieben.
Genauigkeit und Genauigkeit2 unterscheiden sich wie? Was bedeutet die 2?
Man definiert Variablen erst, wenn man sie braucht, und nicht schon 10 Zeilen davor. Dann merkt man auch, welche Variablen man gar nicht braucht.
o3 hat immer den selben Wert wie o ist also überflüssig. o2 hat immer den Wert 2, und damit auch n.
Wenn man eine Schleife will, dann schreibt man eine Schleife und ruft nicht rekursiv die gleiche Funktion immer wieder auf.
Das ganze Programm sieht also ungefähr so aus:

Code: Alles auswählen

def calculate_euler_number(precision):
    result = 2
    while precision >= 0:
        for i in range(1, 3):
            o = o * i 
        z = 1 / o
        result += z
        precision -= 1
    return result

def read_precision():
    while True:
        try:
            return int(input('Bitte gebe hier an wie genau die Zahl berechnet werden soll: '))
        except ValueError:
            print('Bitte gebe nur eine Zahl ein!')

def main():
    precision = read_precision()
    while True:
        print('Berechne...')
        number = calculate_euler_number(precision)
        print(f'Das Programm ist auf das Ergebnis {number} gekommen.')

if __name__ == "__main__":
    main()
Dass die Berechnung nicht ganz stimmen kann, sieht man jetzt viel besser.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Edit: Zu spät, aber nun hab ichs alles geschrieben. :-)

@lmn1: Das die Funktion sich rekursiv aufruft ist falsch. Wenn man etwas wiederholen will, nimmt man eine Schleife, und müllt nicht sinnlos den Aufrufstack mit lokalen Variablen voll, die nie wieder verwendet werden.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassennamen (PascalCase).

Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. Oder irgendwelche sinnlos angehängten Zahlen.

Man definiert Namen erst wenn man sie braucht. Nicht alle *und mehr* am Anfang einer Funktion. `d` wird beispielweise nirgends verwendet. Es macht auch keinen Sinn Namen an Werte zu binden die nie irgendwo verwendet werden bevor der Name an einen neuen Wert gebunden wird. Das ``Genauigkeit = 0`` am Anfang ist so ein Beispiel. Wobei der Name danach dann gar nicht an eine Zahl gebunden wird, sondern an eine Zeichenkette. Aber eigentlich sollte es eine Zahl sein, und `Genauigkeit2` sollte es nicht geben.

Nackte ``except:`` ohne konkrete Angabe von Ausnahmen behandeln *alles*. Auch NameError, MemoryError, IOError wenn das Terminal keine Verbindung mehr hat, und alles was einem da sonst noch einfällt, oder eben auch nicht. Hier soll ein `ValueError` behandelt werden.

In einem ``try`` eine Umwandlung in `int` zu machen und das Ergebnis einfach wegzuwerfen um danach dann diese Umwandlung noch mal zu durchzuführen, macht keinen Sinn.

Wenn man vor Eintritt in eine Schleife weiss, wie oft die durchlaufen wird, dann verwendet man eine ``for``-Schleife und keine ``while``-Schleife wo man den Zähler ”manuell” hoch- beziehungsweise in diesem Fall herunterzählt.

`fact` wird nirgends verwendet. `o3` und `z` bekommen vor der Schleife Werte zugewiesen die nirgends verwendet werden. In der Schleife werden Werte teilweise nur an einen anderen Namen nichtssagenden gebunden der einzig in der folgenden Zeile verwendet wird, also kann man da auch gleich den ursprünglichen Namen verwenden. `n` wird in jedem Schleifendurchlauf erneut an den gleichen Wert gebunden und nie verändert.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    while True:
        while True:
            try:
                genauigkeit = int(
                    input(
                        "Bitte gib hier an, wie genau die Zahl berechnet"
                        " werden soll: "
                    )
                )
                break
            except ValueError:
                print("Bitte gebe nur eine Zahl ein!")

        print("Berechne...")
        ergebnis = 2
        n = 2
        for _ in range(genauigkeit):
            for i in range(1, 3):
                n *= i
            ergebnis += 1 / n

        print("Das Programm ist auf das Ergebnis", ergebnis, " gekommen.")


if __name__ == "__main__":
    main()
Wenn man nicht durch die Präzision von `float` begrenzt werden möchte, kann man sich das `decimal`-Modul aus der Standardbibliothek anschauen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

@Sirius3, ich bin mir nicht sicher, ob das Absicht war oder nicht, aber in 'calculate_euler_number' ist ein undefiniertes 'o' und ich glaube es wäre sinnvoller wenn die Schleife in der 'main' die Funktion 'read_precision' einschließen würde. (?) Wenn ich das 'O' mal von Anfang an auf 2 setze, wie im original Code, dann kommt bei dir und @__blackjack__ das gleiche Ergebnis raus:

Code: Alles auswählen

O = 2

def calculate_euler_number(precision, o):
    result = 2
    while precision >= 0:
        for i in range(1, 3):
            o = o * i
        z = 1 / o
        result += z
        precision -= 1
    return result

def read_precision():
    while True:
        try:
            return int(input('Bitte gebe hier an wie genau die Zahl berechnet werden soll: '))
        except ValueError:
            print('Bitte gebe nur eine Zahl ein!')

def main():
    
    precision = read_precision()
    print('Berechne...')
    number = calculate_euler_number(precision, O)
    print(f'Das Programm ist auf das Ergebnis {number} gekommen.')

if __name__ == "__main__":
    main()
Wenn ich wüsste was 'O' wäre, hätte ich mir einen anderen Namen überlegt. :)

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das ist das O aus „O Tannenbaum“.🎄

SCNR. Hier gibt's gerade Weihnachtsgebäck. 🍪
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei den vielen unnötigen Variablen kann auch mal eine benötigte dem Löscheifer zum Opfer fallen.
Ich wollte es eigentlich in die Schleife ziehen, in der Hoffnung, dass was sinnvolleres rauskommt, war aber nicht der Fall, und so viel es ganz weg, oh weh.

@__blackjack__: jo is denn scho weihnachdn?
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Weihnachtsgebäck gibts erst zur Belohnung, nach jeder erfolgreichen gelösten Advent of Code Aufgabe.
Dann brauche ich mir keine Sorgen machen, das ich durch zu viel Gebäck dick werde 🤭

Ich lasse eure Codebeispiele öfters bei mir laufen um mir das ein oder andere ab zu schauen. Am interessantesten ist es, wenn ihr, wie öfters mal, kurz hinter einander antwortet. 👍🏼
"When I got the music, I got a place to go" [Rancid, 1993]
lmn1
User
Beiträge: 2
Registriert: Mittwoch 15. November 2023, 16:47

Also nochmal zu meiner eigentlichen Frage. Also gibt es keine Möglichkeit irgendwie ein Integer zu generieren der mehr als 68 Stellen beinhalten kann?
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Natuerlich kannst du integer mit mehr als 68 Stellen generieren. 10**100 zB schluckt Python problemlos.

Aber du benutzt doch floats. Da geht das nicht.

Stattdessen kannst du decimal.Decimal verwenden, und die gewuenschte Genauigkeit einstellen: https://docs.python.org/3/library/decimal.html
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was ich ja auch schon weiter oben vorgeschlagen hatte. 🤓
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Ansonsten gibt es auch Algorithmen, die e Stelle für Stelle berechnen (https://de.wikipedia.org/wiki/Tr%C3%B6pfelalgorithmus). Z. B. den hier: https://academic.oup.com/comjnl/article/11/2/229/378761

Der war in ein paar Minuten umgesetzt und dezent an das 21 Jahrhundert angepasst und liefert z.B. das folgende Ergebnis (das ich verifiziert habe) augenblicklich:

Code: Alles auswählen

>>> euler(1000)
[2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5, 2, 3, 5, 3, 6, 0, 2, 8, 7, 4, 7, 1, 3, 5, 2, 6, 6, 2, 4, 9, 7, 7, 5, 7, 2, 4, 7, 0, 9, 3, 6, 9, 9, 9, 5, 9, 5, 7, 4, 9, 6, 6, 9, 6, 7, 6, 2, 7, 7, 2, 4, 0, 7, 6, 6, 3, 0, 3, 5, 3, 5, 4, 7, 5, 9, 4, 5, 7, 1, 3, 8, 2, 1, 7, 8, 5, 2, 5, 1, 6, 6, 4, 2, 7, 4, 2, 7, 4, 6, 6, 3, 9, 1, 9, 3, 2, 0, 0, 3, 0, 5, 9, 9, 2, 1, 8, 1, 7, 4, 1, 3, 5, 9, 6, 6, 2, 9, 0, 4, 3, 5, 7, 2, 9, 0, 0, 3, 3, 4, 2, 9, 5, 2, 6, 0, 5, 9, 5, 6, 3, 0, 7, 3, 8, 1, 3, 2, 3, 2, 8, 6, 2, 7, 9, 4, 3, 4, 9, 0, 7, 6, 3, 2, 3, 3, 8, 2, 9, 8, 8, 0, 7, 5, 3, 1, 9, 5, 2, 5, 1, 0, 1, 9, 0, 1, 1, 5, 7, 3, 8, 3, 4, 1, 8, 7, 9, 3, 0, 7, 0, 2, 1, 5, 4, 0, 8, 9, 1, 4, 9, 9, 3, 4, 8, 8, 4, 1, 6, 7, 5, 0, 9, 2, 4, 4, 7, 6, 1, 4, 6, 0, 6, 6, 8, 0, 8, 2, 2, 6, 4, 8, 0, 0, 1, 6, 8, 4, 7, 7, 4, 1, 1, 8, 5, 3, 7, 4, 2, 3, 4, 5, 4, 4, 2, 4, 3, 7, 1, 0, 7, 5, 3, 9, 0, 7, 7, 7, 4, 4, 9, 9, 2, 0, 6, 9, 5, 5, 1, 7, 0, 2, 7, 6, 1, 8, 3, 8, 6, 0, 6, 2, 6, 1, 3, 3, 1, 3, 8, 4, 5, 8, 3, 0, 0, 0, 7, 5, 2, 0, 4, 4, 9, 3, 3, 8, 2, 6, 5, 6, 0, 2, 9, 7, 6, 0, 6, 7, 3, 7, 1, 1, 3, 2, 0, 0, 7, 0, 9, 3, 2, 8, 7, 0, 9, 1, 2, 7, 4, 4, 3, 7, 4, 7, 0, 4, 7, 2, 3, 0, 6, 9, 6, 9, 7, 7, 2, 0, 9, 3, 1, 0, 1, 4, 1, 6, 9, 2, 8, 3, 6, 8, 1, 9, 0, 2, 5, 5, 1, 5, 1, 0, 8, 6, 5, 7, 4, 6, 3, 7, 7, 2, 1, 1, 1, 2, 5, 2, 3, 8, 9, 7, 8, 4, 4, 2, 5, 0, 5, 6, 9, 5, 3, 6, 9, 6, 7, 7, 0, 7, 8, 5, 4, 4, 9, 9, 6, 9, 9, 6, 7, 9, 4, 6, 8, 6, 4, 4, 5, 4, 9, 0, 5, 9, 8, 7, 9, 3, 1, 6, 3, 6, 8, 8, 9, 2, 3, 0, 0, 9, 8, 7, 9, 3, 1, 2, 7, 7, 3, 6, 1, 7, 8, 2, 1, 5, 4, 2, 4, 9, 9, 9, 2, 2, 9, 5, 7, 6, 3, 5, 1, 4, 8, 2, 2, 0, 8, 2, 6, 9, 8, 9, 5, 1, 9, 3, 6, 6, 8, 0, 3, 3, 1, 8, 2, 5, 2, 8, 8, 6, 9, 3, 9, 8, 4, 9, 6, 4, 6, 5, 1, 0, 5, 8, 2, 0, 9, 3, 9, 2, 3, 9, 8, 2, 9, 4, 8, 8, 7, 9, 3, 3, 2, 0, 3, 6, 2, 5, 0, 9, 4, 4, 3, 1, 1, 7, 3, 0, 1, 2, 3, 8, 1, 9, 7, 0, 6, 8, 4, 1, 6, 1, 4, 0, 3, 9, 7, 0, 1, 9, 8, 3, 7, 6, 7, 9, 3, 2, 0, 6, 8, 3, 2, 8, 2, 3, 7, 6, 4, 6, 4, 8, 0, 4, 2, 9, 5, 3, 1, 1, 8, 0, 2, 3, 2, 8, 7, 8, 2, 5, 0, 9, 8, 1, 9, 4, 5, 5, 8, 1, 5, 3, 0, 1, 7, 5, 6, 7, 1, 7, 3, 6, 1, 3, 3, 2, 0, 6, 9, 8, 1, 1, 2, 5, 0, 9, 9, 6, 1, 8, 1, 8, 8, 1, 5, 9, 3, 0, 4, 1, 6, 9, 0, 3, 5, 1, 5, 9, 8, 8, 8, 8, 5, 1, 9, 3, 4, 5, 8, 0, 7, 2, 7, 3, 8, 6, 6, 7, 3, 8, 5, 8, 9, 4, 2, 2, 8, 7, 9, 2, 2, 8, 4, 9, 9, 8, 9, 2, 0, 8, 6, 8, 0, 5, 8, 2, 5, 7, 4, 9, 2, 7, 9, 6, 1, 0, 4, 8, 4, 1, 9, 8, 4, 4, 4, 3, 6, 3, 4, 6, 3, 2, 4, 4, 9, 6, 8, 4, 8, 7, 5, 6, 0, 2, 3, 3, 6, 2, 4, 8, 2, 7, 0, 4, 1, 9, 7, 8, 6, 2, 3, 2, 0, 9, 0, 0, 2, 1, 6, 0, 9, 9, 0, 2, 3, 5, 3, 0, 4, 3, 6, 9, 9, 4, 1, 8, 4, 9, 1, 4, 6, 3, 1, 4, 0, 9, 3, 4, 3, 1, 7, 3, 8, 1, 4, 3, 6, 4, 0, 5, 4, 6, 2, 5, 3, 1, 5, 2, 0, 9, 6, 1, 8, 3, 6, 9, 0, 8, 8, 8, 7, 0, 7, 0, 1, 6, 7, 6, 8, 3, 9, 6, 4, 2, 4, 3, 7, 8, 1, 4, 0, 5, 9, 2, 7, 1, 4, 5, 6, 3, 5, 4, 9, 0, 6, 1, 3, 0, 3, 1, 0, 7, 2, 0, 8, 5, 1, 0, 3, 8, 3, 7, 5, 0, 5, 1, 0, 1, 1, 5, 7, 4, 7, 7, 0, 4, 1, 7, 1, 8, 9, 8, 6, 1, 0, 6, 8, 7, 3, 9, 6, 9, 6, 5, 5, 2, 1, 2, 6, 7, 1, 5, 4, 6, 8, 8, 9, 5, 7, 0, 3, 5, 0, 3, 5, 4]
Gibt sicher auch noch modernere.
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe den Code aus dem Paper mal in die Mitte der 1980er geholt. Das braucht mindestens TurboPascal Version 2, weil es in 1 `GetMem()` und `FreeMem()` noch nicht gibt.

Code: Alles auswählen

const
  N = 1000;
  MaxIndex = 32000;

type
  TIntegers = Array[0..MaxIndex] of Integer;

var
  d: Array[0..N] of Integer;


procedure ECalculation;
var
  m: Integer;
  test: Real;
  i, j, carry, temp: Integer;
  coefs: ^TIntegers;
begin
  m := 4;
  test := (N + 1) * 2.30258509;
  repeat
    m := m + 1;
  until m * (Ln(m) - 1.0) + 0.5 * Ln(6.2831852 * m) > test;

  if m > MaxIndex then
    begin
      WriteLn('Too many coefs.');
      Halt;
    end
  else
    begin
      WriteLn('m = ', m);
    end;

  GetMem(coefs, SizeOf(Integer) * m);

  for j := 2 to m do coefs^[j] := 1;
  d[0] := 2;
  for i := 1 to N do
    begin
      carry := 0;
      for j := m downto 2 do
        begin
          temp := coefs^[j] * 10 + carry;
          carry := temp DIV j;
          coefs^[j] := temp - carry * j
        end;
      d[i] := carry
    end;

  FreeMem(coefs, SizeOf(Integer) * m);
end;

procedure PrintResult;
var
  i: Integer;
begin
  for i := 0 to N do Write(d[i]);
  WriteLn;
end;

begin
  ECalculation;
  PrintResult;
end.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Und hier eine Portierung für den VIC-20 die in nur 22 Minuten 350 Stellen berechnet. Es wären wohl noch ein paar mehr drin, weil immer noch 365 Bytes RAM frei sind, aber es war halt so eine schöne runde Zahl.

Code: Alles auswählen

   10 REM CALCULATE
   20 REM N DIGITS OF E
   30 TI$="000000"
   40 N=350:DIM D(N)
   50 REM DETERMINE
   60 REM NUMBER OF COEFS
   70 M=4:T=(N+1)*2.30258509
   80 M=M+1
   90 IF M*(LOG(M)-1)+.5*LOG(6.2831852*M)<=T THEN 80
  100 PRINT"M=";M
  200 REM CALCULATE DIGITS
  210 DIM CO(M)
  220 FOR J=2 TO M:CO(J)=1:NEXT
  230 D(0)=2
  240 FOR I=1 TO N:C=0
  250 FOR J=M TO 2 STEP -1
  260 T=CO(J)*10+C
  270 C=INT(T/J)
  280 CO(J)=T-C*J
  290 NEXT:D(I)=C:NEXT
  500 REM PRINT RESULT
  510 PRINT"2.";
  520 FOR I=1 TO N
  530 PRINT MID$(STR$(D(I)),2);
  540 NEXT
  550 PRINT:PRINT TI$
Die 1000 Stellen sollten auch möglich sein, wenn man die nicht speichert, sondern gleich ausgibt. Am besten auf einen Drucker, denn es passen ja nur 506 Zeichen auf den Bildschirm. Mal schauen ob ich das noch ausprobiere. Die Rechenzeit steigt ja quadratisch. Da wird der Rechner Stunden mit beschäftigt sein. 🤔
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Aaalso, 1000 Stellen direkt gedruckt statt gespeichert sind möglich (bei immer noch 850 Bytes freiem Speicher) und es dauert nur 2½ Stunden. 😎
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

__blackjack__ hat geschrieben: Dienstag 21. November 2023, 00:27 Ich habe den Code aus dem Paper mal in die Mitte der 1980er geholt.
Deinen Pascal Quellcode zum Laufen zu bekommen hat mich aber auch im Jahr 2023 keine 2 Minuten gekostet, ohne jegliche Anpassungen. Und Pascal ist ja vom Erscheinungsbild usw. noch recht nah an Algol dran, sodass man eine relativ originalgetreue Portierung machen kann. Einen Algol60 Interpreter/Compiler, der ähnlich leicht zugänglich und ausgereift ist wie Free Pascal um den Originalcode auszuführen, muss man hingegen erst einmal finden. Insofern finde ich, dass Pascal ein guter Kompromiss ist.
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

nezzcarth hat geschrieben: Freitag 24. November 2023, 18:53 Einen Algol60 Interpreter/Compiler, der ähnlich leicht zugänglich und ausgereift ist wie Free Pascal um den Originalcode auszuführen, muss man hingegen erst einmal finden.
Ich habe den Code aus dem Paper einfach mal mit Racket ausprobiert. Ist zwar eigentlich ein Lisp, aber bekanntlicherweise ist ja jede Programmiersprache Lisp und deswegen kann Racket auch Algol60 ausführen:

Code: Alles auswählen

#lang algol60

begin

procedure ecalculation (n, d);
value n;
integer n;
integer array d;
    begin integer m;
    real test;
    m := 4;
    test := (n + 1) * 2.30258509;
    loop: m := m + 1;
    if m * (ln(m) - 1.0) + 0.5 * ln(6.2831852 * m) <= test then goto loop;
    begin integer i, j, carry, temp;
        integer array coef [2 : m];
        for j := 2 step 1 until m do coef [j] := 1;
        d [0] := 2;
        sweep: for i := 1 step 1 until n do begin
            carry := 0;
            for j := m step -1 until 2 do begin
                temp := coef [j] * 10 + carry;
                carry := temp / j;
                coef[j] := temp - carry * j;
            end;
            d [i] := carry;
        end;
    end;
end;

integer n;
n := 1000;
begin
    integer array d[0:n];
    integer i;
    ecalculation(n, d);
    printn(d[0]);
    prints(`.');
    for i := 1 step 1 until n do begin
        printn(d[i]);
    end;
    printsln(`');
end;
end

Code: Alles auswählen

$ racket e.a60
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354
1000 Stellen dauern bei mir 900ms, aber davon sind 650ms Startup. 10_000 dauern 19 Sekunden.

Zwei Probleme hatte ich: `go to` wird in der Racket-Implementierung `goto` geschrieben und die Kommentare nach `end` sind nicht erlaubt. Ansonsten läuft es aber ohne Änderungen.

Mir gefallen besonders die `' als Anführungszeichen. /s
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Manchmal finde ich es ja schade, dass man von der *ganzen* 8-Bit-Rechner-Vielfalt der 80er nicht so alles mitbekommen hat. Der BBC Micro war in UK ja sehr verbreitet, insbesondere in Schulen, so das viele Kontakt hatten, die privat keinen Rechnern hatten. Der BBC BASIC-Dialekt ist deutlich besser als die Microsoft-BASIC-Dialekte die sonst fast überall drin steckten. Die Einrückung im folgenden Programm ist nicht tatsächlich gespeichert, sondern wird beim auflisten erzeugt. Es gibt eine REPEAT … UNTIL Schleife und ein ELSE zum IF. Integer sind 32 Bit und trotzdem ist es schneller als Microsofts BASICs weil bei ganzen Zahlen tatsächlich *damit* gerechnet wird, statt für Rechnungen immer erst alles ins Gleitkommaformat zu wandeln.

Die 1000 Stellen schafft der BBC Micro (6502 mit 2 Mhz) in 46 Minuten auf den ausreichend grossen Textbildschirm, statt in 2½ Stunden auf einen Drucker wie beim VIC-20 (6502 mit ≈1 Mhz). Die Zeitdifferenz ist nicht komplett mit dem doppelten Prozessortakt erklärt; das ist die bessere BASIC-Implementierung des BBC Micro.

Code: Alles auswählen

   10 MODE 3
   20 start%=TIME:N%=1000
   30 DIM D%(N%)
   40 REM Determine number of coefs
   50 M%=4:test=(N%+1)*2.30258509
   60 REPEAT
   70   M%=M%+1
   80 UNTIL M%*(LN(M%)-1)+.5*LN(6.2831852*M%)>test
   90 PRINT"M%=";M%
  100 REM Calculate digits
  110 DIM coef%(M%)
  120 FOR J%=2 TO M%
  130   coef%(J%)=1
  140 NEXT
  150 D%(0)=2
  160 FOR I%=1 TO N%
  170   carry%=0
  180   FOR J%=M% TO 2 STEP -1
  190     T%=coef%(J%)*10+carry%
  200     carry%=T% DIV J%
  210     coef%(J%)=T%-carry%*J%
  220   NEXT
  230   D%(I%)=carry%
  240   PRINT TAB(1,1);I%
  250 NEXT
  260 REM Print result
  270 FOR I%=0 TO N%
  280   PRINT STR$(D%(I%));
  290 NEXT
  300 PRINT
  310 PRINT"In ";(TIME-start%)/100;" seconds"
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
nezzcarth
User
Beiträge: 1635
Registriert: Samstag 16. April 2011, 12:47

Hier mal als Iterator, der noch recht nah am Original dran ist (abgeglichen bis 1.000.000 Stellen gegen eine externe Referenz):

Code: Alles auswählen

from math import log, tau

def iter_euler(n):
    yield 2
    m = 5
    test = (n + 1) * log(10) 
    while m * (log(m) - 1.0) + 0.5 * log(tau * m) < test:
        m += 1
    coefficients = [0] + [1] * m
    for _ in range(n):
        carry = 0
        for j in range(m, 1, -1):
            temp = coefficients[j] * 10 + carry
            carry = temp // j
            coefficients[j] = temp - carry * j
        yield carry
Den Teil der, der "m" u.a. unter Zuhilfenahme der Stirlingformel abschätzt, kann man theoretisch noch lesbarer machen, aber alles, was ich probiert habe, hat den Code spürbar verlangsamt.
Antworten