-
Notifications
You must be signed in to change notification settings - Fork 1
/
temi-svolti.html
2076 lines (2047 loc) · 330 KB
/
temi-svolti.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="it-IT" xml:lang="it-IT">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc-markdown-css-theme" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="author" content="Maurizio Tomasi" />
<title>Temi d’esame svolti</title>
<link rel="stylesheet" href="css/theme.css" />
<link rel="stylesheet" href="css/skylighting-solarized-theme.css" />
<script defer="" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js"></script>
<script>document.addEventListener("DOMContentLoaded", function () {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length; i++) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}});
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" />
<script src="./fmtinstall.js"></script>
</head>
<body>
<header>
<h1 class="title">Temi d’esame svolti</h1>
<blockquote class="metadata">
<p class="author">
Maurizio Tomasi
</p>
<p class="date before-toc"><time datetime="A.A. 2024−2025">A.A. 2024−2025</time></p>
</blockquote>
</header>
<nav id="TOC" role="doc-toc">
<strong>Contents</strong><label for="contents">⊕</label>
<input type="checkbox" id="contents">
<ul>
<li><a href="#premessa" id="toc-premessa">Premessa</a></li>
<li><a href="#alcuni-trucchi-sempre-utili" id="toc-alcuni-trucchi-sempre-utili">Alcuni trucchi sempre utili</a>
<ul>
<li><a href="#uso-di-struct" id="toc-uso-di-struct">Fare a meno dell’incapsulamento</a></li>
<li><a href="#template" id="toc-template">Usare i template al posto di gerarchie di classi</a></li>
<li><a href="#functori" id="toc-functori">Functori</a></li>
</ul></li>
<li><a href="#temaA" id="toc-temaA">Tema 1 (stima di integrali)</a>
<ul>
<li><a href="#letturaTestoA" id="toc-letturaTestoA">Lettura del testo</a></li>
<li><a href="#temaApuntoA" id="toc-temaApuntoA">Implementazione del punto 1</a></li>
<li><a href="#temaApuntoB" id="toc-temaApuntoB">Implementazione del punto 2</a></li>
<li><a href="#temaApuntoCD" id="toc-temaApuntoCD">Implementazione dei punti 3 e 4</a></li>
<li><a href="#temaApuntoE" id="toc-temaApuntoE">Implementazione del punto 5</a></li>
<li><a href="#temaApuntoF" id="toc-temaApuntoF">Implementazione del punto 6</a></li>
<li><a href="#temaApuntoG" id="toc-temaApuntoG">Implementazione del punto 7</a></li>
</ul></li>
<li><a href="#temaB" id="toc-temaB">Tema 2 (equazioni differenziali)</a>
<ul>
<li><a href="#temaBLetturaTesto" id="toc-temaBLetturaTesto">Lettura del testo</a></li>
<li><a href="#temaBpuntoA" id="toc-temaBpuntoA">Implementazione del punto 1</a></li>
<li><a href="#temaBpuntoB" id="toc-temaBpuntoB">Implementazione del punto 2</a></li>
<li><a href="#temaBpuntoC" id="toc-temaBpuntoC">Implementazione del punto 3</a></li>
<li><a href="#temaBpuntoD" id="toc-temaBpuntoD">Implementazione del punto 4</a></li>
<li><a href="#temaBpuntoE" id="toc-temaBpuntoE">Implementazione del punto 5</a></li>
</ul></li>
<li><a href="#temaC" id="toc-temaC">Tema 3 (equazioni differenziali, Monte Carlo)</a>
<ul>
<li><a href="#lettura-del-testo" id="toc-lettura-del-testo">Lettura del testo</a></li>
<li><a href="#temaCpuntoA" id="toc-temaCpuntoA">Implementazione del punto 1</a></li>
<li><a href="#temaCpuntoB" id="toc-temaCpuntoB">Implementazione del punto 2</a></li>
<li><a href="#temaCpuntoC" id="toc-temaCpuntoC">Implementazione del punto 3</a></li>
</ul></li>
<li><a href="#temaD" id="toc-temaD">Tema 4 (integrali, ricerca di zeri)</a>
<ul>
<li><a href="#lettura-del-testo-1" id="toc-lettura-del-testo-1">Lettura del testo</a></li>
<li><a href="#temaDpuntoA" id="toc-temaDpuntoA">Implementazione del punto 1</a></li>
<li><a href="#temaDpuntoB" id="toc-temaDpuntoB">Implementazione del punto 2</a></li>
<li><a href="#temaDpuntoC" id="toc-temaDpuntoC">Implementazione del punto 3</a></li>
</ul></li>
<li><a href="#temaE" id="toc-temaE">Tema 5 (simulazione di un esperimento)</a>
<ul>
<li><a href="#lettura-del-testo-2" id="toc-lettura-del-testo-2">Lettura del testo</a></li>
<li><a href="#temaEpuntoA" id="toc-temaEpuntoA">Implementazione del punto 1</a></li>
<li><a href="#temaEpuntoB" id="toc-temaEpuntoB">Implementazione del punto 2</a></li>
<li><a href="#temaEpuntoC" id="toc-temaEpuntoC">Implementazione del punto 3</a></li>
<li><a href="#temaEpuntoD" id="toc-temaEpuntoD">Implementazione del punto 4</a></li>
</ul></li>
</ul>
</nav>
<main>
<p>In questa pagina fornisco indicazioni utili allo svolgimento dei temi d’esame messi a disposizione da Carminati alla pagina <a href="https://labtnds.docs.cern.ch/ProveEsame/TemiEsame/" class="uri">https://labtnds.docs.cern.ch/ProveEsame/TemiEsame/</a>.</p>
<h1 id="premessa">Premessa</h1>
<p>Prima di discutere come svolgere i temi d’esame proposti da Carminati, vi fornisco qualche informazione di massima che si applica a ciascuno dei temi:</p>
<ul>
<li><p>Non fornisco qui l’implementazione completa, perché ciò significherebbe condividere anche delle routine che devono essere implementate nel corso dell’anno da ciascuno studente (es., il metodo di bisezione, l’integrazione col metodo del punto medio, il metodo di Runge-Kutta…).</p></li>
<li><p>Non ripeto concetti già spiegati a lezione, ed assumo anzi che chi legge questa pagina abbia già una buona infarinatura della teoria ed abbia svolto e sistemato tutti gli esercizi.</p></li>
<li><p>In ogni tema uso tecniche un po’ diverse da quelle che avete visto a lezione; di solito, queste varianti che vi mostro servono per rendere il codice più veloce da scrivere (importante nell’esame scritto, dove avete a disposizione solo due ore!).</p></li>
<li><p>Assumo che ciascuno di voi usi lo standard C++20: questo significa usare il flag <code>-std=c++20</code> con il compilatore.</p></li>
<li><p>Nei miei svolgimento non uso ROOT, ma Gnuplot interfacciato con la libreria <a href="https://github.com/ziotom78/gplotpp">gplot++</a>: lo trovo molto più semplice e veloce da usare. Fate riferimento a <a href="index.html#gplotinstall">questo link</a> per sapere come installarlo sul vostro computer</p></li>
<li><p>Similmente, uso <code>cout</code> e <code>cerr</code> solo nei casi più semplici, mentre quando si tratta di stampare numeri formattati uso la libreria <a href="https://github.com/fmtlib/fmt">fmt</a>. Fate riferimento a <a href="index.html#fmtinstall">questo link</a> per maggiori informazioni.</p></li>
<li><p>Siete caldamente invitati a tenere presente i punti elencati al link <a href="index.html#esamescritto">Come prepararsi all’esame scritto</a> mentre leggete questa pagina!</p></li>
</ul>
<h1 id="alcuni-trucchi-sempre-utili">Alcuni trucchi sempre utili</h1>
<p>Nello svolgimento dei temi d’esame presentato sotto faccio spesso ricorso ad alcuni trucchi, che illustro una volta per tutte in questa sezione</p>
<h2 id="uso-di-struct">Fare a meno dell’incapsulamento</h2>
<p>Nell’<a href="carminati-esercizi-05.html#esercizio-5.0">esercizio 5.0</a> abbiamo visto come si implementa una classe rispettando il principio dell’<em>incapsulamento</em>, in cui i dati della classe non sono direttamente accessibili all’esterno:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Posizione <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// costruttori</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> Posizione<span class="op">();</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> Posizione<span class="op">(</span><span class="dt">double</span> x<span class="op">,</span> <span class="dt">double</span> y<span class="op">,</span> <span class="dt">double</span> z<span class="op">);</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// distruttore</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> <span class="op">~</span>Posizione<span class="op">();</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// metodi</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> getX<span class="op">()</span> <span class="at">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="va">m_x</span><span class="op">;</span> <span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> getY<span class="op">()</span> <span class="at">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="va">m_x</span><span class="op">;</span> <span class="op">}</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> getZ<span class="op">()</span> <span class="at">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="va">m_z</span><span class="op">;</span> <span class="op">}</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// […]</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Distanza<span class="op">(</span><span class="at">const</span> Posizione <span class="op">&)</span> <span class="at">const</span><span class="op">;</span> <span class="co">// distanza da un altro punto</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a> <span class="co">// Dall'esterno è impossibile accedere a questi campi</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">,</span> <span class="va">m_y</span><span class="op">,</span> <span class="va">m_z</span><span class="op">;</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Questo è utile nel caso in cui si decida in futuro di cambiare il modo in cui la classe è implementata internamente. L’idea è che se si impedisce a chi usa la classe di sapere che le coordinate sono salvate in tre variabili chiamate <code>m_x</code>, <code>m_y</code> e <code>m_z</code>, sarà più facile cambiare poi la rappresentazione interna in qualcosa d’altro; ad esempio, si potrebbe cambiare la classe in modo che internamente si mantengano le coordinate sferiche, e <code>getX()</code>, <code>getY()</code> e <code>getZ()</code> ritornino quindi le componenti X/Y/Z calcolandone al volo la conversione da sferiche a cartesiane.</p>
<p>Tuttavia, implementare le classi in questo modo richiede un sacco di tempo e forza a compiere molte ripetizioni, aumentando la possibilità di errore. (Nell’esempio sopra, c’è un errore nel codice, ve ne eravate accorti?). L’idea dell’incapsulamento è quella di rendere il codice più facilmente modificabile in un futuro possibilmente lontano, ma il vostro esame scritto viene sviluppato giusto nel paio di ore richieste per la prova: l’incapsulamento è quindi inutile, oltre che potenzialmente dannoso per il tempo che vi fa sprecare.</p>
<p>Se volete definire una classe nel codice dell’esame, vi consiglio di farlo nel modo più rapido possibile:</p>
<ol>
<li><p>Definite tutti i metodi e i campi dati <code>public</code>.</p></li>
<li><p>Non implementate funzioni <code>get*()</code> e <code>set*()</code>, perché se tutti i dati sono pubblici non servono.</p></li>
<li><p>Evitate di definire i distruttori, a meno che non usiate <code>new</code> nel costruttore (non è il caso di <code>Posizione</code>, e in <strong>nessuno</strong> dei temi d’esame che abbiamo dato negli ultimi dieci anni è stato mai indispensabile usare <code>new</code>).</p></li>
<li><p>Potete anche evitare di definire i costruttori: in tal caso il C++ ne implementerà uno di default, in cui vengono richiesti i valori di tutte le variabili membro. In altre parole, la classe</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Posizione <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> Posizione<span class="op">(</span><span class="dt">double</span> x<span class="op">,</span> <span class="dt">double</span> y<span class="op">,</span> <span class="dt">double</span> z<span class="op">)</span> <span class="op">:</span> <span class="va">m_x</span><span class="op">{</span>x<span class="op">},</span> <span class="va">m_y</span><span class="op">{</span>y<span class="op">},</span> <span class="va">m_z</span><span class="op">{</span>z<span class="op">}</span> <span class="op">{}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">,</span> <span class="va">m_y</span><span class="op">,</span> <span class="va">m_z</span><span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>può essere abbreviata così:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Posizione <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">,</span> <span class="va">m_y</span><span class="op">,</span> <span class="va">m_z</span><span class="op">;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>ed il costruttore che accetta tre parametri è automaticamente scritto dal compilatore C++. Comodo, no?</p></li>
<li><p>In C++ si possono fornire valori di default alle variabili membro della classe. In questo modo, se scrivete</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Posizione <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">{</span><span class="fl">1.0</span><span class="op">},</span> <span class="va">m_y</span><span class="op">{</span><span class="fl">2.0</span><span class="op">},</span> <span class="va">m_z</span><span class="op">{</span><span class="fl">3.0</span><span class="op">};</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>potete poi creare una variabile <code>Posizione</code> e inizializzare le sue coordinate automaticamente:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> Posizione p<span class="op">{</span><span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span><span class="op">};</span> <span class="co">// Inizializzata a (1, 2, 3)</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> Posizione q<span class="op">{};</span> <span class="co">// Idem!</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div></li>
<li><p>Forse non lo sapete, ma in C++ c’è una scorciatoia per definire una classe con membri pubblici: la parola chiave <code>struct</code>. La scrittura</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Posizione <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">{},</span> <span class="va">m_y</span><span class="op">{},</span> <span class="va">m_z</span><span class="op">{};</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>è equivalente a</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Scrivo `struct` anziché `class`, così è tutto `public` di default</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Posizione <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="va">m_x</span><span class="op">{},</span> <span class="va">m_y</span><span class="op">{},</span> <span class="va">m_z</span><span class="op">{};</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>ma è più veloce da scrivere.</p></li>
</ol>
<p>Vi garantisco che il docente non si arrabbierà se usate questi accorgimenti e rinunciate all’incapsulamento: al massimo prenderà spunto dal vostro codice per chiedervi di parlare all’esame orale di “incapsulamento” da un punto di vista teorico, e se voi mostrerete di saperlo, il docente sarà ugualmente soddisfatto.</p>
<h2 id="template">Usare i template al posto di gerarchie di classi</h2>
<p>I template in C++ possono essere usati per rendere più veloce la programmazione, requisito importante in un esame scritto, ma richiedono di ripensare il codice scritto a lezione. Non è quindi una tecnica che raccomando a tutti, ma i più smaliziati possono trarre giovamento se re-implementano alcuni algoritmi degli esercizi usando i template.</p>
<p>Consideriamo l’<a href="carminati-esercizi-07.html#esercizio-7.0">esercizio 7.0</a>, che richiede di implementare il metodo di integrazione della media. A lezione è stato indicato di creare una classe <code>Integral</code>, una classe <code>FunzioneBase</code> e classi derivate da quest’ultima per ciascuna delle funzioni da integrare:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> FunzioneBase <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">virtual</span> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Parabola <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span><span class="op">;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Integral <span class="op">{</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">virtual</span> <span class="dt">double</span> calculate<span class="op">(</span><span class="dt">int</span> step<span class="op">,</span> <span class="at">const</span> FunzioneBase <span class="op">&</span> f<span class="op">)</span> <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> MidPoint <span class="op">:</span> <span class="kw">public</span> Integral <span class="op">{</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> calculate<span class="op">(</span><span class="dt">int</span> step<span class="op">,</span> <span class="at">const</span> FunzioneBase <span class="op">&</span> f<span class="op">)</span> <span class="kw">override</span><span class="op">;</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>L’esercizio era ovviamente pensato per farvi capire il funzionamento dell’ereditarietà e del polimorfismo. È però possibile implementare l’algoritmo del midpoint senza usare né l’uno né l’altro, appoggiandosi ai template: in questo modo il codice diventa molto più semplice da scrivere ed usare:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op"><</span><span class="kw">typename</span> Fn<span class="op">></span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> midpoint<span class="op">(</span>Fn fn<span class="op">,</span> <span class="dt">double</span> a<span class="op">,</span> <span class="dt">double</span> b<span class="op">,</span> <span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> accum<span class="op">{};</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">{};</span> i <span class="op"><</span> n<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> x<span class="op">{</span>a <span class="op">+</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">*</span> <span class="op">(</span><span class="dv">2</span> <span class="op">*</span> i <span class="op">+</span> <span class="dv">1</span><span class="op">)</span> <span class="op">/</span> <span class="op">(</span><span class="dv">2</span> <span class="op">*</span> n<span class="op">)};</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> accum <span class="op">+=</span> fn<span class="op">(</span>x<span class="op">);</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> accum <span class="op">*</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">/</span> n<span class="op">;</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>La definizione del template dice che <code>Fn</code> è un tipo che sarà specificato quando si invoca <code>midpoint</code>, e il tipo corrisponde a una funzione che accetta un <code>double</code> e restituisce un <code>double</code>, perché è così che viene impiegata la variabile <code>fn</code> nel ciclo <code>for</code>. Vediamo una cosa interessante: una variabile come <code>fn</code> in C++ può contenere non solo valori numerici o stringhe, ma addirittura una <em>funzione</em>.</p>
<p>Una volta definita la funzione template <code>midpoint()</code>, questa si usa in modo molto naturale:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> myfn<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">*</span> x <span class="op">-</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">+</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"The integral is </span><span class="sc">{}\n</span><span class="st">"</span><span class="op">,</span> midpoint<span class="op">(</span>myfn<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">));</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Spero che apprezzerete la brevità di questo codice: non c’è bisogno di creare una classe derivata <code>MyFn</code> né di creare una sua istanza <code>MyFn myfn{}</code> nel <code>main</code>. Nel nostro esempio, <code>myfn</code> è il nome di una funzione ma viene passato come parametro (di tipo <code>Fn</code> e di nome <code>fn</code>) alla funzione template; in altre parole, quando invochiamo <code>midpoint</code> così:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>midpoint<span class="op">(</span>myfn<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">)</span></span></code></pre></div>
<p>non scriviamo <code>myfn(…)</code> con le parentesi e un argomento al loro interno, scriviamo solo il nome della funzione perché non vogliamo invocarla ma solo passarla come parametro. Nel template <code>midpoint</code>, il compilatore C++ fa corrispondere il tipo <code>Fn</code> alla dichiarazione <code>double (double x)</code>, ossia una funzione che accetta un <code>double</code> e ritorna un <code>double</code>.</p>
<p>Questo tipo di funzione template è così diffuso che il C++20 consente di abbreviare la definizione</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op"><</span><span class="kw">typename</span> Fn<span class="op">></span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> midpoint<span class="op">(</span>Fn fn<span class="op">,</span> <span class="dt">double</span> a<span class="op">,</span> <span class="dt">double</span> b<span class="op">,</span> <span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>nel modo seguente, usando la parola chiave <code>auto</code>:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> midpoint<span class="op">(</span><span class="kw">auto</span> fn<span class="op">,</span> <span class="dt">double</span> a<span class="op">,</span> <span class="dt">double</span> b<span class="op">,</span> <span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>(È come se <code>auto</code> servisse per dire al compilatore: “non fare tante storie sul tipo di <code>fn</code>, decidi tu quale tipo ti va meglio!”).</p>
<p>Le due scritture sono equivalenti, ma la seconda è molto più veloce da scrivere. (Però dovete ricordare di usare un compilatore C++ abbastanza recente e passare il flag <code>-std=c++20</code>). Attenzione però che ogni <code>auto</code> che usate è un tipo diverso. Quindi la funzione</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> myfun<span class="op">(</span><span class="kw">auto</span> a<span class="op">,</span> <span class="kw">auto</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>non</strong> è equivalente a</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op"><</span><span class="kw">typename</span> T<span class="op">></span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> myfun<span class="op">(</span>T a<span class="op">,</span> T b<span class="op">)</span> <span class="op">{</span> <span class="co">// `a` and `b` are of the same type</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>ma corrisponde invece a</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op"><</span><span class="kw">typename</span> T<span class="op">,</span> <span class="kw">typename</span> U<span class="op">></span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> myfun<span class="op">(</span>T a<span class="op">,</span> U b<span class="op">)</span> <span class="op">{</span> <span class="co">// `a` and `b` can be of different types</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Se volete che <code>a</code> e <code>b</code> abbiano lo stesso tipo, allora non potete usare <code>auto</code> e dovete usare invece obbligatoriamente la parola chiave <code>template</code>.</p>
<p>Per quanto riguarda il punto in cui si <strong>usa</strong> il template, ossia quando nel nostro esempio viene invocato nel <code>main()</code>, se si usano le <a href="https://learn.microsoft.com/it-it/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170">espressioni lambda</a>, si può addirittura fare a meno di definire la funzione <code>myfn()</code>:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Shortest version ever: just five lines!!!</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"The integral is </span><span class="sc">{}\n</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> midpoint<span class="op">([](</span><span class="dt">double</span> x<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> x <span class="op">*</span> x <span class="op">-</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">+</span> <span class="dv">4</span><span class="op">;</span> <span class="op">},</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">));</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>La strana scrittura <code>[](double x) { return ...; }</code> permette di definire “al volo” una funzione senza nome che accetta un parametro <code>double x</code> e restituisce un <code>double</code>, e passarla come argomento.</p>
<p>È facile vedere come l’esempio appena mostrato sia più asciutto e rapido da scrivere rispetto ad un approccio orientato agli oggetti:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Parabola <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">*</span> x <span class="op">-</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">+</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a> Midpoint midpoint<span class="op">;</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a> Parabola myfun</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"The integral is </span><span class="sc">{}\n</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a> Eval<span class="op">.</span>integrate<span class="op">(</span><span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">,</span> myfun<span class="op">));</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In questo caso (1) non possiamo usare le espressioni lambda, (2) dobbiamo definire una classe <code>Parabola</code>, e (3) dobbiamo nel <code>main()</code> dichiarare due variabili: il codice è lungo più del doppio!</p>
<p>Chi fosse interessato all’uso dei <code>template</code>, con un piccolo sforzo può convertire gli algoritmi visti a lezione (bisezione, midpoint, Simpson, Runge-Kutta…) in template tramite un banale copia-e-incolla e qualche piccolo aggiustamento (e la cancellazione di un bel po’ di roba che diventa inutile, come tutte le classi base), e raccoglierli tutti in un file <code>algoritmi.h</code>. Vi sorprenderete di quanto corto sarà questo file: i template consentono di condensare molto il codice! Questo file <code>algoritmi.h</code> vi sarà poi utile da includere nel vostro compito, anziché andare a cercare il codice di ogni singolo esercizio in mille sottocartelle.</p>
<p>Chi non si spaventa all’idea di usare i <code>template</code> e le espressioni lambda, con un po’ di pratica può guadagnare velocità nella scrittura del codice: cosa che, come ho già scritto, è molto utile durante gli scritti.</p>
<p><strong>Avvertenza</strong>: in linea di principio, con la definizione template di <code>midpoint()</code> si potrebbe pensare di poter calcolare l’integrale di <span class="math inline">f(x) = \sin x</span> passandogli direttamente la funzione <code>sin</code> definita in <code><cmath></code>:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><cmath></span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>midpoint<span class="op">(</span><span class="bu">std::</span>sin<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">);</span> <span class="co">// Doesn't work</span></span></code></pre></div>
<p>ma questo non funziona perché <code><cmath></code> definisce <a href="https://en.cppreference.com/w/cpp/numeric/math/sin">più funzioni</a> chiamate <code>sin()</code>: una per <code>float</code>, una per <code>double</code>, e una per <code>long double</code>. Nel template non è chiaro quale usare, e quindi il compilatore C++ si arrabbia. La soluzione più veloce è quella di racchiuderla in un’espressione lambda, in modo da esplicitare il tipo:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Works because we explicitly tell the compiler that we want `double sin(double x)`</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>midpoint<span class="op">([]</span> <span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="bu">std::</span>sin<span class="op">(</span>x<span class="op">);</span> <span class="op">},</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">);</span></span></code></pre></div>
<p>Questo fastidioso inconveniente capita solo con le funzioni definite in <code>cmath</code>: quelle che definite voi non hanno di solito alcuna ambiguità.</p>
<h2 id="functori">Functori</h2>
<p>Nella sezione <a href="#template">Usare i template al posto di gerarchie di classi</a> ho mostrato che i <code>template</code> permettono di evitare la creazione di gerarchie di classi e l’uso del polimorfismo quando si devono implementare algoritmi che agiscono su <em>funzioni</em>.</p>
<p>L’approccio che usa i <code>template</code> può essere facilmente applicato a oggetti derivati da <code>FunzioneBase</code> o <code>FunzioneVettorialeBase</code> usando i cosiddetti “functori” (orribile anglicismo, il termine originale è <em>functor</em>).</p>
<p>Riprendiamo l’implementazione di <code>midpoint()</code> vista sopra:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> midpoint<span class="op">(</span><span class="kw">auto</span> fn<span class="op">,</span> <span class="dt">double</span> a<span class="op">,</span> <span class="dt">double</span> b<span class="op">,</span> <span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> accum<span class="op">{};</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">{};</span> i <span class="op"><</span> n<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> x<span class="op">{</span>a <span class="op">+</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">*</span> <span class="op">(</span><span class="dv">2</span> <span class="op">*</span> i <span class="op">+</span> <span class="dv">1</span><span class="op">)</span> <span class="op">/</span> <span class="op">(</span><span class="dv">2</span> <span class="op">*</span> n<span class="op">)};</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a> accum <span class="op">+=</span> fn<span class="op">(</span>x<span class="op">);</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> accum <span class="op">*</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">/</span> n<span class="op">;</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Abbiamo visto che con questa definizione è possibile passare direttamente funzioni senza bisogno di creare classi derivate da <code>FunzioneBase</code>:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> myfn<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x <span class="op">*</span> x <span class="op">-</span> <span class="dv">3</span> <span class="op">*</span> x <span class="op">+</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"The integral is </span><span class="sc">{}\n</span><span class="st">"</span><span class="op">,</span> midpoint<span class="op">(</span>myfn<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">10</span><span class="op">));</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Però ogni tanto potrebbe essere comodo invece usare le classi: ad esempio quando la funzione dipende da parametri, come nel caso in cui voglia esprimere una generica parabola <span class="math inline">f(x) = ax^2 + bx + c</span>. Con il vecchio approccio basato sugli oggetti, è banale farlo: nel caso della parabola, basta creare una classe che abbia tre variabili membro <code>a</code>, <code>b</code> e <code>c</code>. Ecco un esempio in C++:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="co">// We use `struct` so that everything is `public` by default</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Parabola <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> a<span class="op">,</span> b<span class="op">,</span> c<span class="op">;</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// No need to create a constructor, the compiler will do it for us</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> a <span class="op">*</span> x <span class="op">*</span> x <span class="op">+</span> b <span class="op">*</span> x <span class="op">+</span> c<span class="op">;</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a> Parabola par1<span class="op">{</span><span class="fl">1.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="fl">3.0</span><span class="op">};</span> <span class="co">// x² + 2x + 3</span></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a> Parabola par2<span class="op">{</span><span class="fl">2.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="op">-</span><span class="fl">1.0</span><span class="op">};</span> <span class="co">// 2x² - 1</span></span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// ..</span></span>
<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Una funzionalità del genere è comoda, ma non funziona con la definizione <code>template</code> di <code>midpoint()</code>, perché per valutare <code>par1</code> nel punto <span class="math inline">x = 3</span> bisogna scrivere <code>par1.Eval(3.0)</code>, mentre <code>midpoint()</code> non si aspetta di invocare un metodo <code>Eval</code>: se le si passasse <code>par1</code>, per com’è fatta la versione <code>template</code> di <code>midpoint()</code> riscriverebbe la riga <code>accum += fn(x)</code> come <code>accum += par1(x)</code> anziché <code>accum += par1.Eval(x)</code>, e il compilatore darebbe errore.</p>
<p>Si può risolvere il problema trasformando <code>Parabola</code> in un <em>functore</em>, ossia in una classe che “finge” di essere una funzione. Questo è possibile facendo l’overloading di <code>operator()</code>:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co">// We use `struct` so that everything is `public` by default</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Parabola <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> a<span class="op">,</span> b<span class="op">,</span> c<span class="op">;</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> a <span class="op">*</span> x <span class="op">*</span> x <span class="op">+</span> b <span class="op">*</span> x <span class="op">+</span> c<span class="op">;</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// This operator makes the class a “functor”</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> <span class="kw">operator</span><span class="op">()(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="op">{</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> Eval<span class="op">(</span>x<span class="op">);</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Nel nostro esempio, <code>operator()</code> non fa altro che invocare internamente <code>Eval</code>, ed è quindi del tutto equivalente. Ma ora si può usare qualsiasi oggetto <code>Parabola</code> come se fosse una funzione:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a> Parabola par1<span class="op">{</span><span class="fl">1.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="fl">3.0</span><span class="op">};</span> <span class="co">// x² + 2x + 3</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a> Parabola par2<span class="op">{</span><span class="fl">2.0</span><span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="op">-</span><span class="fl">1.0</span><span class="op">};</span> <span class="co">// 2x² - 1</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// par1 looks like a function, but it's a class!</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"par1 in x = 3 is </span><span class="sc">{}</span><span class="st">"</span><span class="op">,</span> par1<span class="op">(</span><span class="fl">3.0</span><span class="op">));</span></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// The same for par2</span></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"par2 in x = 3 is </span><span class="sc">{}</span><span class="st">"</span><span class="op">,</span> par2<span class="op">(</span><span class="fl">3.0</span><span class="op">));</span></span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Con la definizione di <code>operator()</code>, gli oggetti <code>Parabola</code> possono essere passati alla nostra versione di <code>midpoint()</code> che usa i <code>template</code>:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>Parabola par<span class="op">{</span><span class="fl">1.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="fl">3.0</span><span class="op">};</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>cout <span class="op"><<</span> midpoint<span class="op">(</span>par<span class="op">,</span> <span class="fl">0.0</span><span class="op">,</span> <span class="fl">2.0</span><span class="op">,</span> <span class="dv">50</span><span class="op">)</span> <span class="op"><<</span> <span class="st">"</span><span class="sc">\n</span><span class="st">"</span><span class="op">;</span></span></code></pre></div>
<p>Dal momento che <code>Parabola</code> è comunque una classe derivata da <code>FunzioneBase</code>, essa può essere passata anche a tutte quelle funzioni che avevate definito negli esercizi e che usano la programmazione ad oggetti.</p>
<h1 id="temaA">Tema 1 (stima di integrali)</h1>
<p>Questo è il link per aprire il testo: <a href="https://labtnds.docs.cern.ch/ProveEsame/AppelloTNDS_1.pdf" class="uri">https://labtnds.docs.cern.ch/ProveEsame/AppelloTNDS_1.pdf</a></p>
<p>Si tratta di un tema molto articolato, con ben sette punti, ma ciascuno di questi è abbastanza veloce da implementare.</p>
<h2 id="letturaTestoA">Lettura del testo</h2>
<p>Uno dei consigli più importanti forniti nella sezione <a href="index.html#esamescritto">Come prepararsi all’esame scritto</a> è quello di leggere il testo da cima a fondo prima di iniziare a scrivere del codice: è necessario infatti capire se ci sono più punti che possono essere svolti in modo simile, o delle peculiarità che richiedono di impostare il codice in un certo modo.</p>
<p>In questo primo tema mostrerò come si legge un tema in modo “evoluto”; potreste restarne spaventati, ma non temete! Nei temi successivi mostrerò una serie di tecniche operative che vi permetteranno di imparare a fare questo lavoro essenziale.</p>
<p>Vediamo quindi come fare per leggere i sette punti di questo tema in modo corretto.</p>
<blockquote>
<p>Si stimi il valore di questo integrale con il metodo del punto medio (“midpoint”). Sapendo che il valore vero dell’integrale è <span class="math inline">3e^2/16</span>, costruire una tabella o un grafico in cui si mostra l’andamento dell’errore per un numero di punti che va da 2 a 1024 in potenze di 2.</p>
</blockquote>
<p>Si dovrebbe quindi già capire qui che sarà necessario recuperare il codice dell’<a href="carminati-esercizi-07.html#esercizio-7.0">esercizio 7.0</a>, dove si è implementato il metodo del punto medio. Nella lezione di teoria si è discusso come stimare l’errore nel caso in cui non sia noto il valore esatto dell’integrale, ma qui siamo facilitati, perché il valore vero viene dato già nel testo: <span class="math inline">3e^2/16</span>. (C’era da aspettarselo: in un tema d’esame con ben sette domande, sarebbe molto strano trovare richieste complicate già al primo punto!)</p>
<p>Dovremo stampare “una tabella o un grafico”; è <em>sempre</em> buona cosa stampare la tabella, anche nel caso in cui producete il grafico. Ovviamente, già ci dobbiamo aspettare che l’errore diminuisca man mano che il numero di punti cresce.</p>
<p>Procediamo ora con la lettura del secondo punto:</p>
<blockquote>
<p>Assumendo che l’errore scali con una legge del tipo <span class="math inline">\varepsilon = k_1 h^{k_2}</span>, dove <span class="math inline">h</span> è la dimensione del passo di integrazione, stimare i valori dei coefficienti <span class="math inline">k_1</span> e <span class="math inline">k_2</span>.</p>
</blockquote>
<p>Leggendo questo punto, ci rendiamo conto che nel punto precedente sarà bene non limitarsi a stampare la tabella, ma fare anche il grafico: il testo infatti qui ci dice che l’andamento dell’errore, se plottato in scala logaritmica, deve seguire una retta della forma <span class="math inline">y = m x + q</span>, con <span class="math inline">y = \log\varepsilon</span>, <span class="math inline">x = \log h</span>, pendenza <span class="math inline">m = k_2</span> e intercetta <span class="math inline">q = \log k_1</span>.</p>
<p>(Questo può essere un buon momento per prendere un foglio di brutta e fare un paio di calcoli per ridurre espressioni come <span class="math inline">\varepsilon = k_1 h^{k_2}</span> e capire se si vorrà usare una scala lineare, o logaritmica sulle x, o sulle y, o come nel caso di questo esercizio specifico <strong>bilogaritmica</strong>…).</p>
<p>Passiamo al terzo punto:</p>
<blockquote>
<p>A partire dal metodo del punto medio si aggiunga un nuovo metodo di integrazione (“midright”) che invece di considerare il valore della funzione nel punto medio di un intervallo, la valuti nell’estremo di destra. Si stimi il valore del medesimo integrale con il nuovo metodo di integrazione. Come nel caso precedente sapendo che il valore vero dell’integrale è <span class="math inline">3e^2/16</span>, costruire una tabella o un grafico in cui si mostra l’andamento dell’errore per un numero di punti che va da 2 a 1024 in potenze di 2.</p>
</blockquote>
<p>Qui le cose si fanno interessanti… Dovremo quindi riprendere la nostra implementazione dell’algoritmo del punto medio, farne un copia-e-incolla e modificare questa copia in modo che anziché prendere il punto centrale prenda quello destro. (Sarebbe forse stato più appropriato chiamarlo “right-point” anziché “mid-right”, perché “mid” qui non c’entra, ma seguiamo il nome dato nel testo!)</p>
<p>Avremo quindi una nuova classe <code>MidRight</code>, derivata da <code>Integral</code> e modellata come la classe <code>MidPoint</code>, nel senso che il codice che implementa il metodo <code>MidRight::calculate()</code> sarà molto simile a <code>MidPoint::calculate()</code>, e differirà solo nel calcolo del valore in cui valutare l’integranda. Non abbiamo ancora iniziato a scrivere il codice (stiamo ancora leggendo il testo!), ma nella nostra mente potrebbe iniziare ad apparire il vago profilo di una classe fatta così:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> MidRight <span class="op">:</span> <span class="kw">public</span> Integral <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> calculate<span class="op">(</span><span class="dt">int</span> nstep<span class="op">,</span> FunzioneBase <span class="op">&</span>f<span class="op">)</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Et cetera...</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Notiamo subito che questo punto #3 del tema d’esame è molto simile al punto #1: persino i valori da usare nella tabella sono identici! L’unica cosa per cui lo svolgimento differisce è il metodo di integrazione: “midpoint” al punto #1, “midright” al punto #3. Questa osservazione ci suggerisce quindi di implementare una funzione dedicata a questo compito e chiamarla due volte nel <code>main()</code>. Smpre continuando ad immaginare il codice che scriveremo, potremmo pensare di fare una cosa così:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> <span class="dt">double</span> true_value<span class="op">{</span><span class="dv">3</span> <span class="op">*</span> exp<span class="op">(</span><span class="fl">2.0</span><span class="op">)</span> <span class="op">/</span> <span class="dv">16</span><span class="op">};</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> n<span class="op">{</span><span class="dv">2</span><span class="op">};</span> n <span class="op"><=</span> <span class="dv">1024</span><span class="op">;</span> n <span class="op">*=</span> <span class="dv">2</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Usa `integral` per calcolare l'integrale</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// Confronta l'integrale con il valore di `true_value`</span></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a> <span class="co">// Stampa l'errore a video</span></span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>e poi ovviamente immaginiamo di usare questa ipotetica <code>calculate_errors()</code> nel <code>main()</code>, più o meno così:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Svolgimento punto 1:</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a> MidPoint midpoint<span class="op">{};</span></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a> calculate_errors<span class="op">(</span>midpoint<span class="op">);</span> <span class="co">// Qui dico di integrare col midpoint</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Svolgimento punto 2:</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Svolgimento punto 3:</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a> MidRight midright<span class="op">{};</span></span>
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a> calculate_errors<span class="op">(</span>midright<span class="op">);</span> <span class="co">// Qui dico di integrare col midright</span></span>
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// Et cetera…</span></span>
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Attenzione! Ripeto ancora una volta che non stiamo ancora scrivendo del codice, questi frammenti di C++ stanno ancora nella vostra testa, oppure ancora meglio sul vostro foglio di brutta! Non scriviamo ancora nulla perché non abbiamo ancora terminato di leggere il testo della prova d’esame, e non sappiamo se una funzione come <code>calculate_errors()</code> farà al caso nostro. E infatti, se leggiamo il punto 4, facciamo una scoperta interessante:</p>
<blockquote>
<p>Assumendo che l’errore scali con una legge del tipo <span class="math inline">\varepsilon = k_1 h^{k_2}</span>, dove <span class="math inline">h</span> è la dimensione del passo di integrazione, stimare i valori dei coefficienti <span class="math inline">k_1</span> e <span class="math inline">k_2</span>.</p>
</blockquote>
<p>Il punto #4 è esattamente identico al #2, parola per parola! Questo vuol dire che la nostra funzione <code>calculate_errors</code> che avevamo immaginato sopra andrebbe estesa in modo che non si limiti a stampare la tabella (punto #1 e punto #3), ma anche a calcolare i coefficienti <span class="math inline">k_1</span> e <span class="math inline">k_2</span> (punto #2 e punto #4).</p>
<p>Nella nostra testa (o nei nostri appunti), <code>calculate_errors</code> si trasforma quindi in qualcosa del genere</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> <span class="dt">double</span> true_value<span class="op">{</span><span class="dv">3</span> <span class="op">*</span> exp<span class="op">(</span><span class="fl">2.0</span><span class="op">)</span> <span class="op">/</span> <span class="dv">16</span><span class="op">};</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Salviamo tutti i valori di h e gli errori in due vettori</span></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> step_size<span class="op">{};</span></span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> error<span class="op">{};</span></span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> n<span class="op">{</span><span class="dv">2</span><span class="op">};</span> n <span class="op"><=</span> <span class="dv">1024</span><span class="op">;</span> n <span class="op">*=</span> <span class="dv">2</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> cur_h<span class="op">{(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">/</span> n<span class="op">};</span></span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a> <span class="co">// Usa `integral` per calcolare l'integrale</span></span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// Confronta l'integrale con il valore di `true_value`</span></span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// Stampa l'errore a video</span></span>
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a> <span class="co">// Aggiunge il valore di `h` a `step_size` e l'errore a `error`</span></span>
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true" tabindex="-1"></a> step_size<span class="op">.</span>push_back<span class="op">(</span>cur_h<span class="op">);</span></span>
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true" tabindex="-1"></a> error<span class="op">.</span>push_back<span class="op">(</span>error<span class="op">);</span></span>
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a> <span class="co">// Ora eseguiamo una interpolazione sui valori che abbiamo salvato in</span></span>
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a> <span class="co">// `step_size` ed `error`</span></span>
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-29"><a href="#cb30-29" aria-hidden="true" tabindex="-1"></a> <span class="co">// Stampiamo i valori di k₁ e k₂</span></span>
<span id="cb30-30"><a href="#cb30-30" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb30-31"><a href="#cb30-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Se finora abbiamo immaginato tutto il codice nella testa, ormai le cose da considerare stanno diventando decisamente troppe: meglio tirare fuori quel famoso foglio di brutta e iniziare davvero a scrivere… Anche perché ci siamo dimenticati di una cosa: il grafico! Abbiamo detto che è importante verificare che su scala bilogaritmica l’andamento dell’errore sia lineare!</p>
<p>È sempre bene creare i grafici in file PNG anziché mostrarli a video: potete navigare tra di essi più facilmente, se usate Replit è più veloce visualizzarli, e potete salvare copie di backup se state per fare modifiche al codice e volete confrontare i risultati prima o dopo. In tal caso, la funzione <code>calculate_errors</code> deve accettare un nuovo parametro, che contiene il nome del file PNG in cui sarà salvato il grafico:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... (tutto identico a prima, fino alla fine) ...</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...ma prima di terminare creiamo il grafico</span></span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a> Gnuplot plt<span class="op">{};</span></span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>redirect_to_png<span class="op">(</span>png_file_name<span class="op">);</span></span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>plot<span class="op">(</span>step_size<span class="op">,</span> error<span class="op">);</span></span>
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>set_xlabel<span class="op">(</span><span class="st">"Step size h"</span><span class="op">);</span></span>
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>set_ylabel<span class="op">(</span><span class="st">"Error"</span><span class="op">);</span></span>
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>set_logscale<span class="op">(</span>Gnuplot<span class="op">::</span>AxisScale<span class="op">::</span>LOGXY<span class="op">);</span></span>
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a> plt<span class="op">.</span>show<span class="op">();</span></span>
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Il fatto che il nome del file PNG sia passato come argomento ci permetterà di chiamare più volte nel <code>main()</code> la funzione <code>calculate_errors()</code>, senza che il file PNG venga sovrascritto a ogni chiamata. Questa è una tecnica che seguiremo in tutti i temi d’esame che svolgeremo in questa pagina.</p>
<p>Veniamo ora al punto 5:</p>
<blockquote>
<p>Stimare l’errore nel calcolo del medesimo integrale utilizzando il metodo della media con un numero di estrazioni pari a 16 ripetendo il calcolo un migliaio di volte.</p>
</blockquote>
<p>Bene, giunti a questo punto del compito dovremo quindi recuperare l’<a href="carminati-esercizi-10.html#esercizio-10.2">esercizio 10.2</a> sul calcolo dell’integrale col metodo della media. Non dovrebbero esserci complicazioni, si tratta semplicemente di implementare un ciclo <code>for</code> e poi calcolare l’errore: possiamo usare la funzione per calcolare la deviazione standard (o la varianza, ma in questo caso dovremo poi estrarre la radice quadrata) che avevamo implementato nell’<a href="carminati-esercizi-03.html#esercizio-3.1">esercizio 3.1</a>.</p>
<blockquote>
<p>Quanti punti sarebbero necessari per ottenere con il metodo della media la stessa precisione che si ottiene con il metodo del “midpoint” tradizionale a 16 punti?</p>
</blockquote>
<p>Qui si vede se gli studenti hanno studiato o no la teoria: com’è legato l’errore nel metodo della media al numero <span class="math inline">N</span> dei punti? Se si conosce la formula, basta fare un paio di calcoli su un foglio di brutta per trovare la formula matematica che dà la soluzione e implementarla nel proprio codice C++.</p>
<p>C’è però un piccolo dettaglio che non dobbiamo farci sfuggire. Per fare questo calcolo, ci occorre che il programma “ricordi” l’errore associato al metodo del mid-point che aveva trovato per il caso <span class="math inline">N = 16</span> nello svolgimento del punto #1.</p>
<p>Ci sono vari modi per fare questo:</p>
<ol>
<li><p>Il più facile è quello di eseguire il nostro programma una volta che i punti #1 e #2 sono implementati e corretti, annotarsi su un foglio l’errore calcolato nel caso <span class="math inline">N = 16</span> passaggi, e poi inserire brutalmente questo numero nella sezione del codice C++ che svolge questo punto #6.</p>
<p>Questo procedimento però è orribile! Se, una volta implementato il codice, ci accorgessimo prima di consegnare che c’era un errore nello svolgimento del punto #1 e riuscissimo a correggerlo, rischieremmo di dimenticarci di aggiornare il valore corrispondente qui!</p></li>
<li><p>Sarebbe allora meglio che la funzione <code>calculate_errors()</code> non ritorni un tipo <code>void</code>, ma proprio l’errore associato al caso <span class="math inline">N = 16</span>:</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Ho cambiato il tipo di ritorno da `void` a `double`</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> error_to_return<span class="op">{};</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> n <span class="op">=</span> <span class="dv">2</span><span class="op">;</span> n <span class="op"><=</span> <span class="dv">1024</span><span class="op">;</span> n <span class="op">*=</span> <span class="dv">2</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// Calcolo l'errore...</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...ed ora lo salvo</span></span>
<span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span><span class="op">(</span>n <span class="op">==</span> <span class="dv">16</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a> error_to_return <span class="op">=</span> cur_error<span class="op">;</span></span>
<span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// Creo e salvo il grafico</span></span>
<span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb32-18"><a href="#cb32-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// Restituisco l'errore associato al valore N=16</span></span>
<span id="cb32-20"><a href="#cb32-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> error_to_return<span class="op">;</span></span>
<span id="cb32-21"><a href="#cb32-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Nel <code>main()</code> quindi salverei l’errore restituito per lo svolgimento del punto #1 e lo userei poi quando è il tempo di risolvere il punto #6. (Se uno è elegante, può passare il valore <code>16</code> come parametro aggiuntivo di <code>calculate_errors()</code>).</p></li>
<li><p>La soluzione più consigliabile però è quella di far restituire a <code>calculate_errors()</code> l’intera tabella calcolata. È vero che nel punto #6 ci serve solo l’errore per <span class="math inline">N = 16</span>, ma avere a disposizione tutta la tabella ci può permettere rapidamente di usare dei <code>print</code> per fare debug nel <code>main()</code>, nel caso in cui il risultato del punto #6 ci sembrasse strano.</p>
<p>Proprio nell’ottica di aiutarci a fare debug, potremmo restituire queste quantità:</p>
<ol>
<li>I valori di <span class="math inline">N</span>;</li>
<li>I valori di <span class="math inline">h</span>;</li>
<li>I valori degli integrali calcolati;</li>
<li>Gli errori;</li>
<li>I valori di <span class="math inline">k_1</span> e <span class="math inline">k_2</span> nella formula dell’errore interpolato.</li>
</ol>
<p>Vorremmo restituire tutti questi valori alla fine della funzione <code>calculate_errors()</code>, ma c’è un problema: il C++ permette di restituire solo <em>un</em> valore!</p>
<p>La classica soluzione è quella di implementare una <code>struct</code> (vedi il <a href="#uso-di-struct">suggerimento</a>):</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ErrorTable <span class="op">{</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> num_of_steps<span class="op">{};</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> step_size<span class="op">{};</span></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> value<span class="op">{};</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> error<span class="op">{};</span></span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> k1<span class="op">{};</span></span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> k2<span class="op">{};</span></span>
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>e usare questa definizione per <code>calculate_errors</code>:</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>ErrorTable calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a> ErrorTable result<span class="op">;</span></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Fai i calcoli e riempi la variabile `result`</span></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result<span class="op">;</span></span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div></li>
</ol>
<p>In questo modo potremo poi nel <code>main()</code> recuperare l’errore per il caso <span class="math inline">N = 16</span> facilmente.</p>
<p>Sarebbe anche meglio racchiudere l’implementazione del punto #5 in una funzione che accetti il numero <code>N</code> come input, in modo da poterla poi invocare per il punto #6 con il nuovo numero di punti e verificare così il risultato. Annotiamo quindi sul foglio di carta che dovremo implementare una funzione con questo prototipo:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> run_integral_mc_mean<span class="op">(</span><span class="dt">int</span> N<span class="op">)</span> <span class="op">{</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>La funzione dovrà ovviamente restituire la deviazione standard dei 1000 campioni, ossia l’errore associato alla stima dell’integrale, in modo da poter implementare il punto #6 sulla base del risultato del punto #5.</p>
<blockquote>
<p>Si consideri ora il seguente integrale: [nuovo integrale]. Si provi a calcolarne il valore utilizzando uno dei due metodi (“midpoint” o “midright”) indicati sopra: quale usereste? Quanto vale il coefficiente <span class="math inline">k_2</span> in questo caso ?</p>
</blockquote>
<p>Di solito l’ultimo punto è “per la lode”, e richiede un po’ di lavoro in più. Qui dobbiamo abbandonare l’integrale che abbiamo usato nei sei punti precedenti e usarne uno nuovo, quindi si richiedono alcuni accorgimenti:</p>
<ol>
<li><p>Se abbiamo definito il valore vero del primo integrale (<span class="math inline">3e^2/16</span>) in una costante chiamata <code>true_value</code>, sarebbe bene rinominare quella costante <code>true_value1</code>, in modo da poter poi definire una nuova costante <code>true_value2</code> anche per questo secondo integrale. (Il testo non dice quanto vale, ma è facile calcolarlo).</p></li>
<li><p>La nostra funzione <code>calculate_errors()</code> accettava come unico parametro la classe che implementa il metodo di integrazione, perché a seconda del punto a cui stiamo rispondendo si vuole passare un’istanza della classe <code>MidPoint</code> o della classe <code>MidRight</code>. Quella funzione fa al caso nostro anche per il punto #7, ma dobbiamo modificarla in modo che anche la funzione da integrare sia passata come argomento:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Passo come argomenti sia l'algoritmo di integrazione che l'integranda</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>ErrorTable</span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> FunzioneBase <span class="op">&</span> fn<span class="op">,</span></span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div></li>
<li><p>Pensandoci meglio, come fa <code>calculate_errors</code> a calcolare l’errore, se il valore vero dell’integrale è diverso a seconda dell’integrale? Dovremmo passare anche il valore vero a <code>calculate_errors</code>:</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Passo sia l'integrale che la funzione da integrare, che il valore atteso!</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>ErrorTable</span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a>calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span></span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> FunzioneBase <span class="op">&</span> fn<span class="op">,</span></span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> true_value<span class="op">,</span></span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div></li>
</ol>
<p>Phew! Abbiamo terminato la lettura del testo, e ci siamo fatti un’idea del lavoro richiesto. Possiamo ora passare all’implementazione.</p>
<h2 id="temaApuntoA">Implementazione del punto 1</h2>
<p>Iniziamo col definire una serie di costanti che corrispondono ai parametri che compaiono nel testo:</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><numbers></span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">;</span></span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a><span class="co">// Costante di Nepero</span></span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> e<span class="op">{</span>numbers<span class="op">::</span>e<span class="op">};</span></span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a><span class="co">// Estremi di integrazione</span></span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> a<span class="op">{</span><span class="fl">0.0</span><span class="op">};</span></span>
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> b<span class="op">{</span>exp<span class="op">(</span><span class="fl">0.5</span><span class="op">)};</span></span>
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a><span class="co">// Valore vero del primo integrale</span></span>
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> true_value1<span class="op">{</span><span class="dv">3</span> <span class="op">*</span> exp<span class="op">(</span><span class="fl">2.0</span><span class="op">)</span> <span class="op">/</span> <span class="dv">16</span><span class="op">};</span></span>
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true" tabindex="-1"></a><span class="co">// Valore vero del secondo integrale; l'integranda può essere riscritta</span></span>
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a><span class="co">// tramite un cambio di variabile come 1/√(1 - y²), che è la derivata</span></span>
<span id="cb38-17"><a href="#cb38-17" aria-hidden="true" tabindex="-1"></a><span class="co">// di arcsin(y). Se non ci arrivate, potete usare Wolfram Alpha da browser</span></span>
<span id="cb38-18"><a href="#cb38-18" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> true_value2<span class="op">{</span>numbers<span class="op">::</span>pi <span class="op">/</span> <span class="dv">2</span><span class="op">};</span></span></code></pre></div>
<p>Nel caso in cui non sappiate calcolare il valore del secondo integrale, potete usare il sito <a href="https://www.wolframalpha.com/">WolframAlpha</a>:</p>
<p><img src="images/exam1-wolfram-alpha-integral2.png" /></p>
<p>Passiamo ora ad implementare la funzione integranda. Se usiamo l’approccio di derivare una classe da <a href="carminati-esercizi-06.html#esercizio-6.1"><code>FunzioneBase</code></a>, la nostra sarà fatta così:</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Funzione1 <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> x_squared<span class="op">{</span>x <span class="op">*</span> x<span class="op">};</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> x_squared <span class="op">*</span> x <span class="op">*</span> log<span class="op">(</span>sqrt<span class="op">(</span>e <span class="op">+</span> x_squared<span class="op">));</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Un errore che compiono spesso gli studenti è quello di non verificare che le funzioni date nel testo siano implementate bene in C++. Si tratta di funzioni a volte complesse, dove è facile chiudere la parentesi nel posto sbagliato. Implementiamo alcuni test per essere certi che <code>Funzione1</code> operi come deve:</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> are_close<span class="op">(</span><span class="dt">double</span> a<span class="op">,</span> <span class="dt">double</span> b<span class="op">,</span> <span class="dt">double</span> eps <span class="op">=</span> <span class="fl">1.0e-7</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> abs<span class="op">(</span>a <span class="op">-</span> b<span class="op">)</span> <span class="op"><</span> eps<span class="op">;</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_code<span class="op">()</span> <span class="op">{</span></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a> Funzione1 fun1<span class="op">;</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// I valori attesi sono calcolabili a mano</span></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>fun1<span class="op">.</span>Eval<span class="op">(</span><span class="fl">0.0</span><span class="op">),</span> <span class="fl">0.0</span><span class="op">));</span></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>fun1<span class="op">.</span>Eval<span class="op">(</span><span class="fl">1.0</span><span class="op">),</span> <span class="fl">0.5</span> <span class="op">*</span> log<span class="op">(</span>e <span class="op">+</span> <span class="dv">1</span><span class="op">)));</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>fun1<span class="op">.</span>Eval<span class="op">(</span><span class="fl">2.0</span><span class="op">),</span> <span class="fl">8.0</span> <span class="op">*</span> log<span class="op">(</span>sqrt<span class="op">(</span>e <span class="op">+</span> <span class="fl">4.0</span><span class="op">))));</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a> cerr <span class="op"><<</span> <span class="st">"All the tests passed. Hurrah!</span><span class="sc">\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Veniamo ora al “cuore” del punto #1. Riguardando i nostri appunti, vediamo che abbiamo stabilito di implementare sia il punto #1 che il punto #2 in una funzione <code>calculate_errors()</code>. Seguiamo quindi il prototipo che avevamo stabilito per implementarla, ricordando che dovremo riempire una variabile di tipo <code>ErrorTable</code> in modo da poterla restituire ed impiegarla nel <code>main()</code>:</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a>ErrorTable</span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a>calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span></span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> FunzioneBase <span class="op">&</span> fn<span class="op">,</span></span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> true_value<span class="op">,</span></span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a> ErrorTable results<span class="op">;</span></span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> n <span class="op">=</span> <span class="dv">2</span><span class="op">;</span> n <span class="op"><=</span> <span class="dv">1024</span><span class="op">;</span> n <span class="op">*=</span> <span class="dv">2</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>num_of_steps<span class="op">.</span>push_back<span class="op">(</span>n<span class="op">);</span></span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> h<span class="op">{(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">/</span> n<span class="op">};</span></span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>step_size<span class="op">.</span>push_back<span class="op">(</span>h<span class="op">);</span></span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> cur_value<span class="op">{</span>integral<span class="op">.</span>integrate<span class="op">(</span>a<span class="op">,</span> b<span class="op">,</span> n<span class="op">,</span> fn<span class="op">)};</span></span>
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>value<span class="op">.</span>push_back<span class="op">(</span>cur_value<span class="op">);</span></span>
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> cur_error<span class="op">{</span>abs<span class="op">(</span>cur_value <span class="op">-</span> true_value<span class="op">)};</span></span>
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>error<span class="op">.</span>push_back<span class="op">(</span>cur_error<span class="op">);</span></span>
<span id="cb41-19"><a href="#cb41-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true" tabindex="-1"></a> <span class="co">// Vedi più sotto</span></span>
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>print_table<span class="op">();</span></span>
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-24"><a href="#cb41-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> results<span class="op">;</span></span>
<span id="cb41-25"><a href="#cb41-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Per stampare i valori, avremmo potuto inserire direttamente il codice in <code>calculate_errors</code>; però questa è effettivamente una funzionalità che appartiene alla classe <code>ErrorTable</code>, così scegliamo di implementarla come metodo (che, essendo la classe stata definita tramite la parola chiave <code>struct</code>, è di default pubblico e quindi invocabile da chichessia):</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ErrorTable <span class="op">{</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> num_of_steps<span class="op">{};</span></span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> step_size<span class="op">{};</span></span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> value<span class="op">{};</span></span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> error<span class="op">{};</span></span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> k1<span class="op">{};</span></span>
<span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> k2<span class="op">{};</span></span>
<span id="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a> <span class="co">/// Output the table with the errors to `cout`</span></span>
<span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> print_error_table<span class="op">()</span> <span class="op">{</span></span>
<span id="cb42-12"><a href="#cb42-12" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"Error table:</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb42-13"><a href="#cb42-13" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"</span><span class="sc">{:>6s}\t{:>20s}\t{:>20s}\t{:>20s}\t{:>20s}</span><span class="st">"</span><span class="op">,</span> <span class="st">"N"</span><span class="op">,</span> <span class="st">"h"</span><span class="op">,</span></span>
<span id="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a> <span class="st">"Value"</span><span class="op">,</span> <span class="st">"Error"</span><span class="op">,</span> <span class="st">"Estimated error"</span><span class="op">);</span></span>
<span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">{};</span> i <span class="op"><</span> ssize<span class="op">(</span>step_size<span class="op">);</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> estimated_error<span class="op">{</span>interpolated_error<span class="op">(</span>step_size<span class="op">[</span>i<span class="op">])};</span></span>
<span id="cb42-17"><a href="#cb42-17" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"</span><span class="sc">{:6d}\t{:20.7e}\t{:20.7e}\t{:20.7e}\t{:20.7e}</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb42-18"><a href="#cb42-18" aria-hidden="true" tabindex="-1"></a> num_of_steps<span class="op">.</span>at<span class="op">(</span>i<span class="op">),</span> step_size<span class="op">.</span>at<span class="op">(</span>i<span class="op">),</span> value<span class="op">.</span>at<span class="op">(</span>i<span class="op">),</span></span>
<span id="cb42-19"><a href="#cb42-19" aria-hidden="true" tabindex="-1"></a> error<span class="op">.</span>at<span class="op">(</span>i<span class="op">),</span> estimated_error<span class="op">);</span></span>
<span id="cb42-20"><a href="#cb42-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb42-21"><a href="#cb42-21" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb42-22"><a href="#cb42-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb42-23"><a href="#cb42-23" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Ovviamente il codice fa uso della libreria <a href="index.html#fmtinstall">fmtlib</a> per stampare la tabella in un formato gradevole.</p>
<p>Dobbiamo ora implementare il <code>main</code>, che è banale:</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// Chiamiamo i test che verificano il codice che abbiamo scritto</span></span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a> test_code<span class="op">();</span></span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Stampiamo il valore vero dell'integrale, in modo da tenerlo sott'occhio</span></span>
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>print<span class="op">(</span></span>
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"True value of the integral between a=</span><span class="sc">{:.3f}</span><span class="st"> and b=</span><span class="sc">{:.3f}</span><span class="st">: </span><span class="sc">{:.5f}\n\n</span><span class="st">"</span><span class="op">,</span> a<span class="op">,</span></span>
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a> b<span class="op">,</span> true_value1<span class="op">);</span></span>
<span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Point #1</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-12"><a href="#cb43-12" aria-hidden="true" tabindex="-1"></a> Midpoint midpoint<span class="op">;</span></span>
<span id="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a> Function1 fun1<span class="op">;</span></span>
<span id="cb43-14"><a href="#cb43-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-15"><a href="#cb43-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// Salviamo il risultato in `midpoint_results`, perché sappiamo che</span></span>
<span id="cb43-16"><a href="#cb43-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// poi dovremo usarlo nello svolgimento del punto #6</span></span>
<span id="cb43-17"><a href="#cb43-17" aria-hidden="true" tabindex="-1"></a> ErrorTableResults midpoint_results<span class="op">{</span>calculate_errors<span class="op">(</span>midpoint<span class="op">,</span></span>
<span id="cb43-18"><a href="#cb43-18" aria-hidden="true" tabindex="-1"></a> fun1<span class="op">,</span> true_value1<span class="op">,</span></span>
<span id="cb43-19"><a href="#cb43-19" aria-hidden="true" tabindex="-1"></a> <span class="st">"point1.png"</span><span class="op">)};</span></span>
<span id="cb43-20"><a href="#cb43-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Et voilà, se compiliamo il codice, ecco l’output:</p>
<pre><code>All the tests passed. Hurrah!
True value of the integral between a=0.000 and b=1.649: 1.38545
# Point #1
Error table:
N h Value Error Estimated error
2 8.2436064e-01 1.1577259e+00 2.2772215e-01 2.2772215e-01
4 4.1218032e-01 1.3273320e+00 5.8116025e-02 5.7101881e-02
8 2.0609016e-01 1.3708484e+00 1.4599573e-02 1.4318435e-02
16 1.0304508e-01 1.3817938e+00 3.6542570e-03 3.5903821e-03
32 5.1522540e-02 1.3845342e+00 9.1383628e-04 9.0029700e-04
64 2.5761270e-02 1.3852195e+00 2.2847606e-04 2.2575165e-04
128 1.2880635e-02 1.3853909e+00 5.7120077e-05 5.6607773e-05
256 6.4403175e-03 1.3854337e+00 1.4280086e-05 1.4194536e-05
512 3.2201587e-03 1.3854444e+00 3.5700255e-06 3.5593142e-06
1024 1.6100794e-03 1.3854471e+00 8.9250664e-07 8.9250664e-07</code></pre>
<p>ed ecco il grafico:</p>
<p><img src="images/exam1-point1.png" /></p>
<p>L’andamento su scala bilogaritmica è effettivamente lineare, e l’errore decrescere man mano che decresce il passo <span class="math inline">h</span>: ottimo!</p>
<h2 id="temaApuntoB">Implementazione del punto 2</h2>
<p>Per implementare il punto #2, nei nostri appunti avevamo scritto di modificare la funzione <code>calculate_errors</code>, che ora dovrà implementare alcune istruzioni aggiuntive dopo aver calcolato la tabella, per inizializzare le variabili <code>k1</code> e <code>k2</code> della classe <code>ErrorTable</code>:</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a>ErrorTable</span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>calculate_errors<span class="op">(</span><span class="at">const</span> Integral <span class="op">&</span> integral<span class="op">,</span></span>
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> FunzioneBase <span class="op">&</span> fn<span class="op">,</span></span>
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> true_value<span class="op">,</span></span>
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a> string png_file_name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// Tutto il ciclo `for` resta identico</span></span>
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// Calcola k1 e k2, la implementeremo tra un attimo</span></span>
<span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>calculate_k1_and_k2<span class="op">();</span></span>
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-12"><a href="#cb45-12" aria-hidden="true" tabindex="-1"></a> results<span class="op">.</span>print_error_table<span class="op">();</span></span>
<span id="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-14"><a href="#cb45-14" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>println<span class="op">(</span><span class="st">"k₁ = </span><span class="sc">{:.2f}</span><span class="st">, k₂ = </span><span class="sc">{:.2f}</span><span class="st">"</span><span class="op">,</span> results<span class="op">.</span>k1<span class="op">,</span> results<span class="op">.</span>k2<span class="op">);</span></span>
<span id="cb45-15"><a href="#cb45-15" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb45-16"><a href="#cb45-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-17"><a href="#cb45-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> results<span class="op">;</span></span>
<span id="cb45-18"><a href="#cb45-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Per calcolare <span class="math inline">k_1</span> e <span class="math inline">k_2</span>, dobbiamo ricordare che il testo dice di interpolare il passo <span class="math inline">h</span> e l’errore <span class="math inline">\varepsilon</span> con la formula <span class="math inline">\varepsilon = k_1 \cdot h^{k_2}</span>. Possiamo interpolare tra il primo punto (che chiamiamo <span class="math inline">a</span>) e l’ultimo punto (che chiamiamo <span class="math inline">b</span>), considerando che il grafico rivela un andamento approssimativamente lineare su scala logaritmica: <span class="math display">
\begin{cases}
\varepsilon_a = k_1 \cdot h_a^{k_2},\\
\varepsilon_b = k_1 \cdot h_b^{k_2},\\
\end{cases}
</span> e facendone il rapporto per semplificare <span class="math inline">k_1</span> si ottiene <span class="math display">
\frac{\varepsilon_a}{\varepsilon_b} = \left(\frac{h_a}{h_b}\right)^{k_2}\quad\Rightarrow\quad k_2 = \frac{\log\bigl(\varepsilon_b / \varepsilon_a\bigr)}{\log\bigl(h_b / h_a\bigr)}.\\
</span> da cui è ora facile ricavare <span class="math inline">k_1</span>: <span class="math display">
k_1 = \frac{\varepsilon_a}{h_a^{k_2}}.
</span></p>
<p>Implementiamo quindi il metodo <code>ErrorTable.calculate_k1_and_k2()</code>:</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> ErrorTable <span class="op">{</span></span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span> calculate_k1_and_k2<span class="op">()</span> <span class="op">{</span></span>
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// Usiamo il primo e l'ultimo valore della tabella per calcolare</span></span>
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// un'interpolazione lineare sulla scala bilogaritmica</span></span>
<span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a> k2 <span class="op">=</span> log<span class="op">(</span>error<span class="op">.</span>back<span class="op">()</span> <span class="op">/</span> error<span class="op">.</span>front<span class="op">())</span> <span class="op">/</span></span>
<span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a> log<span class="op">(</span>step_size<span class="op">.</span>back<span class="op">()</span> <span class="op">/</span> step_size<span class="op">.</span>front<span class="op">());</span></span>
<span id="cb46-10"><a href="#cb46-10" aria-hidden="true" tabindex="-1"></a> k1 <span class="op">=</span> error<span class="op">.</span>front<span class="op">()</span> <span class="op">/</span> pow<span class="op">(</span>step_size<span class="op">.</span>front<span class="op">(),</span> k2<span class="op">);</span></span>
<span id="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb46-12"><a href="#cb46-12" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Abbiamo usato qui i comodi metodi <code>front()</code> e <code>back()</code> della classe <code>std::vector</code>, che restituiscono il valore del primo e dell’ultimo elemento del vettore.</p>
<p>L’output che otteniamo appena sotto la tabella è il seguente:</p>
<pre><code>k₁ = 0.33, k₂ = 2.00</code></pre>
<p>che ci rassicura: <span class="math inline">k_2</span> è l’esponente del termine <span class="math inline">h</span>, e vediamo che il metodo del mid-point segue una legge <span class="math inline">\varepsilon \propto h^2</span>, che è quello che ci dovevamo aspettare, visto che conosciamo molto bene la teoria! 😉</p>
<h2 id="temaApuntoCD">Implementazione dei punti 3 e 4</h2>
<p>È necessario ora implementare il cosiddetto metodo del “mid-right”. Facciamo un copia-e-incolla della definizione della classe <code>MidPoint</code> dentro il nostro file <code>main.cpp</code>: è inutile creare un file <code>midright.h</code> e un file <code>midright.cpp</code>, e poi stare a impazzire aggiornando il <code>Makefile</code>…</p>
<p>Ricordate che nell’<a href="carminati-esercizi-07.html#esercizio-7.0">esercizio 7.0</a> avevamo implementato la classe <code>Integral</code> in modo che fosse da sovrascrivere il metodo privato <code>calculate</code>, e che potevamo assumere che gli estremi di integrazione <span class="math inline">a</span> e <span class="math inline">b</span> fossero già ordinati: <span class="math inline">a < b</span>. Questo ci torna utile: ora non dobbiamo fare alcun controllo su di essi né ricordarci di cambiare il segno all’integrale se necessario.</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> MidRight <span class="op">:</span> <span class="kw">public</span> Integral <span class="op">{</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> calculate<span class="op">(</span><span class="dt">int</span> nstep<span class="op">,</span> FunzioneBase <span class="op">&</span>f<span class="op">)</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> accum<span class="op">{};</span></span>
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">{};</span> i <span class="op"><</span> nstep<span class="op">;</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a> accum <span class="op">+=</span> f<span class="op">.</span>Eval<span class="op">(</span>a <span class="op">+</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">*</span> <span class="op">(</span>i <span class="op">+</span> <span class="dv">1</span><span class="op">)</span> <span class="op">/</span> n<span class="op">);</span></span>
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> accum <span class="op">*</span> <span class="op">(</span>b <span class="op">-</span> a<span class="op">)</span> <span class="op">/</span> n<span class="op">;</span></span>
<span id="cb48-10"><a href="#cb48-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb48-11"><a href="#cb48-11" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Dobbiamo però sincerarci che il metodo sia stato implementato correttamente. Abbiamo ancora la classe <code>Seno</code> implementata nell’<a href="carminati-esercizi-07.html#esercizio-7.0">esercizio 7.0</a>, così copiamola nel <code>main.cpp</code> e aggiungiamo un paio di test alla funzione <code>test_code()</code> che avevamo implementato prima. Col metodo del mid-right usando <span class="math inline">N = 1</span> si restituisce il valore della funzione sull’estremo destro <span class="math inline">x = b</span>, quindi <span class="math display">
\int_0^1 \sin x\,\mathrm{d}x \stackrel{N = 1}{\approx} \sin1.
</span> Con <span class="math inline">N = 2</span>, si restituisce invece la media tra il valore nella posizione centrale <span class="math inline">x = (a + b)/2</span> e l’estremo <span class="math inline">x = b</span>: <span class="math display">
\int_0^1 \sin x\,\mathrm{d}x \stackrel{N = 2}{\approx} \frac{\sin\frac12 + \sin1}2.
</span> Implementiamo quindi entrambi questi test, per essere sicuri che la nostra implementazione di <code>MidRight</code> funzioni bene:</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_code<span class="op">()</span> <span class="op">{</span></span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb49-4"><a href="#cb49-4" aria-hidden="true" tabindex="-1"></a> Seno seno<span class="op">{};</span></span>
<span id="cb49-5"><a href="#cb49-5" aria-hidden="true" tabindex="-1"></a> MidRight midright<span class="op">{};</span></span>
<span id="cb49-6"><a href="#cb49-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb49-7"><a href="#cb49-7" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>midright<span class="op">.</span>integrate<span class="op">(</span><span class="fl">0.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> seno<span class="op">),</span></span>
<span id="cb49-8"><a href="#cb49-8" aria-hidden="true" tabindex="-1"></a> sin<span class="op">(</span><span class="fl">1.0</span><span class="op">));</span></span>
<span id="cb49-9"><a href="#cb49-9" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>midright<span class="op">.</span>integrate<span class="op">(</span><span class="fl">0.0</span><span class="op">,</span> <span class="fl">1.0</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> seno<span class="op">),</span></span>
<span id="cb49-10"><a href="#cb49-10" aria-hidden="true" tabindex="-1"></a> <span class="op">(</span>sin<span class="op">(</span><span class="fl">0.5</span><span class="op">)</span> <span class="op">+</span> sin<span class="op">(</span><span class="fl">1.0</span><span class="op">))</span> <span class="op">/</span> <span class="dv">2</span><span class="op">);</span></span>
<span id="cb49-11"><a href="#cb49-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb49-12"><a href="#cb49-12" aria-hidden="true" tabindex="-1"></a> cerr <span class="op"><<</span> <span class="st">"All the tests passed. Hurrah!</span><span class="sc">\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb49-13"><a href="#cb49-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Una volta implementato <code>MidRight</code>, l’implementazione dei punti #3 e #4 è automatica per come avevamo implementato <code>calculate_errors()</code>: basta invocarlo una seconda volta nel <code>main()</code> passando però una istanza di <code>MidRight</code> anziché <code>MidPoint</code>:</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a> test_code<span class="op">();</span></span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// Il codice per i punti #1 e #2 resta ovviamente uguale</span></span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Points 3 and 4</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-9"><a href="#cb50-9" aria-hidden="true" tabindex="-1"></a> MidRight midright<span class="op">;</span></span>
<span id="cb50-10"><a href="#cb50-10" aria-hidden="true" tabindex="-1"></a> calculate_errors<span class="op">(</span>midright<span class="op">,</span> fun1<span class="op">,</span> true_value1<span class="op">,</span> <span class="st">"point3.png"</span><span class="op">)};</span></span>
<span id="cb50-11"><a href="#cb50-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Notate che a differenza del punto #1 qui non salviamo il risultato di <code>calculate_errors</code>, perché non ci interessa. L’output è il seguente:</p>
<pre><code># Points 3 and 4
Error table:
N h Value Error Estimated error
2 8.2436064e-01 3.4101235e+00 2.0246755e+00 2.0246755e+00
4 4.1218032e-01 2.2839247e+00 8.9847667e-01 9.8376464e-01
8 2.0609016e-01 1.8056283e+00 4.2018032e-01 4.7799900e-01
16 1.0304508e-01 1.5882384e+00 2.0279037e-01 2.3225377e-01
32 5.1522540e-02 1.4850161e+00 9.9568059e-02 1.1284922e-01
64 2.5761270e-02 1.4347751e+00 4.9327111e-02 5.4832031e-02
128 1.2880635e-02 1.4099973e+00 2.4549318e-02 2.6642202e-02
256 6.4403175e-03 1.3976941e+00 1.2246099e-02 1.2945115e-02
512 3.2201587e-03 1.3915639e+00 6.1159093e-03 6.2898701e-03
1024 1.6100794e-03 1.3885042e+00 3.0561697e-03 3.0561697e-03
k₁ = 2.48, k₂ = 1.04</code></pre>
<p>e questo è il grafico:</p>
<p><img src="images/exam1-point3.png" /></p>
<p>Notate che ora l’errore segue la legge <span class="math inline">\varepsilon \propto h</span> (l’esponente di <span class="math inline">h</span> è 1): il mid-right non funziona così bene come il mid-point.</p>
<h2 id="temaApuntoE">Implementazione del punto 5</h2>
<p>Per svolgere il punto #5 dobbiamo recuperare l’algoritmo per il calcolo dell’integrale col metodo della media dall’<a href="carminati-esercizi-10.html#esercizio-10.2">esercizio 10.2</a>, e la funzione <code>stddev</code> per calcolare la deviazione standard dall’<a href="carminati-esercizi-03.html#esercizio-3.1">esercizio 3.1</a>.</p>
<p>Come avevamo stabilito quando abbiamo letto il testo dei punti #5 e #6, implementiamo il codice che risolve il punto #5 in una funzione <code>run_integral_mc_mean</code>:</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> run_integral_mc_mean<span class="op">(</span><span class="dt">int</span> N<span class="op">)</span> <span class="op">{</span></span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a> IntegraleMedia media<span class="op">{</span><span class="dv">1</span><span class="op">};</span></span>
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a> vector<span class="op"><</span><span class="dt">double</span><span class="op">></span> mc_samples<span class="op">(</span><span class="dv">1000</span><span class="op">);</span></span>
<span id="cb52-4"><a href="#cb52-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i<span class="op">{};</span> i <span class="op"><</span> ssize<span class="op">(</span>mc_samples<span class="op">);</span> <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb52-5"><a href="#cb52-5" aria-hidden="true" tabindex="-1"></a> mc_samples<span class="op">.</span>at<span class="op">(</span>i<span class="op">)</span> <span class="op">=</span> media<span class="op">.</span>Integra<span class="op">(</span>fun1<span class="op">,</span> a<span class="op">,</span> b<span class="op">,</span> N<span class="op">,</span> <span class="fl">0.0</span><span class="op">);</span></span>
<span id="cb52-6"><a href="#cb52-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb52-7"><a href="#cb52-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> error_mc<span class="op">{</span>stddev<span class="op">(</span>mc_samples<span class="op">)};</span></span>
<span id="cb52-8"><a href="#cb52-8" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">::</span>print<span class="op">(</span><span class="st">"Estimate of the integral using the mean method with N=</span><span class="sc">{}</span><span class="st"> points: "</span></span>
<span id="cb52-9"><a href="#cb52-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"</span><span class="sc">{:.5f}</span><span class="st"> ± </span><span class="sc">{:.5f}\n\n</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb52-10"><a href="#cb52-10" aria-hidden="true" tabindex="-1"></a> N<span class="op">,</span></span>
<span id="cb52-11"><a href="#cb52-11" aria-hidden="true" tabindex="-1"></a> mc_samples<span class="op">.</span>front<span class="op">(),</span> <span class="co">// Let's take the first sample</span></span>
<span id="cb52-12"><a href="#cb52-12" aria-hidden="true" tabindex="-1"></a> error_mc<span class="op">);</span></span>
<span id="cb52-13"><a href="#cb52-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb52-14"><a href="#cb52-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> error_mc<span class="op">;</span></span>
<span id="cb52-15"><a href="#cb52-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Se volete potete produrre anche un istogramma di <code>mc_samples</code>, per verificare la bontà dei risultati. Ci sono alcune cose a cui stare attenti:</p>
<ul>
<li><p>Non confondete il numero di campioni del metodo della media (<span class="math inline">N = 16</span>) con il numero di estrazioni Monte Carlo (1000)!</p></li>
<li><p>Anche se non è richiesto dal testo del problema, è bene stampare il valore stimato dell’integrale e non solo il suo errore: se tutto è implementato come si deve, dovremmo ritrovare un valore che non si discosta molto dal valore vero (<span class="math inline">3e^2 / 16 \approx 1.385</span>).</p></li>
<li><p>Attenzione al valore che attribuite all’integrale! Anche se avete 1000 stime dell’integrale in <code>mc_mean</code>, non potete calcolarne la media e dire che quel valore è affetto dall’errore restituito dalla chiamata a <code>stddev</code>. In altre parole, questo codice è <strong>errato</strong>:</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">"Estimate of the integral using the mean method with N=</span><span class="sc">{}</span><span class="st"> points: "</span></span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a> <span class="st">"</span><span class="sc">{:.5f}</span><span class="st"> ± </span><span class="sc">{:.5f}\n\n</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a> N<span class="op">,</span></span>
<span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a> mean<span class="op">(</span>mc_samples<span class="op">),</span> <span class="co">// WRONG WRONG WRONG!</span></span>
<span id="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a> error_mc<span class="op">);</span></span></code></pre></div>
<p>perché l’errore associato al valore medio dei valori in <code>mc_samples</code> non è la deviazione standard <span class="math inline">\sigma</span> restituita da <code>stddev</code>, bensì l’errore della media <span class="math inline">\sigma / \sqrt{N}</span>. Questo non è però quanto richiede il testo del tema d’esame, che parla esplicitamente di “errore nel calcolo […] dell’integrale […] con un numero di estrazioni pari a 16”. Se mediate insieme 1000 valori, non è più l’errore del caso <span class="math inline">N = 16</span>, ma corrisponde a un caso in cui <span class="math inline">N = 16 \times 1000</span>.</p>
<p>Nel nostro codice stampiamo come valore di riferimento il primo dei 1000 calcolati (<code>mc_samples.front()</code>), ma ne avremmo potuto scegliere un qualsiasi elemento del vettore e sarebbe andato bene ugualmente.</p></li>
</ul>
<p>Nel <code>main()</code> eseguiamo <code>run_integral_mc_mean()</code> salvando il risultato in una variabile <code>error_mc</code>: ci servirà poi per implementare il punto #6:</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">int</span> N<span class="op">{</span><span class="dv">16</span><span class="op">};</span></span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> error_mc<span class="op">{</span>run_integral_mc_mean<span class="op">(</span>N<span class="op">)};</span></span></code></pre></div>
<p>L’output prodotto è il seguente:</p>
<pre><code># Point #5
Estimate of the integral using the mean method with N=16 points: 1.08628 ± 0.41611</code></pre>
<p>che è confortante, perché è compatibile con il valore vero dell’integrale (1.385) entro la barra d’errore.</p>
<h2 id="temaApuntoF">Implementazione del punto 6</h2>
<p>Per svolgere il punto #6 dobbiamo recuperare l’errore che avevamo calcolato nel punto #1, e che è stato salvato all’interno della variabile <code>midpoint_results</code> nel <code>main</code>. La variabile contiene l’intera tabella degli errori, ma a noi serve solo quello che corrisponde a <span class="math inline">N = 16</span>. Potremmo scrivere una funzione che cerca nella tabella qual è l’indice <code>k</code> che corrisponde al caso <code>midpoint_results.num_of_steps[k] == 16</code>, ma è più rapido guardare sul video qual è la riga corrispondente nell’output del nostro programma (la terza) e inserire questo valore direttamente nel codice, inserendo un <code>assert</code> per sicurezza:</p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">int</span> row_index<span class="op">{</span><span class="dv">3</span><span class="op">};</span></span>
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>midpoint_results<span class="op">.</span>num_of_steps<span class="op">[</span>row_index<span class="op">]</span> <span class="op">==</span> <span class="dv">16</span><span class="op">);</span></span>
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a><span class="co">// Dobbiamo fare in modo che il metodo della media raggiunga questo errore</span></span>
<span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">double</span> target_error<span class="op">{</span>midpoint_results<span class="op">.</span>error<span class="op">[</span>row_index<span class="op">]};</span></span></code></pre></div>
<p>In questo modo, se prima di consegnare lo scritto ci accorgeremo di aver sbagliato a produrre la tabella e la riga corrispondente non sarà più la numero 3, il codice ci avviserà del problema. Ricordate sempre che è meglio essere prudenti, e spendere un po’ di tempo per implementare questi <code>assert()</code> può evitare di avere errori la cui correzione richiede molto tempo!</p>
<p>Sapendo che l’errore nel metodo della media varia come <span class="math inline">\varepsilon(N) = \sigma / \sqrt{N}</span>, manipolando l’espressione otteniamo che <span class="math display">
N_{\text{target}} = N \cdot \left(\frac{\varepsilon(N)}{\epsilon_{\text{target}}}\right)
</span> che si traduce immediatamente nel seguente codice C++:</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><span class="at">const</span> <span class="dt">int</span> new_N<span class="op">{</span><span class="kw">static_cast</span><span class="op"><</span><span class="dt">int</span><span class="op">>(</span>N <span class="op">*</span> pow<span class="op">(</span>error_mc <span class="op">/</span> target_error<span class="op">,</span> <span class="fl">2.0</span><span class="op">))};</span></span>
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb57-3"><a href="#cb57-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb57-4"><a href="#cb57-4" aria-hidden="true" tabindex="-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">"Number of points required for the mean method to achieve an "</span></span>
<span id="cb57-5"><a href="#cb57-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"error of </span><span class="sc">{:.3e}</span><span class="st">: </span><span class="sc">{}\n\n</span><span class="st">"</span><span class="op">,</span></span>
<span id="cb57-6"><a href="#cb57-6" aria-hidden="true" tabindex="-1"></a> target_error<span class="op">,</span> new_N<span class="op">);</span></span>
<span id="cb57-7"><a href="#cb57-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb57-8"><a href="#cb57-8" aria-hidden="true" tabindex="-1"></a><span class="co">// Esegui di nuovo il Monte Carlo per verificare che l'errore calcolato sia corretto</span></span>
<span id="cb57-9"><a href="#cb57-9" aria-hidden="true" tabindex="-1"></a>run_integral_mc_mean<span class="op">(</span>new_N<span class="op">);</span></span></code></pre></div>
<p>Questo è l’output:</p>
<pre><code># Point #6
Number of points required for the mean method to achieve an error of 3.654e-03: 207466
Estimate of the integral using the mean method with N=207466 points: 1.38456 ± 0.00366</code></pre>
<p>L’errore prodotto è compatibile con quello atteso: <code>0.00366</code> rispetto a <code>3.654e-03</code>, quindi lo svolgimento è corretto.</p>
<h2 id="temaApuntoG">Implementazione del punto 7</h2>
<p>Resta l’ultimo punto, quello “per la lode”, che però non richiede molto sforzo per essere implementato. È sufficiente ereditare una nuova classe da <code>FunzioneBase</code> e implementare l’integranda:</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Funzione2 <span class="op">:</span> <span class="kw">public</span> FunzioneBase <span class="op">{</span></span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">double</span> Eval<span class="op">(</span><span class="dt">double</span> x<span class="op">)</span> <span class="at">const</span> <span class="kw">override</span> <span class="op">{</span></span>
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="fl">1.0</span> <span class="op">/</span> sqrt<span class="op">(</span><span class="fl">4.0</span> <span class="op">-</span> x <span class="op">*</span> x<span class="op">);</span></span>
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
<p>Aggiungiamo per sicurezza un paio di test in <code>test_code()</code>:</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> test_code<span class="op">()</span> <span class="op">{</span></span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// I test per `Funzione1` restano invariati</span></span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a> Funzione2 fun2</span>
<span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>fun2<span class="op">.</span>Eval<span class="op">(</span><span class="fl">0.0</span><span class="op">),</span> <span class="fl">0.5</span><span class="op">));</span></span>
<span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>are_close<span class="op">(</span>fun2<span class="op">.</span>Eval<span class="op">(</span><span class="fl">1.0</span><span class="op">),</span> <span class="fl">1.0</span> <span class="op">/</span> sqrt<span class="op">(</span><span class="fl">3.0</span><span class="op">)));</span></span>
<span id="cb60-8"><a href="#cb60-8" aria-hidden="true" tabindex="-1"></a> <span class="ot">assert</span><span class="op">(</span>isinf<span class="op">(</span>fun2<span class="op">.</span>Eval<span class="op">(</span><span class="fl">2.0</span><span class="op">)));</span></span>
<span id="cb60-9"><a href="#cb60-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-10"><a href="#cb60-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// I test per MidRight restano invariati</span></span>
<span id="cb60-11"><a href="#cb60-11" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span></code></pre></div>
<p>Notate che verifichiamo che in <span class="math inline">x = 2</span> la funzione sia uguale a <span class="math inline">\infty</span>: la funzione <code>isinf</code> restituisce <code>true</code> se il numero floating-point è uno dei <a href="https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html">tipi di infinito</a> supportati da <code>double</code>.</p>
<p>Ovviamente dobbiamo usare il metodo del mid-point con la seconda integranda, perché il mid-right richiederebbe di calcolarla in <span class="math inline">x = 2</span>, dove non è definita. Dobbiamo anche ricordarci di confrontare il valore stimato dell’integrale con <code>true_value2</code> (ossia <span class="math inline">\pi / 2</span>) anziché <code>true_value1</code>:</p>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a> test_code<span class="op">();</span></span>
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-4"><a href="#cb61-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb61-5"><a href="#cb61-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-6"><a href="#cb61-6" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"# Point #7</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb61-7"><a href="#cb61-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-8"><a href="#cb61-8" aria-hidden="true" tabindex="-1"></a> cout <span class="op"><<</span> <span class="st">"We must use mid-point, otherwise the function to integrate is "</span></span>
<span id="cb61-9"><a href="#cb61-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"estimated outside of its domain.</span><span class="sc">\n\n</span><span class="st">"</span><span class="op">;</span></span>
<span id="cb61-10"><a href="#cb61-10" aria-hidden="true" tabindex="-1"></a> Funzione2 fun2<span class="op">;</span></span>
<span id="cb61-11"><a href="#cb61-11" aria-hidden="true" tabindex="-1"></a> ErrorTable fun2_results<span class="op">{</span>calculate_errors<span class="op">(</span>midpoint<span class="op">,</span> fun2<span class="op">,</span></span>
<span id="cb61-12"><a href="#cb61-12" aria-hidden="true" tabindex="-1"></a> true_value2<span class="op">,</span> <span class="st">"point7.png"</span><span class="op">)};</span></span>
<span id="cb61-13"><a href="#cb61-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Questo è l’output:</p>
<pre><code># Point #7
We must use mid-point, otherwise the function to integrate is estimated outside of its domain.
Error table:
N h Value Error Estimated error
2 8.2436064e-01 1.2723267e+00 2.9846960e-01 2.9846960e-01
4 4.1218032e-01 1.3583103e+00 2.1248598e-01 2.1136014e-01
8 2.0609016e-01 1.4200533e+00 1.5074307e-01 1.4967390e-01
16 1.0304508e-01 1.4640336e+00 1.0676275e-01 1.0599102e-01
32 5.1522540e-02 1.4952436e+00 7.5552682e-02 7.5057145e-02
64 2.5761270e-02 1.5173514e+00 5.3444936e-02 5.3151439e-02
128 1.2880635e-02 1.5329976e+00 3.7798727e-02 3.7638994e-02
256 6.4403175e-03 1.5440660e+00 2.6730367e-02 2.6653914e-02
512 3.2201587e-03 1.5518942e+00 1.8902153e-02 1.8874870e-02
1024 1.6100794e-03 1.5574302e+00 1.3366169e-02 1.3366169e-02
k₁ = 0.33, k₂ = 0.50</code></pre>
<p>e questo è il grafico:</p>
<p><img src="images/exam1-point7.png" /></p>
<h1 id="temaB">Tema 2 (equazioni differenziali)</h1>
<p>Questo è il link per aprire il testo: <a href="https://labtnds.docs.cern.ch/ProveEsame/AppelloTNDS_2.pdf" class="uri">https://labtnds.docs.cern.ch/ProveEsame/AppelloTNDS_2.pdf</a></p>
<h2 id="temaBLetturaTesto">Lettura del testo</h2>
<p>Nello svolgimento del <a href="#temaA">primo esercizio</a> abbiamo mostrato come svolgere un’efficace <a href="#letturaTestoA">lettura del testo</a>, ma non abbiamo spiegato <em>come</em> si può arrivare a leggere l’enunciato di un tema d’esame in un modo efficace. Qui faremo quindi un lavoro più dettagliato dal punto di vista pratico: fingeremo di avere a disposizione un foglio di carta su cui segneremo le cose importanti da fare. All’inizio lasceremo cinque caselle vuote, una per ogni punto riportato nel testo:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
</ol>
</blockquote>
<p>Leggeremo il tema punto per punto come abbiamo fatto per il Tema 1, e annoteremo in questa lista le cose importanti.</p>
<p>Il primo punto chiede di usare il metodo Runge-Kutta per risolvere un’equazione differenziale del secondo ordine, quindi dovremo recuperare il testo dell’<a href="carminati-esercizi-08.html#esercizio-8.2">esercizio 8.2</a>. Richiede di stimare la posizione alla fine della simulazione, quindi si tratta di scrivere un ciclo <code>while</code> che aumenta il tempo <code>t</code> finché non raggiunge il tempo finale: nulla di difficile, è praticamente identico all’esercizio 8.2, anche se qui ci chiede di usare un “passo <span class="math inline">h</span> di integrazione opportuno”. Aggiorniamo quindi il nostro foglio:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">
<li><p>Stima un buon valore per <span class="math inline">h</span>, usa RK fino al tempo finale e stampa posizione (es. 8.2)</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
</ol>
</blockquote>
<p>Passiamo al secondo punto, che richiede di stimare l’errore nella posizione. Dobbiamo ricordarci che il metodo Runge-Kutta è un metodo del <em>quarto</em> ordine (sapete bene la teoria, vero?!? 🫵), e usare quindi le formule insegnate a lezione per stimare l’errore quando non si conosce la soluzione analitica: risolvere il problema con passo <span class="math inline">h</span>, poi con passo <span class="math inline">h/2</span>, e poi combinare i due risultati. Aggiorniamo il nostro foglio:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">
<li><p>Stima un buon valore per <span class="math inline">h</span>, usa RK fino al tempo finale e stampa posizione (es. 8.2)</p></li>
<li><p>Usa RK con <span class="math inline">h/2</span> fino al tempo finale, poi combina il risultato con la stima del punto 1</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
</ol>
</blockquote>
<p>Veniamo al terzo punto, che richiede di stimare <span class="math inline">h</span> in modo da ottenere un preciso errore sulla posizione. Questo si potrà stimare sapendo che <span class="math inline">\varepsilon \propto h^4</span> (la teoria, la teoria!), quindi possiamo aggiornare il nostro foglio:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">
<li><p>Stima un buon valore per <span class="math inline">h</span>, usa RK fino al tempo finale e stampa posizione (es. 8.2)</p></li>
<li><p>Usa RK con <span class="math inline">h/2</span> fino al tempo finale, poi combina il risultato con la stima del punto 1</p></li>
<li><p>Calcola il valore di <span class="math inline">h</span> richiesto usando la formula analitica dell’errore</p></li>
<li><p>?</p></li>
<li><p>?</p></li>
</ol>
</blockquote>
<p>Il punto 4 richiede di eseguire una simulazione Monte Carlo, stimando l’errore sulla posizione al tempo finale; dovremo quindi usare il generatore di numeri casuali dell’<a href="carminati-esercizi-10.html#esercizio-10.0">esercizio 10.0</a>. Il nostro foglio diventa questo:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">
<li><p>Stima un buon valore per <span class="math inline">h</span>, usa RK fino al tempo finale e stampa posizione (es. 8.2)</p></li>
<li><p>Usa RK con <span class="math inline">h/2</span> fino al tempo finale, poi combina il risultato con la stima del punto 1</p></li>
<li><p>Calcola il valore di <span class="math inline">h</span> richiesto usando la formula analitica dell’errore</p></li>
<li><p>Esegui MC 1000 volte per stimare l’errore sulla posizione al tempo finale (es. 10.0)</p></li>
<li><p>?</p></li>
</ol>
</blockquote>
<p>Infine, l’ultimo punto richiede di ripetere il punto 4 con valori diversi dell’errore e stampare una tabella in cui si mostra l’andamento dell’errore della posizione; dovremo quindi usare il codice per la deviazione standard implementato nell’<a href="carminati-esercizi-03.html#esercizio-3.1">esercizio 3.1</a>. Con questo abbiamo completato la nostra tabellina sul foglio di brutta:</p>
<blockquote>
<p>Cose da fare:</p>
<ol type="1">