Hochschule für Technik, Wirtschaft und Kultur Leipzig Fakultät Informatik, Mathematik und Naturwissenschaften Multiprozessor-Systeme und Programmierung Beleg 3 Numerische Integration B.Sc. Matthias Rick 20. Juni 2010 Inhaltsverzeichnis 2 Inhaltsverzeichnis 1. Aufgabenstellung 3 2. Implementation 4 3. Beobachtungen 3.1. Genauigkeit der Formeln . . 3.2. Zeitverhalten . . . . . . . . 3.3. Skalierbarkeit und Speedup 3.4. Erkenntnisse . . . . . . . . A. Quelltext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 . 6 . 8 . 11 . 13 14 3 1. Aufgabenstellung Es soll ein FORTRAN77-Programm entwickelt werden, welches unterschiedliche Funktionen mittels verschiedener Algorithmen parallel integriert. Dabei soll das Integrationsintervall in gleich große Teile zerlegt werden, von denen jeder Prozessor je einen berechnet. Die Integrationsalgorithmen sollen Rechteck-, Trapez- sowie Simpson’sche (Parabel-) Formel nutzen. • Integration nach der Rechteckformel ´b a y dx ' h(y0 + y1 + ... + yn−1 ) ' h(f (a) + f (a + h) + ... + f (a + (n − 1) ∗ h)) • Integration nach der Trapezformel ´b a ´b a y dx ' h2 (y0 + 2y1 + ... + 2yn−1 + yn ) y dx ' h( f (a) 2 + f (a + 2h) + ... + f (a + (n − 1) ∗ h) + f (a+n∗h) ) 2 • Integration nach der Parabelformel / Simpson’sche Formel (für gerades n) ´b a y dx ' h3 (y0 + 4y1 + 2y2 + 4y3 + ... + 2yn−2 + 4yn−1 + yn ) Diesen Formeln ist gemeinsam, dass sie das Integral durch die Berechnung von Teilintervallen als Flächen unterhalb der Funktion approximieren. Daher wird zusätzlich eine Schrittanzahl (n) benötigt, die die Schrittweite (h) der Algorithmen bestimmt. Zum Untersuchen der Funktionalität werden folgende Testfunktionen verwendet: 1. f 1 (x) = x ∗ sin(x) ⇒0 2. f 2 (x) = 4 1+x2 ⇒0 ´1 ´π 4 1+x2 x ∗ sin(x) dx = π dx = π Im weiteren Dokument werden diese Funktionen als f 1 und f 2 bezeichnet. 4 2. Implementation Die Aufgabe wird mittels einer Master-Slave-Architektur gelöst. Hierzu wird die Struktur der Clique aus der Vir-Top-Library der Parix-Umgebung genutzt. Alle Knoten rechnen vollkommen gleichartig mit, wobei die Slaves nach Ende der Berechnung ihre Daten an den Master senden. Dieser empfängt der Reihe nach von allen die Teilintegrale und summiert diese auf. Alle benötigten Parameter übernimmt das Programm von der Kommandozeile. Es ist aber auch möglich, das Programm zu starten ohne die Parameter zu übergeben. Dann werden diese zunächst vom Master abgefragt und anschließend an die Slaves gesendet. Zusätzlich zu den Parametern holt sich das Programm noch Informationen über Prozessoranzahl und die spezifische Prozessor-ID. Im folgenden die Auflistung der einzelnen Kommandozeilenargumente: 1. Output-Mode: • 1 : Abweichung zu Maschinen-PI • 2 : Zeitmessung 2. Welcher Integrationsalgorithmus? • 1 : Rechteck • 2 : Trapez • 3 : Simpson 3. Welche Testfunktion? • 1: f 1 (x) = x ∗ sin(x) • 2: f 2 (x) = 4 1+x2 4. Wie viele Integrationsintervalle? • Möglich ist die Eingabe eines ASCII-Zeichens ab ’0’, aus dem sich die Anzahl der Integrationsintervalle wie folgt berechnet: n = 2((ASCII−48)+5) ) Somit ergeben sich folgende 2er Potenzen: – ’0’: n = 64 – ’1’: n = 128 – ’2’: n = 256 – ... – ’:’: n = 32768 – ’;’: n = 65636 – ’<’: n = 131072 5 Da beim Starten des Programmes mit Kommandozeilenargumenten die benötigten Daten allen Prozessoren gleichermaßen vom Start an zur Verfügung stehen, wird keine Verteilung von Daten durch den Master benötigt. Stattdessen können die Slaves die Grenzen ihres Teils des Integationsintervalls sowie ihre Schrittanzahl direkt aus den Parametern, der Prozessoranzahl und ihrer Prozessor-ID berechnen. Ein weiterer Vorteil ist, dass man durch die Eingabe der Parameter über die Kommandozeile Skripte zum automatisierten Ausführen und auswerten nutzen kann. Zur Berechnung der einzelnen Teilintevalle ermittelt jeder Prozessor zunächst die Schrittweite durch folgende Formel: h= b−a n Anschließend wird die Anzahl der Schritte benötigt er, die jeder Prozessor selbst berechnen muss. Dies geschieht indem die Anzahl der Partitionsintervalle durch die Anzahl der Prozessoren (nprocs) geteilt wird: nP roz = n nprocs Letztlich wird anhand der Prozessor-ID die untere Intervall-Grenze wie folgt berechnet: a = P ID ∗ nP roz ∗ h Mit diesen drei Werten (h, nP roz und a) kann die Berechnung auf den einzelnen Prozessoren durchgeführt werden. Anschließend findet dann die einzige Kommunikation statt, in der die DOUBLE PRECISION -Ergebnisse an den Master geschickt werden. Dieser summiert dann die Ergbnisse noch auf und gibt je nach Output-Mode entweder die Laufzeit oder die Abweichung des Ergebnisses vom Maschinen-PI an. 6 3. Beobachtungen 3.1. Genauigkeit der Formeln Die Tabellen 3.1 und 3.2 vergleichen die von den verschiedenen Formeln und Funktionen gelieferten Abweichungen vom Maschinen-π. Berechnet wurden die Werte auf einem Prozessor. Man kann allgemein feststellen, dass die Abweichungen mit steigender Schrittzahl (n) geringer werden. Dies trifft hauptsächlich für Rechteck- und Trapez-Formel zu. Bei der Simpson’schen Formel stimmt dies zwar auch, aber die Aussage beschränkt sich dabei auf wesentlich geringere Schrittzahlen, als bei den anderen beiden. Weiterhin lässt sich feststellen, dass die von der Simpson’schen Formel gelieferten Werte bei kleiner Schrittzahl genauer, als die der Trapezformel und der Rechteckformel sind. Anders formuliert benötigt die Simpson’sche Formel weniger Iterationen um ein gleich genaues Ergebnis zu erzeugen, als die anderen beiden. Das bei weiter steigender Schrittzahl das Ergebnis der Simpson’schen Formel wieder ungenauer wird, liegt an numerischen Fehlern, die bei der Berechnung entstehen. Beim Vergleich zwischen Rechteck- und Trapezformel bei f 1 fällt auf, dass die Abweichungen identisch sind. Das liegt daran, dass der Sinus an den beiden Integrationsgrenzen (bei 0 und bei π) 0 beträgt und somit auch der Funktionswert an der Stelle 0 ist. Durch Vereinfachen von Trapezformel und Rechteckformel ergibt sich dann die gleiche Integrations-Formel: ´b Rechteck: a y dx ' h(y0 + ... + yn−1 ) = h(y1 + ... + yn−1 ) Trapez: ´b a y dx ' h2 (2y1 + ... + 2yn−1 ) = h(y1 + ... + yn−1 ) Außerdem ist zu sehen, dass die Parabelformel bei f 1 größere Abweichungen, als bei f 2 hat. Dies hat zum einen den Grund, dass die Schrittweiten kleiner sind (da bei f 2 das Intervall nur von 0 bis 1 geht) und zum anderen lässt sich die Funktion f 2, da sie im zu integrierenden Intervall nahezu eine Gerade ist, besser approximieren. Ähnlich verhält sich dies auch bei der Trapezformel. Es ist weiterhin zu erkennen, dass f 2 und die Rechteckformel besser miteinander harmonieren als f 1 mit der gleichen Formel. Der Grund dafür ist, dass f 1 in den ersten zwei Dritteln des Integrationsintervalls langsam ansteigt und dann im letzten Drittel schnell fällt, während f 2 über den gesamten Integrationsbereich fällt. Dadurch haben die von der Rechteckformel gemachten Näherungsfehler bei f 1 die Möglichkeit, sich auszugleichen, während sie sich für f 2 immer weiter summieren. Funktion f1 f2 f1 f2 f1 f2 Formel Rechteck Rechteck Trapez Trapez Simpson Simpson Schritte 64 64 64 64 64 64 Abweichung vom Maschinen-π 0.0006308496490250 0.0155843098958605 0.0006308496490246 0.0000406901041389 0.0000001013634918 0.0000000000005782 Tabelle 3.1.: Abweichungen vom Maschinen-π (I) 3.1. GENAUIGKEIT DER FORMELN Funktion f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 f1 f2 Formel Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson Rechteck Rechteck Trapez Trapez Schritte 128 128 128 128 128 128 256 256 256 256 256 256 512 512 512 512 512 512 1024 1024 1024 1024 1024 1024 2048 2048 2048 2048 2048 2048 4096 4096 4096 4096 4096 4096 8192 8192 8192 8192 8192 8192 16384 16384 16384 16384 7 Abweichung vom Maschinen-π 0.0001577076618577 0.0078023274739593 0.0001577076618572 0.0000101725260410 0.0000000063338632 0.0000000000000097 0.0000394266185717 0.0039037068684884 0.0000394266185717 0.0000025431315116 0.0000000003958549 0.0000000000000004 0.0000098566361290 0.0019524892171283 0.0000098566361295 0.0000006357828716 0.0000000000247015 0.0000000000000004 0.0000024641578529 0.0009764035542789 0.0000024641578529 0.0000001589457210 0.0000000000015534 0.0000000000000013 0.0000006160394905 0.0004882415135663 0.0000006160394905 0.0000000397364337 0.0000000000000004 0.0000000000000018 0.0000001540101344 0.0002441306908905 0.0000001540101349 0.0000000099341095 0.0000000000002731 0.0000000000000000 0.0000000385019772 0.0001220678289791 0.0000000385019772 0.0000000024835209 0.0000000000004947 0.0000000000000044 0.0000000096259147 0.0000610345353587 0.0000000096259147 0.0000000006208913 Tabelle 3.2.: Abweichungen vom Maschinen-π (II) 3.2. ZEITVERHALTEN Funktion f1 f2 f1 f2 f1 f2 f1 f2 Formel Simpson Simpson Rechteck Rechteck Trapez Trapez Simpson Simpson 8 Schritte 16384 16384 32768 32768 32768 32768 32768 32768 Abweichung vom Maschinen-π 0.0000000000002887 0.0000000000000071 0.0000000024049585 0.0000305174229003 0.0000000024049580 0.0000000001552247 0.0000000000014349 0.0000000000000107 Tabelle 3.3.: Abweichungen vom Maschinen-π (I) 3.2. Zeitverhalten Die Abbildungen 3.1 bis 3.6 zeigen die Laufzeit der Integration der zwei Funktionen mit den verschiedenen Formeln in rein sequentieller Ausführung und Parallelisierung auf 4 bzw. 8 Prozessoren. Deutlich ist zu erkennen, dass sich alle Algorithmen linear verhalten und die unterschiedlichen Anstiege zeigen die verschiedenen Rechengeschwindigkeiten an. Demnach ist f 2 mit der Rechteckformel am schnellsten, gefolgt von Trapezformel und letztlich der Simpson’schen. Die gleiche Rangfolge gilt auch für die Funktion f 1, nur dass diese allgemein längere Laufzeiten hat. Dieser Unterschied zwischen den Funktionen erklärt sich aus der Verwendung des Sinus in f 1, welcher durch die interne Reihenentwicklung langsamer arbeitet. Die unterschiedlichen Laufzeiten der einzelnen Formeln erklären sich aus dem Rechenaufwand, der bei der Rechteckformel geringer ist, als bei der Trapezformel und den größten Rechenaufwand benötigt die Simpson’sche Formel. Abbildung 3.1.: Zeitverhalten von Testfunktion 1 sequentiell 3.2. ZEITVERHALTEN Abbildung 3.2.: Zeitverhalten von Testfunktion 2 sequentiell Abbildung 3.3.: Zeitverhalten von Testfunktion 1 bei 4 Prozessoren 9 3.2. ZEITVERHALTEN Abbildung 3.4.: Zeitverhalten von Testfunktion 2 bei 4 Prozessoren Abbildung 3.5.: Zeitverhalten von Testfunktion 1 bei 8 Prozessoren 10 3.3. SKALIERBARKEIT UND SPEEDUP 11 Abbildung 3.6.: Zeitverhalten von Testfunktion 2 bei 8 Prozessoren Weiterhin ist in der Abbildung 3.7 zu erkennen, dass die Parallelisierung keinen Einfluß auf das lineare Zeitverhalten der Algorithmen hat. Das liegt an der minimalen Kommunikation zwischen den einzelnen Prozessoren. Abbildung 3.7.: Zeitverhalten Rechteckformel für verschiedene Prozessoranzahlen (f 1) 3.3. Skalierbarkeit und Speedup Abbildung 3.8 zeigt beispielhaft die Skalierbarkeit der Rechteckformel für verschiedene Schrittzahlen. Wie in Abschnitt 3.2 untersucht, ist das Zeitverhalten der anderen Formeln und damit auch die Skalierbarkeit identisch. Deutlich ist die Annäherung an Null und ein Verhalten nach n1 zu erkennen. Damit skaliert der Algorithmus sehr gut. Dies ist zurückzuführen auf die grobe Granularität des Programms. Das bedeutet, dass die Anzahl der Rechenschritte vor der Kommunikation ansteigt, der Kommunikationsaufwand hingegen aber gleich bleibt. 3.3. SKALIERBARKEIT UND SPEEDUP 12 Abbildung 3.8.: Skalierbarkeit der Rechteckformel für verschiedene Schrittzahlen (f 1) Abbildung 3.9 gibt den Speedup für f 1 mit Rechteckformel und 32768 Schritten aus. Wie im Abschnitt 3.2 gesehen, verhalten sich die zweite Funktion und die anderen Formeln gleich. Sehr schön ist der lineare Anstieg zu erkennen, ohne dass eine Abflachung oder gar Konvergenz zu sehen wäre. Dies zeigt die sehr gute Parallelisierbarkeit der Integration. Abbildung 3.9.: Speedup der Rechteckformel (f 1) Nachfolgend noch eine Betrachtung der Effizienz des Programms (Speedup-Werte der Rechteckformel unter Benutzung der Testfunktion f 1): E(p) = S(p) p E(1) = 1 E(2) = E(4) = E(8) = 1,990088964 2 3,956715369 4 7,807227827 8 = 0, 995044482 = 0, 98917884225 = 0, 975903478375 Wie an den einzelnen Effizienzwerten zu sehen ist, entfernen sich die Werte nur sehr langsam von 1, was einem exakt linearen Algorithmus gleichkommen würde. Das ist ebenfalls ein Nachweis für die gute Parallelisierbarkeit des Algorithmus. Letztlich gilt es natürlich noch den Speedup für die Simpson’sche Formel zu betrachten. Dargestellt ist dies in Abbildung 3.10. Da wir bereits bei sehr geringen Schrittzahlen ein 3.4. ERKENNTNISSE 13 hinreichend genaues Ergebnis erhalten, so müssen auch nur diese geringen Schrittzahlen betrachtet werden. Abbildung 3.10.: Speedup der Simpson’schen Formel(f 2) Auffallend in Abbildung 3.10 ist, dass es bei einer Schrittzahl von 64 gar keinen Speedup gibt und selbst bei 128 und 256 nur bei 2 bzw. 4 Prozessoren ein kleiner Speedup zu sehen ist. Zurückzuführen ist dies auf den Kommunikationsoverhead. Bei solch geringen Schittzahlen lohnt sich dementsprechend eine Parallelisierung nicht. 3.4. Erkenntnisse Abschließend lässt sich aus den Ergebnissen aus 3.1 bis 3.3 schlussfolgern, dass bei der numerischen Integration die Wahl der Integrationsformel, wesentlich schneller ein genaueres Ergebnis erzielen kann, als die Paralleliesierung einer anderen Integrationsformel. Dies zeigt sich ganz deutlich im Direktvergleich der Rechteck- und der Simpson’schen Formel: Die Simpson’schen Formel hat bereits bei einer Schrittzahl von 64 und der Funktion f 1 eine Genauigkeit von 10−6 . Die Rechteckformel hingegen erreicht solch eine Genauigkeit erst ab einer Schrittzahl von über 2048. Formel Rechteck Simpson Schrittzahl 2048 64 Abweichung 0.0000006160394905 0.0000001013634918 Prozessoren 8 1 Laufzeit 17208 3779 Tabelle 3.4.: Laufzeitvergleich von Rechteck- und Simpson’scher Formel (f 1) Tabelle 3.3 zeigt die Laufzeiten der beiden Verfahren bei annähernd gleicher Abweichung. Dabei wird die Rechteckformel auf 8 Prozessoren ausgeführt und die Simpson’sche Formel nur auf einem. Auch bezieht sich die Betrachtung auf die Funktion f 1, die für die Simpson’sche Formel ein schlechteres Ergebnis erzielt. Das bedeutet, das bei f 2 der Unterschied noch wesentlich größer wäre. 14 A. Quelltext C C C C PROGRAM i n t e g r a l Initialisierung INTEGER which , t f , n , Requid , nLinks , np , i a r g c INTEGER Topid , L i n k s ( 0 : 7 ) , PID , MSG( 0 : 2 ) INTEGER timenowhigh , tS , tE , t , a r g c n t , l e v e l DOUBLE PRECISION PI , y i n t , a , b , h , e r g CHARACTER argv ∗10 PARAMETER( Requid = 1 , nLinks = 7 ) PI=DACOS(DBLE( − 1 . 0 ) ) Anlegen d e r T o p o l o g i e np = n p r o c s ( ) Topid = m a k e c l i q u e ( 1 , np , −1 , −1 , −1 , −1 , −1 , −1 ,PID , L i n k s ) argcnt = iargc () PRINT∗ , ’ a r g c n t = ’ , a r g c n t IF ( a r g c n t . g t . 3 ) THEN CALL g e t a r g ( 1 , argv ) l e v e l = ICHAR( argv )−48 CALL g e t a r g ( 2 , argv ) which = ICHAR( argv )−48 CALL g e t a r g ( 3 , argv ) t f = ICHAR( argv )−48 CALL g e t a r g ( 4 , argv ) n = 2 ∗ ∗ (ICHAR( argv )−48 + 5 ) ELSE n = 1024 IF ( PID . eq . 0 ) THEN Menü PRINT∗ , ’ I n t e g r a l b e r e c h n u n g \n 1 −> Rechteck ’ PRINT∗ , ’ 2 −> Trapez \n 3 −> P a r a b e l \n ’ READ∗ , which PRINT∗ , ’ T e s t f u n k t i o n 1 o d e r 2 ’ READ∗ , t f PRINT∗ , ’ Anzahl d e r P a r t i t i o n s i n t e r v a l l e ’ READ∗ , n ENDIF IF ( PID . eq . 0 ) THEN Verteilung MSG( 0 ) = n MSG( 1 ) = which MSG( 2 ) = t f DO i =1, np−1 CALL send ( Topid , L i n k s ( i ) , MSG, 1 2 ) ENDDO 15 ELSE CALL r e c v ( Topid , L i n k s ( 0 ) , MSG, 1 2 ) n = MSG( 0 ) which = MSG( 1 ) t f = MSG( 2 ) ENDIF ENDIF tS = timenowhigh ( ) C C C C C C Intervallgrenzen IF ( t f . eq . 1 ) THEN a = DBLE( 0 . 0 ) b = PI ENDIF IF ( t f . eq . 2 ) THEN a = DBLE( 0 . 0 ) b = DBLE( 1 . 0 ) ENDIF Berechnung h = ( b−a ) /DBLE( n ) Es muss g e l t e n : n%np=0 n = INT( n/np ) a = DBLE( PID ) ∗ DBLE( n ) ∗ h IF ( which . eq . 1 ) THEN CALL r e c h t e c k ( a , h , n , t f , y i n t ) ENDIF i f ( which . eq . 2 ) THEN CALL t r a p e z ( a , h , n , t f , y i n t ) ENDIF i f ( which . eq . 3 ) THEN CALL p a r a b e l ( a , h , n , t f , y i n t ) ENDIF Zusammentragen und Aufsummieren d e r T e i l i n t e r v a l l e IF ( PID . eq . 0 ) THEN Verteilung DO i =1, np−1 CALL r e c v ( Topid , L i n k s ( i ) , erg , 8 ) y int = y int + erg ENDDO tE = timenowhigh ( ) t = tE − tS Ausgaben IF (LEVEL == 2 ) THEN PRINT∗ , ’ L a u f z e i t : ’ , t ENDIF IF (LEVEL == 1 ) THEN PRINT∗ , ’ Abweichung zu Maschinen−PI : ’ , DABS( PI − y i n t ) ENDIF ELSE CALL send ( Topid , L i n k s ( 0 ) , y i n t , 8 ) ENDIF 16 CALL f r e e t o p ( Topid ) END SUBROUTINE r e c h t e c k ( a , h , n , t f , y i n t ) INTEGER t f , i , n DOUBLE PRECISION a , y i n t , h , f u n k t i o n 1 , f u n k t i o n 2 y i n t = DBLE( 0 . 0 ) i = 0 DO WHILE( n . g t . i ) i = i + 1 IF ( t f .EQ. 1 ) THEN y int = y int + funktion1 (a) ENDIF IF ( t f .EQ. 2 ) THEN y int = y int + funktion2 (a) ENDIF a = a + h ENDDO y int = h ∗ y int RETURN END SUBROUTINE t r a p e z ( a , h , n , t f , y i n t ) INTEGER t f , i , n DOUBLE PRECISION a , y i n t , h , f u n k t i o n 1 , f u n k t i o n 2 y i n t = DBLE( 0 . 0 ) i = 0 DO WHILE( n . ge . i ) i = i + 1 IF ( t f .EQ. 1 ) THEN IF ( ( i .EQ . 1 ) .OR. ( i .EQ. n+1)) THEN y i n t = y i n t + f u n k t i o n 1 ( a ) / DBLE( 2 . 0 ) ELSE y int = y int + funktion1 (a) ENDIF ENDIF IF ( t f .EQ. 2 ) THEN IF ( ( i .EQ . 1 ) .OR. ( i .EQ. n+1)) THEN y i n t = y i n t + f u n k t i o n 2 ( a ) / DBLE( 2 . 0 ) ELSE y int = y int + funktion2 (a) ENDIF ENDIF a = a + h ENDDO y int = h ∗ y int RETURN END 17 SUBROUTINE p a r a b e l ( a , h , n , t f , y i n t ) INTEGER t f , i , n DOUBLE PRECISION a , y i n t , h , f u n k t i o n 1 , f u n k t i o n 2 y i n t = DBLE( 0 . 0 ) i = 0 DO WHILE( n . ge . i ) i = i + 1 IF ( t f .EQ. 1 ) THEN IF ( ( i .EQ . 1 ) .OR. ( i .EQ. n+1)) THEN y int = y int + funktion1 (a) ELSE IF (MOD( i −1,2)==1) THEN y i n t = y i n t + DBLE( 4 . 0 ) ∗ f u n k t i o n 1 ( a ) ELSE y i n t = y i n t + DBLE( 2 . 0 ) ∗ f u n k t i o n 1 ( a ) ENDIF ENDIF ENDIF IF ( t f .EQ. 2 ) THEN IF ( ( i .EQ . 1 ) .OR. ( i .EQ. n+1)) THEN y int = y int + funktion2 (a) ELSE IF (MOD( i −1,2)==1) THEN y i n t = y i n t + DBLE( 4 . 0 ) ∗ f u n k t i o n 2 ( a ) ELSE y i n t = y i n t + DBLE( 2 . 0 ) ∗ f u n k t i o n 2 ( a ) ENDIF ENDIF ENDIF a = a + h ENDDO y i n t = h / DBLE( 3 . 0 ) ∗ y i n t RETURN END DOUBLE PRECISION FUNCTION f u n k t i o n 1 ( x ) DOUBLE PRECISION x , f u n k t i o n 1 f u n k t i o n 1 = x∗ s i n ( x ) RETURN END DOUBLE PRECISION FUNCTION f u n k t i o n 2 ( x ) DOUBLE PRECISION x , f u n k t i o n 2 f u n k t i o n 2 = DBLE( 4 . 0 ) / (DBLE( 1 . 0 ) + x∗x ) RETURN END