Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 2).

Vorheriger Artikel Portierung des Programms "FORTRAN77 Numerical Computing Programming" nach C und Python (Teil 1)

Aus dem Code von FORTRAN77 Numerical Calculation Programming, 1.2.

Anhäufung von Fehlern im Trapezgesetz

Kumulativer Rundungsfehler

Zitiert vom Ende von P.5 bis zur Vorderseite des P.6-Programms

Integration als Beispiel für einen kumulativen Rundungsfehler

I = \int_{0}^{1}\frac{1}{1+x^2}dx = \frac{\pi}{4} = 0.7853982\tag{1.13}


 >, Während die Schrittweite $ h $ schrittweise verringert wird, ** Trapezregel **

>```math
I_h = h\biggr[\frac{1}{2}f(a)+\sum_{j=1}^{n-1}f(a+jh)+\frac{1}{2}f(b)\biggr], \quad  h=\frac{b-a}{n}\tag{1.14}
a=0, \quad b=1, \quad f(x)=\frac{1}{1+x^2} \tag{1.15}

Versuchen Sie die numerische Integration mit>.

Fortran-Code

Ein Programm, das die numerische Integration von (1.14) und (1.15) durchführt.

strap.f


*     Accumulation of round off error
      PROGRAM STRAP
        PARAMETER (ONE = 1.0)
*
        EV = ATAN(ONE)
*
        WRITE (*,2000)
2000    FORMAT (' ---- TRAP ----')
*
        DO 10  K = 1, 13
* 
            N = 2**K
            H = 1.0 / N
*
            S = 0.5 * (1.0 + 0.5)
            DO 20 I = 1, N - 1
                S = S + 1 / (1 + (H * I)**2)
  20        CONTINUE
            S = H * S
*
            ERR = S - EV
            IF (ERR .NE. 0.0) THEN
                ALERR = ALOG10 (ABS(ERR))
            ELSE
                ALERR = -9.9
            END IF
*
            WRITE (*,2001) N, H, S, ERR, ALERR
2001        FORMAT (' N=',I6,'  H=',1PE9.2,'  S=',E13.6,
     $              '  ERR=',E8.1,'  L(ERR)=',0PF4.1)
*
  10    CONTINUE
*
      END

Das Ausführungsergebnis ist

 ---- TRAP ----
 N=     2  H= 5.00E-01  S= 7.750000E-01  ERR=-1.0E-02  L(ERR)=-2.0
 N=     4  H= 2.50E-01  S= 7.827941E-01  ERR=-2.6E-03  L(ERR)=-2.6
 N=     8  H= 1.25E-01  S= 7.847471E-01  ERR=-6.5E-04  L(ERR)=-3.2
 N=    16  H= 6.25E-02  S= 7.852354E-01  ERR=-1.6E-04  L(ERR)=-3.8
 N=    32  H= 3.12E-02  S= 7.853574E-01  ERR=-4.1E-05  L(ERR)=-4.4
 N=    64  H= 1.56E-02  S= 7.853879E-01  ERR=-1.0E-05  L(ERR)=-5.0
 N=   128  H= 7.81E-03  S= 7.853957E-01  ERR=-2.4E-06  L(ERR)=-5.6
 N=   256  H= 3.91E-03  S= 7.853976E-01  ERR=-5.4E-07  L(ERR)=-6.3
 N=   512  H= 1.95E-03  S= 7.853978E-01  ERR=-4.2E-07  L(ERR)=-6.4
 N=  1024  H= 9.77E-04  S= 7.853981E-01  ERR=-6.0E-08  L(ERR)=-7.2
 N=  2048  H= 4.88E-04  S= 7.853982E-01  ERR= 6.0E-08  L(ERR)=-7.2
 N=  4096  H= 2.44E-04  S= 7.853983E-01  ERR= 1.2E-07  L(ERR)=-6.9
 N=  8192  H= 1.22E-04  S= 7.853981E-01  ERR=-6.0E-08  L(ERR)=-7.2

Wird sein. Oh, die Ausgabe von ERR und L (ERR) unterscheidet sich vom Buch von ungefähr $ N = 128 $ ...

Den Code verstehen

Warum heißt dieses Programm überhaupt STRAP? Abgesehen von der Frage, was war die Integration? Lassen Sie uns einen zweiten Blick darauf werfen und überprüfen, was wir in das Buch und den Code schreiben.   In dem Buch wird die Integrationsgleichung durch das Trapezgesetz numerisch integriert. Viele Trapezoide werden in den Bereich des Graphen gestellt, der durch die ursprüngliche Integration dargestellt wird, und die Summe der Flächen der Trapezoide wird in den Integrationsgraphen integriert. Um es eine Annäherung an die Fläche von zu machen.

Das Programm führt also die Formeln (1.14) und (1.15) aus, während $ h $ immer kleiner wird. Das Thema ist, wie sehr es sich von der in (1.13) geforderten Antwort unterscheidet.

Ich habe ein Flussdiagramm gezeichnet. strap_flowchart.png

Zunächst machen wir in * 1 $ arctan 1.0 $, das die inverse Dreiecksfunktion arctangent verwendet. Ausdrücken der Bogentangente als konstantes Integral,

arctan\,x = \int_0^x \frac 1 {z^2 + 1}\,dz

Es wird die Formel. Wenn $ x $ $ 1 $ ist und $ z $ $ x $ ist, entspricht dies der Formel in (1.13), sodass EV hier der gleiche Wert wie (1.13) zugewiesen wird, dh $ I $. ..

Als nächstes wird in * 2 $ 2 $ durch $ 2 ^ K $ ersetzt, und $ N $ ist die Formel (1.14) für $ \ sum_ {j = 1} ^ {n-1} $. Die Anzahl der Bestellungen, die grob gesagt in dem Wert verwendet werden, der allmählich zunimmt. Das hier verwendete $ K $ ist ein Zähler für Schleife 1, und diese Schleife 1 dient dazu, das Fehlerverhalten bis zu 2 bis zur 13. Potenz zu testen.

Und für * 3 wurde dies ursprünglich als $ h = \ frac {ba} {n} $ in (1.14) ausgedrückt, und in (1.15) wurde es zu $$ a = 0, \ quad b = 1 . Wenn Sie es also ersetzen, ist es dasselbe wie $ h = \ frac {1} {n} $$.

Dann ist der erste Ausdruck in (1.14) $ I_h = h \ biggr [\ frac {1} {2} f (a) + \ sum_ {j = 1} ^ {n-1} f (a + jh) ) + \ Frac {1} {2} f (b) \ biggr] Wenn Sie zuerst die zweite Formel anwenden $ h = \ frac {1} {n} $$

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{1}{2}f(a)+\sum_{j=1}^{n-1}f(a+j\frac{1}{n})+\frac{1}{2}f(b)\biggr]

Und wenn Sie (1.15) durch $ a = 0 $ und $ b = 1 $ ersetzen

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{1}{2}f(0)+\sum_{j=1}^{n-1}f(0+\frac{j}{n})+\frac{1}{2}f(1)\biggr]

Und $ f (x) = \ frac {1} {1 + x ^ 2} $, also

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{1}{2}\times\frac{1}{1+0^2}+\sum_{j=1}^{n-1}\frac{1}{1+\big(\frac{j}{n}\big)^2} +\frac{1}{2}\times\frac{1}{1+1^2}\biggr]

Von

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{1}{2}+\sum_{j=1}^{n-1}\frac{n}{1+\frac{j^2}{n^2}}+\frac{1}{4}\biggr]\tag{r1}

des Weiteren

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{1}{2}+\sum_{j=1}^{n-1}\frac{n^2}{n^2+j^2}+\frac{1}{4}\biggr]

damit,

I_\frac{1}{n}=\frac{1}{n}\biggr[\frac{3}{4}+\sum_{j=1}^{n-1}\frac{n^2}{n^2+j^2}\biggr]\tag{r2}

Kann organisiert werden.

Der Zähler I von Schleife 2 ist $$ j , geschrieben in $ \ sum_ {j = 1} ^ {n-1} $$. Es wäre leicht zu verstehen, wenn Sie es J. geben würden.

Und in * 5 wird $ S + 1 \ div (1+ (H \ mal I) ^ 2) $ $ S $ zugewiesen, aber diese Formel lautet $ 1 \ div (1+ (H \) mal I) ^ 2) Wir werden den Teil von $ organisieren. Als allererstes $ 1 \ div1 + {\ big (\ frac {1} {n} \ times j \ big)} ^ 2 $  $\frac{1}{1+{\big(\frac{1}{n}\times j\big)}^2}$   Von $ \ frac {1} {1 + \ frac {j ^ 2} {n ^ 2}} $ und es erscheint in der Formel (r1).

Schleife 2 ist also (1.14)

\frac{1}{2}f(a)+\sum_{j=1}^{n-1}f(a+jh)+\frac{1}{2}f(b)

Es wird derjenige sein, der den Teil von berechnet. In * 6 ist die erste Formel von (1.14) vervollständigt, und in * 7 die Differenz zur Formel von (1.13), dh die Differenz zwischen dem ursprünglich durch die Integralberechnung erhaltenen Berechnungsergebnis und dem Näherungswert unter Verwendung des Trapezgesetzes. Ich rechne.   Wenn in * 8 die in * 7 erhaltene Differenz ungleich 0 ist, wird der Absolutwert der Differenz berechnet ("ABS (ERR)") und der gemeinsame Logarithmus dieses Wertes berechnet ("ALOG10 ()"). .. Der gemeinsame Logarithmus ist der Wert von $, so dass $ x = 10 ^ a $ und in der Formel als $ a = \ log_ {10} x $$ ausgedrückt wird. Mit diesem Wert können Sie ein Diagramm wie folgt zeichnen: graph.png Diese Grafik zeigt, dass der kumulative Fehler proportional zu $ h ^ 2 $ abnimmt, aber nicht abnimmt, wenn sich der Fehler dem Computer Epsilon nähert.

Unterschied zu Büchern

Im Vergleich dazu hat sich der Wert von $ S $ von $ N = 128 $ leicht erhöht. Der Punkt, an dem die Abnahme des kumulativen Fehlers aufhört, ist etwas später. Der in diesem Buch verwendete Computer (darf nicht als Computer geschrieben werden) ist MV4000 AOS / VS, es handelt sich also um ein 16-Bit-Betriebssystem, nicht wahr? Es ähnelt also dem Diagramm, das ich ausgegeben habe. Das Diagramm wurde unter Verwendung der Gleitkommazahl mit doppelter Genauigkeit berechnet, die als Referenz im Buch angegeben ist. Es ist nur ähnlich, aber es ist ein bisschen anders, aber in der Buchumgebung ist Gleitkomma-Arithmetik eine 6-stellige Rundungsarithmetik. Ich denke, dies ist auf das Ergebnis einer Kürzungsoperation auf einem 64-Bit-Betriebssystem zurückzuführen (die Umgebung ist 32-Bit). Bitte lassen Sie mich wissen, wenn Sie ein Experte sind. Nachtrag: Ich habe mir in den Kommentaren wirklich einen Experten (@cure_honey) sagen lassen. Vielen Dank.

C-Code

strap.c


#include <stdio.h>
#include <math.h>

int main(void)
{
    const float ONE = 1.0f;
    float ev = atanf(ONE);
    int k, i;
    int n;
    float h, s, err, alerr;

    printf("%14.7E\n", ev);

    printf("--- TRAP ---\n");

    for(k=1; k<=13; k++)
    {
        n = pow(2,k);
        h = 1.0f / n;
        s = 0.5f * (1.0f + 0.5f);
        
        for(i=1; i<=n-1; i++)
        {
            s = s + 1 / (1+ powf(h*i,2));
        }
        
        s = h * s;
        err = s - ev;

        if(err != 0.0f)
        {
            alerr = log10(fabsf(err));
        }
        else 
        {
            alerr = -9.9f;
        }
        printf("N=%6d H=%9.2E S=%13.6E ERR=%8.1E L(ERR)=%4.1F\n",n, h, s, err, alerr);
    }

    return 0;
}

Das Ausführungsergebnis ändert sich nicht.

Python-Code

strap.py


import numpy as np
import matplotlib.pyplot as plt

ONE = np.array((1.0),dtype=np.float32)
ev = np.arctan(ONE,dtype=np.float32)

h, s, err, alerr = np.array([0.0, 0.0, 0.0, 0.0],dtype=np.float32)

#Zur Berechnung 1.0, 0.5, 0.0, -9.Gleitkommazahl mit einfacher Genauigkeit von 9
tmp = np.array([1.0, 0.5, 0.0, -9.9],dtype=np.float32)

#Liste zum Zeichnen von Grafiken
x = []
y = []

print("--- TRAP ---")

for k in range(13):
    n = np.power(2,k+1)
    h = tmp[0] / n.astype(np.float32)
    s = tmp[1] * (tmp[0] + tmp[1])
    
    for i in range(n-1):
        s = s + tmp[0] / (tmp[0] + np.square(h*(i+1),dtype=np.float32))  
        
    s = s * h
    err = s - ev

    if err != tmp[2]:
        alerr = np.log10(np.abs(err))
    else:
        alerr = tmp[3]

    print("N=%6d H=%9.2E S=%13.6E ERR=%8.1E L(ERR)=%4.1F" % (n, h, s, err, alerr))
    
    #Variablensatz für Grafik
    x.append(k+1)
    y.append(alerr)

#Diagrammzeichnung
fig, ax = plt.subplots()
ax.scatter(x,y)
ax.set_xlabel("n (1/2^n)")
ax.set_ylabel("l (10^l)")
plt.show()

Das Ausgabeergebnis ist das gleiche. Außerdem habe ich eine Grafik erstellt. graph1.png

Zusammenfassung

Ich denke, dass der Python-Code sauberer sein wird. Und ich denke, es ist eine gute Idee, Numpy zu streuen, um es einfach zu machen. Möchten Sie die Genauigkeit des Fortran-Codes verdoppeln ... Nein, aber dann können die Ausführungsergebnisse nicht mit dem Buch verglichen werden. Muu.

Recommended Posts

Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 3).
Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 2).
Versuchen Sie, das Programmier-Herausforderungsbuch mit Python3 zu lösen
[Einführung in Python] Ich habe die Namenskonventionen von C # und Python verglichen.
Schreiben Sie ein Programm, das das Programm missbraucht und 100 E-Mails sendet
Der Versuch, Segmentbäume Schritt für Schritt zu implementieren und zu verstehen (Python)
Setzen Sie Cabocha 0.68 in Windows ein und versuchen Sie, die Abhängigkeit mit Python zu analysieren
C-Sprache zum Anzeigen und Erinnern Teil 2 Rufen Sie die C-Sprache aus der Python-Zeichenfolge (Argument) auf
Portieren und Ändern des Doublet-Solvers von Python2 auf Python3.
Versuchen Sie, Python-Code zu schreiben, um Go-Code zu generieren. - Versuchen Sie, JSON-to-Go usw. zu portieren
Python Amateur versucht die Liste zusammenzufassen ①
C-Sprache zum Anzeigen und Erinnern Teil 4 Rufen Sie die C-Sprache von Python (Argument) double auf
C-Sprache zum Anzeigen und Erinnern Teil 5 Rufen Sie die C-Sprache aus dem Python-Array (Argument) auf
C-Sprache zum Sehen und Erinnern Teil 3 Rufen Sie die C-Sprache aus Python auf (Argument) c = a + b
Verwendung der C-Bibliothek in Python
So generieren Sie eine Sequenz in Python und C ++
Versuchen Sie, das Problem der Python-Klassenvererbung zu lösen
Versuchen Sie, das Mensch-Maschine-Diagramm mit Python zu lösen
Versuchen Sie es mit dem Python-Webframework Tornado Part 1
Versuchen Sie es mit dem Python-Webframework Tornado Part 2
"Cython" -Tutorial, um Python explosiv zu machen: Übergeben Sie das C ++ - Klassenobjekt an das Klassenobjekt auf der Python-Seite. Teil 2
Die Geschichte der Portierung von Code von C nach Go (und zur Sprachspezifikation)
Überlegen Sie, wie Sie Python auf Ihrem iPad programmieren können
Versuchen Sie, ein Python-Modul in C-Sprache zu erstellen
[Python] Versuchen Sie, die coole Antwort auf das FizzBuzz-Problem zu lesen
Versuchen Sie, das Problem der Zuweisung von Schulungsärzten mit Python zu lösen
Probieren Sie die DB-Operation mit Python aus und visualisieren Sie sie mit d3
Versuchen Sie, Python mit pybind11 in ein C ++ - Programm einzubetten
Tipps und Vorsichtsmaßnahmen beim Portieren von MATLAB-Programmen nach Python
Python Gibt die Funktion an, die ausgeführt werden soll, wenn das Programm endet
Ich hatte das Gefühl, dass ich den Python-Code nach C ++ 98 portiert habe.
Wie man Python auf Android genießt !! Programmieren für unterwegs !!
Gehen Sie in die Sprache, um Teil 7 C in der Sprache GO zu sehen und sich daran zu erinnern
[C / C ++] Übergeben Sie den in C / C ++ berechneten Wert an eine Python-Funktion, um den Prozess auszuführen, und verwenden Sie diesen Wert in C / C ++.
"Cython" -Tutorial, um Python explosiv zu machen: Übergeben Sie ein C ++ - Klassenobjekt an ein Klassenobjekt auf der Python-Seite. Teil ①
Versuchen Sie, in die Datenbank zu importieren, indem Sie ShapeFile mit numerischen Informationen zum nationalen Land mit Python bearbeiten
Eine Geschichte über die Portierung des Codes "Versuchen Sie zu verstehen, wie Linux funktioniert" nach Rust
[Python] Ein Programm, um die Anzahl der Äpfel und Orangen zu ermitteln, die geerntet werden können
[Einführung in cx_Oracle] (Teil 6) Zuordnung von DB- und Python-Datentypen
Versuchen Sie es mit GUI, PyQt in Python
Versuchen Sie, mit Python schnell und einfach auf die Twitter-API zuzugreifen
Versuchen Sie, die Funktionsliste des Python> os-Pakets abzurufen
Ich wollte den Panasonic Programming Contest 2020 mit Python lösen
Versuchen Sie, über XML RPC eine Verbindung zu Supervisord herzustellen, um das Programm zu starten / zu stoppen
Lassen Sie uns das Ausführungsergebnis des Programms mit C ++, Java, Python messen.
[Teil 2] Crawlen mit Python! Klicken Sie auf die Webseite, um sich zu bewegen!
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Versuchen Sie, ein Unterfenster mit PyQt5 und Python zu öffnen
Erstellen Sie eine Python-Umgebung und übertragen Sie Daten auf den Server
Ich habe versucht, den Chi-Quadrat-Test in Python und Java zu programmieren.
Versuchen Sie, den Betrieb von Netzwerkgeräten mit Python zu automatisieren
Lösen mit Ruby und Python AtCoder ABC011 C Dynamische Planungsmethode
Ich möchte die Natur von Python und Pip kennenlernen
Ich habe versucht, die Unterschiede zwischen Java und Python aufzuzählen
Objektorientiert in C-Sprache: "○ ✕ game" wurde überarbeitet und nach Python portiert
Programm zur Beurteilung, ob es nach dem westlichen Kalender ein ruhiges Jahr ist [Python]
Versuchen Sie einfach, einen Webhook mit ngrok und Python zu erhalten
Versuchen Sie, die verstümmelten Zeichen im angehängten Dateinamen mit Python zu entschlüsseln
Gehen Sie zur Sprache, um Teil 8 zu sehen und sich daran zu erinnern. Rufen Sie die GO-Sprache von Python aus auf
Übergeben Sie die OpenCV-Daten der ursprünglichen C ++ - Bibliothek an Python
Lesen Sie das alte Gakushin DC-Antragsformular Word-Datei (.doc) von Python und versuchen Sie, es zu bedienen