B blokk · Változók és típusok · 3. tananyag
Az átlag, az ár, a testmagasság nem egész — kell egy típuscsalád a törteknek is. Csakhogy a törtvilág trükkös: a saját szemeddel látod majd, hogy a gép szerint 0.1 + 0.2 nem pontosan 0.3 — és megtanulod a szakma vasszabályát: pénzt soha ne számolj double-ben.
float, a
double és a
decimal, és mekkora a pontosságuk.f,
m (és a d).0.1 + 0.2 meglepő
eredményt — és miért nem bug ez.decimal a pénz típusa,
és mikor elég a double.7 / 2.0).Számoljunk átlagot a B2 eszközeivel:
int jegy1 = 4; int jegy2 = 5; Console.WriteLine((jegy1 + jegy2) / 2); // 4 — pedig 4.5 kellene!
Egész / egész = egész — a 4,5-ből 4 lett. Ide új típus kell: olyan, amely törtrészt is tárol. A C# hármat is ad, és a választás közöttük nem ízlés kérdése.
| Típus | Méret | Pontosság (értékes jegy) | Literál | Mire való? | .NET-név |
|---|---|---|---|---|---|
float | 4 bájt | ~7 jegy | 3.14f | 3D-grafika, ahol a hely számít — nálunk ritka | System.Single |
double | 8 bájt | ~15–16 jegy | 3.14 | az alapértelmezés: mérés, tudomány, játék | System.Double |
decimal | 16 bájt | 28–29 jegy | 3.14m | pénz és minden pontos tizedes | System.Decimal |
Három dolog, amit rögzíts:
double —
a 3.14 önmagában double.3.14f →
float, 3.14m → decimal (a
3.14d → double, de ezt nem szokás kiírni).
Utótag nélkül a float f = 3.14;
le sem fordul (CS0664) — a fordító nem hajlandó csendben
pontosságot veszíteni.float és a double neve
onnan jön, hogy a tizedespont „lebeg”: a gép a számot egy
szorzat alakjában tárolja (számjegyek × 2 valamelyik hatványa), így ugyanaz a
típus tud nagyon nagy és nagyon kicsi számot is — de mindig csak
korlátos számú értékes jeggyel.double magassag = 1.72; float sebesseg = 12.5f; decimal ar = 2499.90m;
A tizedes elválasztó a kódban mindig pont. A
3,14 a fordítónak két külön dolog: egy 3-as meg
egy 14-es.
Írasd ki — a saját gépeden, most:
Console.WriteLine(0.1 + 0.2); // 0.30000000000000004
Nem elírás, és nem a géped romlott el. A magyarázat: a gép kettes számrendszerben tárol, és ott a 0.1 végtelen szakaszos tört — pontosan úgy, ahogy tízes számrendszerben az 1/3 = 0,33333… sosem írható le véges számjeggyel. A double a 0.1-nek csak egy nagyon jó közelítését tudja eltárolni, és a parányi kerekítési hibák összeadódva néha láthatóvá válnak.
Ez nem bug — ez a lebegőpontos ábrázolás természete, minden nyelvben így van (a JavaScript is ezt csinálja). A kérdés csak az, mikor számít:
double jó.decimal.A decimal tízes számrendszerben
tárol — pontosan úgy „gondolkodik”, ahogy a papíron számolunk. A
0.1m tényleg pontosan 0.1:
double d = 0.1 + 0.2; decimal m = 0.1m + 0.2m; Console.WriteLine(d); // 0.30000000000000004 Console.WriteLine(m); // 0.3 — pontosan
Egy valósághű árszámítás — csupa decimal:
decimal nettoAr = 1999.00m; const decimal AfaSzorzo = 1.27m; // B1: a bűvös szám konstansba való! decimal bruttoAr = nettoAr * AfaSzorzo; Console.WriteLine(bruttoAr); // 2538.7300
Az ára: a decimal lassabb és kisebb a tartománya
(kb. ±7,9 × 10²⁸ — azért ez is bőven elég egy államadósságra). Cserébe 28–29
értékes jegy, tizedesen pontosan.
A Mastermindban int-ek lesznek; a kalandjáték boltjában (II. félév) decimal árak.
A C# ugyanúgy számol, ahogy a matekórán tanultad:
*, /,
% — szorzás, osztás, maradék;+, - — összeadás, kivonás;Console.WriteLine(2 + 3 * 4); // 14 — előbb a szorzás Console.WriteLine((2 + 3) * 4); // 20 — a zárójel felülír Console.WriteLine(10 - 4 - 3); // 3 — balról jobbra: (10-4)-3
A klasszikus átlag-csapda:
int jegy1 = 4; int jegy2 = 5; Console.WriteLine(jegy1 + jegy2 / 2); // 6 — ROSSZ: csak a jegy2 feleződött! Console.WriteLine((jegy1 + jegy2) / 2); // 4 — jobb, de még egészosztás…
Ha egy pillanatig is gondolkodnod kell a sorrenden, zárójelezz. A fölösleges zárójel nem hiba — az olvashatóság eszköze (A9: a kódot többször olvassák, mint írják).
És most a B2-es szálka feloldása. Ha egy műveletben az egyik oldal tört, az egész fél automatikusan törtté lép elő, és az eredmény is tört:
Console.WriteLine(7 / 2); // 3 — int / int = int Console.WriteLine(7 / 2.0); // 3.5 — int / double = double! Console.WriteLine(7.0 / 2); // 3.5 — ez is
Így már megvan a helyes átlag is:
Console.WriteLine((jegy1 + jegy2) / 2.0); // 4.5 ✔
Ez az automatikus „előlépés” egy implicit konverzió — a
konverziók teljes rendszerét a B6-ban tesszük rendbe. Most a mintát jegyezd
meg: egy jól elhelyezett .0 a kifejezésben
átbillenti az osztást a törtvilágba.
Melyik típust választanád az adatnak? A döntési ábra segít!
| Tünet | Mi történt? | Mit tegyél? |
|---|---|---|
CS0664: Literal of type double cannot be implicitly converted… | float f = 3.14; vagy decimal d = 3.14; — hiányzik az utótag | 3.14f, illetve 3.14m |
0.30000000000000004 a kimeneten | a double bináris kerekítése — nem bug | pénznél/pontos tizedesnél válts decimal-ra; másutt hagyd |
Az átlag egész lett (4, nem 4.5) | minden operandus egész volt → egészosztás | tegyél a kifejezésbe 2.0-t, vagy használj tört típusú változót |
jegy1 + jegy2 / 2 fura eredményt ad | a / előbb hajtódik végre, mint a + | zárójelezd: (jegy1 + jegy2) / 2.0 |
A 3,14 beírása hibasort dob | vessző a pont helyett | a tizedes elválasztó a kódban mindig pont |
Tortek, .NET 10.0.1 + 0.2-t double-ként, majd
0.1m + 0.2m-ként. Tegyél töréspontot, és a
Locals-ban is nézd meg a két értéket!decimal:decimal kenyer = 899.50m; decimal tej = 429.90m; decimal sajt = 1249.00m; decimal osszesen = kenyer + tej + sajt; Console.WriteLine(osszesen); // 2578.40
osszesen - osszesen / 1.27m) —
és a 1.27m-et tedd konstansba (B1!).double átlagot a 2.0-trükkel.Tort tipusok es aritmetika gyakorlat).Láttad a 0.30000000000000004-et és mellette a decimal pontos 0.3-ját; a blokk végösszege 2578.40; az átlagod 4.5.
⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás
Melyik sor fordul le, melyik nem — és miért?
double a = 2.5; ·
float b = 2.5; ·
float c = 2.5f; ·
decimal d = 2.5; ·
decimal e = 2.5m;
Számold ki papíron, aztán ellenőrizd géppel:
2 + 3 * 4 · (2 + 3) * 4 ·
10 - 4 - 3 · 10 - (4 - 3) ·
2 + 10 / 2 · (2 + 10) / 2
Egy munkatársad ezt írta három jegy átlagára:
jegy1 + jegy2 + jegy3 / 3.0 — a teszteléskor furcsa
értékek jönnek ki. Mi a hiba, és hogyan javítanád? Próbáld ki a 4, 5, 3
jegyekkel!
Írj „kasszablokkot”: három tétel bruttó ára decimal-ban, végösszeg, majd az ÁFA-tartalom kiírása. A 27%-os kulcs konstans legyen. Ellenőrizd az összegeket számológéppel!
Adj össze tízszer 0.1-et egy double változóban (a B2-es
rövidítéssel: osszeg += 0.1; tíz sorban), és
írasd ki. Mit kapsz 1.0 helyett? Ismételd meg decimal-lal. Magyarázd el
3-4 mondatban, mi történt — és hogy miért pont a decimal „tudja jól”.
Minden kérdésnél egy válasz helyes. A végén pontszámot kapsz.
| Fogalom | Jelentés |
|---|---|
| lebegőpontos (floating point) | törtszám-ábrázolás, amelyben a tizedespont „lebeg”: számjegyek × 2 hatványa |
float / double | 4 / 8 bájtos lebegőpontos típus, ~7 / ~15–16 értékes jeggyel |
decimal | 16 bájtos, tízes alapú törttípus, 28–29 értékes jeggyel — a pénz típusa |
| literál-utótag | a literál típusát jelöli: f (float), m (decimal), d (double, elhagyható) |
| értékes jegy | ahány számjegyet a típus megbízhatóan tárol — a pontosság mértéke |
| kerekítési hiba | a bináris közelítésből eredő parányi eltérés (0.1 + 0.2 ≠ 0.3) |
| precedencia (műveleti sorrend) | zárójel → * / % → + -, azonos szinten balról jobbra |
| implicit konverzió (előzetes) | az egész automatikus „előlépése” törtté vegyes kifejezésben — részletek: B6 |
float (ritka),
double (az alapértelmezés,
~15–16 jegy), decimal (tízes
alapú, pénzhez). Utótagok: f,
m.0.1 + 0.2 = 0.30000000000000004
nem bug: a 0.1 binárisan végtelen szakaszos, a double
közelítve tárolja — mint tízesben az 1/3-ot.int, mérés →
double, pénz →
decimal — számlán egy fillér eltérés
sem megengedett.* / % →
+ -, balról jobbra. Ha gondolkodnod kell
rajta, zárójelezz.7 / 2.0 = 3.5 — egy jól elhelyezett
.0 átbillenti az osztást a törtvilágba
(a teljes konverziórendszer: B6).