Ce vei învăța astăzi?
Vom crea un program complex cu meniu care combină toate formulele geometrice învățate. Vom discuta și despre eficiență: câte operații face programul nostru?
Dicționar: Matematică ↔ C++ (Această lecție)
| Simbol matematic | Cum se citește | În C++ | Observație |
|---|---|---|---|
| √x | „radical din x" | sqrt(x) | <cmath> |
| |x| | „modul / val. absolută" | fabs(x) | pt double, nu abs() |
| a ≈ b | „a aproximativ egal b" | fabs(a-b) < eps | eps = 0.001 |
| S = |det|/2 | „aria cu determinant" | fabs(x1*(y2-y3)+...)/2 | coliniaritate |
| s = P/2 | „semiperimetru" | s = (a+b+c)/2.0 | 2.0, nu 2! |
| G | „centru de greutate" | (x1+x2+x3)/3.0 | 3.0, nu 3! |
| R = abc/(4S) | „raza cercului circumscris" | a*b*c/(4.0*aria) | 4.0, nu 4! |
Proiectarea meniului
Structura meniului:
- Calculează distanța dintre 2 puncte
- Calculează perimetrul unui triunghi
- Calculează aria unui triunghi (Heron)
- Verifică dacă 3 puncte sunt coliniare
- Clasifică triunghiul
- Ieșire
Analogie: Meniul ca un aparat de cafea
Un meniu cu do-while e ca un aparat de cafea: afișează opțiunile, iei alegerea, prepară băutura, apoi întreabă din nou. Se oprește doar când apeși „Anulare". Structura do-while garantează că meniul se afișează cel puțin o dată.
Sfat practic: Folosind do-while cu switch, poți crea programe cu meniu care rulează până când utilizatorul alege să iasă.
Funcții C++ — reutilizarea codului
Funcție: Un bloc de cod cu un nume, care primește parametri și returnează un rezultat. Se definește O SINGURĂ DATĂ, se apelează de câte ori ai nevoie.
double dist(double x1, double y1, double x2, double y2) {
return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}
// Apeluri:
double d = dist(0, 0, 3, 4); // d = 5.0
double e = dist(1, 2, 4, 6); // e = 5.0
Urmărire pas cu pas: dist(0, 0, 3, 4)
| Pas | Operație manuală | Variabilă C++ | Valoare |
|---|---|---|---|
| 1 | x₂ − x₁ = 3 − 0 | x2-x1 | 3 |
| 2 | y₂ − y₁ = 4 − 0 | y2-y1 | 4 |
| 3 | 3 + 4 | (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) | 25 |
| 4 | √25 | sqrt(25) | 5.0 |
Formula lui Heron pentru arie
Formula lui Heron: Calculează aria triunghiului cunoscând cele 3 laturi, fără a cunoaște înălțimea.
s = (a + b + c) / 2 (semiperimetrul)
S = √(s · (s-a) · (s-b) · (s-c))
Exemplu: Triunghi cu laturile 3, 4, 5
s = (3+4+5)/2 = 6
S = √(6 · (6-3) · (6-4) · (6-5)) = √(6 · 3 · 2 · 1) = √36 = 6
Verificare: triunghi dreptunghic cu catete 3,4 → S = 3×4/2 = 6 ✓
double a = dist(x2,y2,x3,y3); // latura opusă lui A double b = dist(x1,y1,x3,y3); // latura opusă lui B double c = dist(x1,y1,x2,y2); // latura opusă lui C double s = (a + b + c) / 2; double aria = sqrt(s * (s-a) * (s-b) * (s-c));
Atenție: Dacă s-a, s-b sau s-c e negativ, ai introdus un triunghi invalid (inegalitatea triunghiului nu e satisfăcută). Verifică: a+b > c, a+c > b, b+c > a.
Coliniaritate — 3 puncte pe aceeași dreaptă
Coliniaritate: Trei puncte sunt coliniare dacă aria triunghiului format de ele = 0.
S = |x₁(y₂-y₃) + x₂(y₃-y₁) + x₃(y₁-y₂)| / 2
Dacă S ≈ 0 (S < 0.001) → punctele sunt coliniare
Exemplu: (1,1), (2,2), (3,3) — pe diagonală
S = |1·(2-3) + 2·(3-1) + 3·(1-2)| / 2 = |(-1) + 4 + (-3)| / 2 = 0 / 2 = 0 → Coliniare ✓
Clasificarea triunghiului
| Tip | Condiție | Cod C++ |
|---|---|---|
| Echilateral | a = b = c | fabs(a-b)<eps && fabs(b-c)<eps |
| Isoscel | 2 laturi egale | fabs(a-b)<eps || fabs(b-c)<eps || fabs(a-c)<eps |
| Scalen | Toate diferite | altfel (else) |
| Dreptunghic | a = b + c | fabs(a2-b2-c2)<eps (testezi toate 3 combinații) |
De ce folosim fabs(a-b) < eps? Deoarece calculele cu double introduc erori de rotunjire. Nu comparăm niciodată cu == la numere reale. Folosim o toleranță mică: eps = 0.001.
Implementarea completă
#include <iostream>
#include <cmath>
using namespace std;
double dist(double x1, double y1, double x2, double y2) {
return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}
int main() {
int optiune;
double x1, y1, x2, y2, x3, y3;
do {
cout << "\n=== CALCULATOR GEOMETRIC ===" << endl;
cout << "1. Distanta dintre 2 puncte" << endl;
cout << "2. Perimetrul triunghiului" << endl;
cout << "3. Aria triunghiului (Heron)" << endl;
cout << "4. Verifica coliniaritate" << endl;
cout << "5. Clasificare triunghi" << endl;
cout << "0. Iesire" << endl;
cout << "Alege optiunea: ";
cin >> optiune;
switch(optiune) {
case 1: {
cout << "A(x1,y1): "; cin >> x1 >> y1;
cout << "B(x2,y2): "; cin >> x2 >> y2;
cout << "Distanta = " << dist(x1,y1,x2,y2) << endl;
break;
}
case 2: {
cout << "A(x1,y1): "; cin >> x1 >> y1;
cout << "B(x2,y2): "; cin >> x2 >> y2;
cout << "C(x3,y3): "; cin >> x3 >> y3;
double a = dist(x2,y2,x3,y3);
double b = dist(x1,y1,x3,y3);
double c = dist(x1,y1,x2,y2);
cout << "Perimetrul = " << a+b+c << endl;
break;
}
case 3: {
cout << "A(x1,y1): "; cin >> x1 >> y1;
cout << "B(x2,y2): "; cin >> x2 >> y2;
cout << "C(x3,y3): "; cin >> x3 >> y3;
double a = dist(x2,y2,x3,y3);
double b = dist(x1,y1,x3,y3);
double c = dist(x1,y1,x2,y2);
double s = (a+b+c) / 2;
double aria = sqrt(s*(s-a)*(s-b)*(s-c));
cout << "Aria = " << aria << endl;
break;
}
case 4: {
cout << "A(x1,y1): "; cin >> x1 >> y1;
cout << "B(x2,y2): "; cin >> x2 >> y2;
cout << "C(x3,y3): "; cin >> x3 >> y3;
double det = fabs(x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
if (det < 0.001) cout << "Punctele SUNT coliniare" << endl;
else cout << "Punctele NU sunt coliniare" << endl;
break;
}
case 5: {
cout << "A(x1,y1): "; cin >> x1 >> y1;
cout << "B(x2,y2): "; cin >> x2 >> y2;
cout << "C(x3,y3): "; cin >> x3 >> y3;
double a = dist(x2,y2,x3,y3);
double b = dist(x1,y1,x3,y3);
double c = dist(x1,y1,x2,y2);
double eps = 0.001;
if(fabs(a-b)<eps && fabs(b-c)<eps)
cout << "Echilateral" << endl;
else if(fabs(a-b)<eps || fabs(b-c)<eps || fabs(a-c)<eps)
cout << "Isoscel" << endl;
else cout << "Scalen" << endl;
break;
}
case 0:
cout << "La revedere!" << endl;
break;
default:
cout << "Optiune invalida!" << endl;
}
} while (optiune != 0);
return 0;
}
Algoritmul complet (Pseudocod)
Introducere în eficiență
Câte operații face programul nostru?
- Funcția
dist()face: 2 scăderi, 2 înmulțiri, 1 adunare, 1 radical = 6 operații - Perimetrul: 3 apeluri la dist + 2 adunări = 20 operații
- Aria (Heron): 3 apeluri la dist + semiperimetru + 4 scăderi + 4 înmulțiri + 1 radical = ~30 operații
Întrebare de reflecție
La opțiunile 3, 4 și 5, calculăm de fiecare dată laturile de la zero. Putem optimiza?
Răspuns: Da! Calculăm laturile o singură dată și le reutilizăm. Aceasta este optimizare prin evitarea calculelor redundante.
| Versiune | Operații per ciclu | Motivare |
|---|---|---|
| Inițială | ~30 per opțiune | Recalculează laturile de fiecare dată |
| Optimizată | ~18 + reutilizare | Calculează laturile o dată, reutilizează |
| Economie | ~40% | Mai puține apeluri sqrt redundante |
Greșeli frecvente
Lipsa break în switch: Fără break, execuția „cade" în case-ul următor (fall-through). Uneori e intenționat, dar de regulă e o eroare.
Variabile declarate în case: Trebuie puse între acolade { }. Altfel, compilatorul dă eroare „jump to case label".
Compararea cu == la double: if(a == b) e riscant. Folosește fabs(a-b) < eps cu eps = 0.001.
do-while vs while: do-while execută întâi blocul, apoi verifică condiția. while verifică ÎNAINTE. Pentru meniuri, do-while e potrivit: vrem ca meniul să se afișeze cel puțin o dată.
Verificare cunoștințe
1. Ce structură repetitivă este potrivită pentru un meniu?
2. Ce face break în switch?
3. Aria triunghiului cu laturile 5, 12, 13 (Heron) este:
4. Cum verifici dacă 3 puncte sunt coliniare?
5. De ce scriem fabs(a-b) < eps în loc de a == b pentru double?
6. dist(0,0,3,4) returnează:
Întrebări frecvente (FAQ)
O funcție e un bloc reutilizabil. Scrii formula O DATĂ în funcție, apoi o apelezi de câte ori ai nevoie: dist(0,0,3,4), dist(1,2,5,6). Fără funcție, ai copia codul de 3 ori.
Da, dar x*x e mai rapid decât pow(x,2). pow e util la puteri fracționare/mari. Pentru pătrat, înmulțirea directă e preferată.
Returnează NaN (Not a Number). De aceea verifici mereu ca argumentul să fie ≥ 0. La Heron, un s-a negativ înseamnă triunghi invalid.
Doar când enunțul cere două zecimale. Adaugă #include <iomanip>, apoi afișează rezultatul așa: cout << fixed << setprecision(2) << valoare;. Pe scurt: fixed înseamnă „afișează zecimale normale”, iar setprecision(2) înseamnă „arată 2 cifre după virgulă”.
PbInfo - Distanta dintre doua puncte
Formula distantei
Enunț:
Cerință: Se citesc coordonatele a doua puncte. Afiseaza distanta dintre ele cu doua zecimale.
Date de intrare:
x1 y1 x2 y2.
Date de ieșire:
Distanta dintre puncte.
Exemplu:
Intrare:
0 0 3 4
Ieșire:
5.00
Explicație: Distanta este sqrt(3^2+4^2)=5.
Cum gândim soluția:
- Calculam dx=x2-x1 si dy=y2-y1.
- Aplicam sqrt(dx*dx+dy*dy).
- Afisam cu doua zecimale.
Tip: double pastreaza rezultatul cu virgula. Daca enuntul cere exact doua zecimale, folosim fixed si setprecision(2) doar la afisarea acelui rezultat.
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main() {
double x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
double d = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
// Enuntul cere doua zecimale: 5 devine 5.00, 3.14159 devine 3.14.
cout << fixed << setprecision(2) << d;
}
PbInfo - Aria Heron
Triunghi din laturi
Enunț:
Cerință: Se citesc trei laturi. Daca formeaza triunghi, afiseaza aria prin formula lui Heron.
Date de intrare:
a b c.
Date de ieșire:
Aria sau mesajul Imposibil.
Exemplu:
Intrare:
3 4 5
Ieșire:
6.00
Explicație: Semiperimetrul este 6, aria este 6.
Cum gândim soluția:
- Verificam inegalitatile triunghiului.
- Calculam s=(a+b+c)/2.
- Aplicam sqrt(s*(s-a)*(s-b)*(s-c)).
Tip: Nu aplica Heron inainte sa verifici triunghiul.
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main() {
double a, b, c;
cin >> a >> b >> c;
if (a + b <= c||a + c <= b||b + c <= a) {
cout << "Imposibil";
return 0;
}
double s = (a + b + c) / 2;
// Afisam cu doua zecimale deoarece exemplul cere 6.00, nu doar 6.
cout << fixed << setprecision(2) << sqrt(s * (s - a) * (s - b) * (s - c));
}
PbInfo - Coliniaritate
Arie zero
Enunț:
Cerință: Se citesc trei puncte. Afiseaza DA daca sunt coliniare, altfel NU.
Date de intrare:
Coordonatele celor trei puncte.
Date de ieșire:
DA sau NU.
Exemplu:
Intrare:
0 0 1 1 2 2
Ieșire:
DA
Explicație: Punctele sunt pe aceeasi dreapta.
Cum gândim soluția:
- Calculam determinantul.
- Daca determinantul este 0, aria este 0.
- Afisam DA/NU.
Tip: Pentru coordonate intregi poti compara determinantul exact cu 0.
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
using namespace std;
int main() {
long long x1, y1, x2, y2, x3, y3;
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
long long det = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2);
cout << (det == 0?"DA":"NU");
}
Exercițiul Practic: Calculator geometric
Extinde calculatorul geometric si optimizeaza formulele reutilizate in mai multe optiuni. Important: aici exersam ideea, nu copierea unei singure variante de cod.
Cum lucram la calculator: poti porni de la programul complet din lectie sau poti scrie o varianta mai mica, doar cu optiunile cerute. Este corect si daca citesti coordonatele in fiecare case, si daca le citesti o singura data inainte de meniu; diferenta este de organizare si eficienta. Important este sa explici in cod ce varianta ai ales.
Sarcina 1: Adaugă opțiunea de triunghi dreptunghic
Adauga o optiune pentru verificarea triunghiului dreptunghic. Poti folosi numarul 6 in meniul existent sau poti face un program separat care citeste trei puncte si afiseaza rezultatul.
Pași de rezolvare:
- Daca lucrezi in meniul existent, adauga
case 6:inswitch, cu{ }pentru variabile locale - Daca faci program separat, citeste direct punctele A, B, C si sari peste meniu
- Calculeaza distantele la patrat (fara
sqrt):a2 = (x3-x2)*(x3-x2)+(y3-y2)*(y3-y2) - Testeaza Pitagora pe toate 3 combinatii:
fabs(a2-b2-c2)<eps - In varianta cu
switch, nu uitabreak;la final
De ce funcționează? Teorema lui Pitagora spune că într-un triunghi dreptunghic, ipotenuza = cateta₁ + cateta₂. Nu știm care latură e ipotenuza, așa că testăm toate 3 combinații. Folosim fabs() (valoare absolută) deoarece numerele double au erori de rotunjire — nu comparăm niciodată cu ==!
case 6: {
// Citim coordonatele celor 3 varfuri
cout << "A,B,C: "; cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
// Calculam patratele laturilor (fara sqrt — e mai eficient!)
double a2 = (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2); // BC^2
double b2 = (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1); // AC^2
double c2 = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); // AB^2
double eps = 0.001; // toleranta pentru erori de rotunjire
// Testam Pitagora pe toate 3 combinatii (nu stim care e ipotenuza)
if(fabs(a2-b2-c2)<eps || fabs(b2-a2-c2)<eps
|| fabs(c2-a2-b2)<eps)
cout << "Dreptunghic" << endl;
else
cout << "Nu este dreptunghic" << endl;
break;
}
Sarcina 2: Optimizare - evitarea calculelor repetate
Rescrie sau reorganizeaza programul astfel incat valorile folosite de mai multe ori sa nu fie recalculate inutil. Poti optimiza tot calculatorul sau doar partea de triunghi.
Pași de rezolvare:
- Alege ce optimizezi: toate optiunile cu triunghi sau doar cele care folosesc aceleasi laturi
- Citeste coordonatele o singura data pentru acel triunghi
- Calculeaza laturile
a,b,cimediat dupa citire - Calculeaza doar ce iti trebuie:
Ppentru perimetru,ssiariapentru Heron,a2,b2,c2pentru Pitagora - In fiecare
case, foloseste variabilele deja calculate
De ce funcționează? În versiunea inițială, fiecare case recalcula laturile a, b, c de la zero — adică 3 × sqrt() de fiecare dată. Mutând calculele înainte de switch, facem 3 sqrt() o singură dată, indiferent câte operații alege utilizatorul. E un exemplu clasic de precalculare (memoizare simplificată).
// === OPTIMIZARE: citim si calculam O SINGURA DATA === cout << "A: "; cin >> x1 >> y1; // coordonatele varfului A cout << "B: "; cin >> x2 >> y2; // coordonatele varfului B cout << "C: "; cin >> x3 >> y3; // coordonatele varfului C // Laturile triunghiului — calculate o singura data double a = dist(x2,y2,x3,y3); // latura BC double b = dist(x1,y1,x3,y3); // latura AC double c = dist(x1,y1,x2,y2); // latura AB // Valori derivate — reutilizabile in orice case double P = a + b + c; // perimetru double s = P / 2; // semiperimetru double aria = sqrt(s*(s-a)*(s-b)*(s-c)); // Heron // Apoi in switch reutilizam a, b, c, P, aria — FARA recalculare!