Essayez de porter le programme "FORTRAN77 Numerical Computing Programming" vers C et Python (partie 2)

Article précédent Portage du programme "FORTRAN77 Numerical Computing Programming" vers C et Python (Partie 1)

De Programmation de calcul numérique FORTRAN77, code 1.2.

Accumulation d'erreurs en loi trapézoïdale

Erreur d'arrondi cumulative

Cité de la fin de P.5 au début du programme P.6

Intégration comme exemple d'erreur d'arrondi cumulée

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


 >, Tout en réduisant progressivement la largeur du pas $ h $, ** règle trapézoïdale **

>```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}

Essayez l'intégration numérique avec>.

Code Fortran

Un programme qui effectue l'intégration numérique de (1.14) et (1.15).

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

Le résultat de l'exécution est

 ---- 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

Sera. Oh, la sortie de ERR et L (ERR) est différente du livre d'environ $ N = 128 $ ...

Comprendre le code

Pourquoi le nom de ce programme STRAP en premier lieu? Mis à part la question, quelle a été l'intégration? Jetons un second regard et vérifions ce que nous écrivons dans le livre et le code.   Dans le livre, l'équation d'intégration est numériquement intégrée par la loi trapézoïdale. De nombreux trapèzes sont placés dans la zone du graphe représentée par l'intégration d'origine, et la somme des aires des trapèzes est intégrée dans le graphe d'intégration. Pour en faire une approximation de la superficie de.

Donc, ce que fait le programme est d'exécuter les formules (1.14) et (1.15) tout en rendant $ h $ de plus en plus petit. Le thème est combien il diffère de la réponse requise dans (1.13).

J'ai dessiné un organigramme. strap_flowchart.png

Tout d'abord, ce que nous faisons dans * 1 est $ arctan 1.0 $, qui utilise la fonction triangulaire inverse arctangente. Exprimer l'arc tangent comme une intégrale constante,

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

Cela devient la formule. Si $ x $ est $ 1 $ et $ z $ est $ x $, ce sera la même chose que la formule dans (1.13), donc la même valeur que (1.13), c'est-à-dire que $ I $ sera affecté à EV ici. ..

Ensuite, dans * 2, $ 2 ^ K $ est remplacé par $ N $, et $ N $ est la formule (1.14) de $ \ sum_ {j = 1} ^ {n-1} $. Le nombre de commandes utilisées dans, en gros, la valeur qui augmente progressivement. Le $ K $ utilisé ici est un compteur de boucle 1, et cette boucle 1 consiste à essayer le comportement d'erreur jusqu'à 2 à la 13e puissance.

Et pour * 3, cela a été initialement exprimé par $ h = \ frac {ba} {n} $ dans (1.14), et dans (1.15) il est devenu $$ a = 0, \ quad b = 1 . Donc, si vous le remplacez, c'est la même chose que $ h = \ frac {1} {n} $$.

Ensuite, la première expression dans (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] Si vous appliquez d'abord la deuxième formule $ 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]

Et si vous remplacez (1.15) par $ a = 0 $ et $ b = 1 $

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]

Et $ f (x) = \ frac {1} {1 + x ^ 2} $, donc

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]

De

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}

plus loin

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]

alors,

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}

Peut être organisé.

Le compteur I de la boucle 2 est $$ j $ écrit en $ \ sum_ {j = 1} ^ {n-1} $. Ce serait facile à comprendre si vous le donniez à J.

Et dans * 5, $ S + 1 \ div (1+ (H \ times I) ^ 2) $ est assigné à $ S , mais cette formule est $ 1 \ div (1+ (H ) fois I) ^ 2) Nous organiserons la partie de $. Tout d'abord $ 1 \ div1 + {\ big (\ frac {1} {n} \ times j \ big)} ^ 2 $  $\frac{1}{1+{\big(\frac{1}{n}\times j\big)}^2}$   De $ \ frac {1} {1 + \ frac {j ^ 2} {n ^ 2}} $$ et il apparaît dans la formule (r1).

Donc, la boucle 2 est (1.14)

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

Ce sera celui qui calcule la part de. En * 6, la première équation de (1.14) est complétée, et en * 7, la différence avec l'équation de (1.13), c'est-à-dire la différence entre le résultat du calcul obtenu à l'origine par le calcul intégral et la valeur approximative utilisant la loi trapézoïdale. Je calcule.   En * 8, lorsque la différence obtenue en * 7 n'est pas égale à 0, la valeur absolue de la différence est calculée (ʻABS (ERR) ), et la valeur logarithmique commune de cette valeur est calculée (ʻALOG10 ()). .. Le logarithme courant est la valeur de $ telle que $ x = 10 ^ a $, qui est exprimée par $ a = \ log_ {10} x $$ dans la formule. Vous pouvez utiliser cette valeur pour tracer un graphique comme celui-ci: graph.png Ce graphique montre que l'erreur cumulée diminue proportionnellement à $ h ^ 2 $, mais elle ne diminue pas à mesure que l'erreur s'approche de l'ordinateur d'Epsilon.

Différence avec les livres

Par comparaison, la valeur de $ S $ a légèrement augmenté de $ N = 128 $. Le point où la diminution de l'erreur cumulée s'arrête est un peu plus tard. L'ordinateur utilisé dans le livre (n'ose pas être écrit comme ordinateur) est MV4000 AOS / VS, donc c'est un système d'exploitation 16 bits, n'est-ce pas? Donc, c'est similaire au graphique que j'ai publié, le graphique calculé en utilisant le nombre à virgule flottante double précision qui est donné comme référence dans le livre. C'est juste similaire, mais c'est un peu différent, mais dans l'environnement du livre, l'arithmétique en virgule flottante est une arithmétique d'arrondi à 6 chiffres. Donc, je suppose que cela est dû au résultat d'une opération de troncature sur un système d'exploitation 64 bits (l'environnement est 32 bits). Veuillez me faire savoir si vous êtes un expert. Postscript: J'ai vraiment eu un expert (@cure_honey) me le dire dans les commentaires. Merci beaucoup.

Code C

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;
}

Le résultat de l'exécution ne change pas.

Code Python

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)

#Pour le calcul 1.0, 0.5, 0.0, -9.Nombre à virgule flottante simple précision de 9
tmp = np.array([1.0, 0.5, 0.0, -9.9],dtype=np.float32)

#Liste pour dessiner des graphiques
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))
    
    #Jeu de variables pour le graphique
    x.append(k+1)
    y.append(alerr)

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

Le résultat de sortie est le même. Aussi, j'ai mis un graphique. graph1.png

Résumé

Je pense que le code Python va être plus propre. Et je pense que c'est une bonne idée de disperser numpy pour faire simple. Voulez-vous doubler la précision du code Fortran ... Non, mais alors les résultats d'exécution ne peuvent pas être comparés avec le livre. Muu.

Recommended Posts

Essayez de porter le programme "FORTRAN77 Numerical Computing Programming" vers C et Python (partie 3)
Essayez de porter le programme "FORTRAN77 Numerical Computing Programming" vers C et Python (partie 2)
Essayez de résoudre le livre des défis de programmation avec python3
[Introduction à Python] J'ai comparé les conventions de nommage de C # et Python.
Ecrire un programme qui abuse du programme et envoie 100 e-mails
Essayer d'implémenter et de comprendre les arborescences de segments étape par étape (python)
Mettez Cabocha 0.68 dans Windows et essayez d'analyser la dépendance avec Python
Langage C pour voir et se souvenir de la partie 2 Appeler le langage C à partir de la chaîne Python (argument)
Portage et modification du solveur de doublets de python2 vers python3.
Essayez d'écrire du code python pour générer du code go - Essayez de porter JSON-to-Go et ainsi de suite
Python amateur tente de résumer la liste ①
Langage C pour voir et se souvenir de la partie 4 Appelez le langage C depuis Python (argument) double
Langage C pour voir et se souvenir de la partie 5 Appel du langage C à partir du tableau Python (argument)
Langage C pour voir et se souvenir de la partie 3 Appelez le langage C depuis Python (argument) c = a + b
Comment utiliser la bibliothèque C en Python
Comment générer une séquence en Python et C ++
Essayez de résoudre le problème de l'héritage de classe Python
Essayez de résoudre le diagramme homme-machine avec Python
Essayez d'utiliser le framework Web Python Tornado Partie 1
Essayez d'utiliser le framework Web Python Tornado Partie 2
Tutoriel "Cython" pour rendre Python explosif: Passez l'objet de classe C ++ à l'objet de classe côté Python. Partie 2
L'histoire du portage du code de C vers Go (et vers la spécification du langage)
Réfléchissez à la programmation de Python sur votre iPad
Essayez de créer un module Python en langage C
[Python] Essayez de lire la bonne réponse au problème FizzBuzz
Essayez de résoudre le problème d'affectation du médecin de formation avec Python
Essayez le fonctionnement de la base de données avec Python et visualisez avec d3
Essayez d'incorporer Python dans un programme C ++ avec pybind11
Conseils et précautions lors du portage des programmes MATLAB vers Python
python Spécifie la fonction à exécuter lorsque le programme se termine
J'ai senti que j'avais porté le code Python en C ++ 98.
Comment profiter de Python sur Android !! Programmation en déplacement !!
Aller à la langue pour voir et se souvenir du langage Partie 7 C en langage GO
[C / C ++] Passez la valeur calculée en C / C ++ à une fonction python pour exécuter le processus et utilisez cette valeur en C / C ++.
Tutoriel "Cython" pour rendre Python explosif: Passez un objet de classe C ++ à un objet de classe côté Python. Partie ①
Essayez d'importer dans la base de données en manipulant ShapeFile d'informations numériques sur les terres nationales avec Python
Une histoire sur le portage du code de "Essayez de comprendre comment fonctionne Linux" sur Rust
[Python] Un programme pour trouver le nombre de pommes et d'oranges qui peuvent être récoltées
[Introduction à cx_Oracle] (Partie 6) Mappage des types de données DB et Python
Essayez de le faire avec GUI, PyQt en Python
Essayez d'utiliser l'API Twitter rapidement et facilement avec Python
Essayez d'obtenir la liste des fonctions du paquet Python> os
Je voulais résoudre le concours de programmation Panasonic 2020 avec Python
Essayez de vous connecter à Supervisord via XML RPC pour démarrer / arrêter le programme
Mesurons le résultat de l'exécution du programme avec C ++, Java, Python.
[Part.2] Exploration avec Python! Cliquez sur la page Web pour vous déplacer!
J'ai essayé d'illustrer le temps et le temps du langage C
Essayez d'ouvrir une sous-fenêtre avec PyQt5 et Python
Créer un environnement Python et transférer des données vers le serveur
J'ai essayé de programmer le test du chi carré en Python et Java.
Essayez d'automatiser le fonctionnement des périphériques réseau avec Python
Résolution avec Ruby et Python AtCoder ABC011 C Méthode de planification dynamique
Je veux connaître la nature de Python et pip
J'ai essayé d'énumérer les différences entre java et python
Orienté objet en langage C: "○ ✕ game" a été refacturé et porté en Python
Programme pour juger si c'est une année calme du calendrier occidental [Python]
Essayez simplement de recevoir un webhook avec ngrok et Python
Essayez de déchiffrer les caractères déformés dans le nom du fichier joint avec Python
Aller au langage pour voir et se souvenir de la partie 8 Appeler le langage GO à partir de Python
Transmettez les données OpenCV de la bibliothèque C ++ d'origine à Python
Lisez l'ancien fichier Word du formulaire d'application Gakushin DC (.doc) à partir de Python et essayez de le faire fonctionner