1. Giriş
Real həyatda nadir hallarda pul ödənişləri yüz trilyonuncu avro hissəsinə qədər dəqiqliklə olur, ya da otağın uzunluğu yüzdə bir millimetrə qədər ölçülür. Proqramlaşdırmada da belədir: double və ya float ilə işləyərkən nəticələr çox vaxt "çox kəsrli" olur.
Budur klassik bir problem:
double result = 10.0 / 3.0;
Console.WriteLine(result); // 3.3333333333333335
Bəs biz bu ədədi, məsələn, istifadəçini "qorxutmamaq" üçün yalnız iki vergüldən sonrakı rəqəmlə çıxarmaq istəsək? Bunun üçün yuvarlaqlaşdırma lazımdır.
2. C#-da əsas yuvarlaqlaşdırma metodları
C# kəsrli ədədi yuvarlaqlaşdırmaq üçün bir neçə üsul verir. Və burada maraqlı şeylər başlayır: yuvarlaqlaşdırma müxtəlif cür ola bilər! Gəlin əsas variantlara baxaq və fərqlərini başa düşək.
1) Math.Round funksiyası — klassik yuvarlaqlaşdırma
Ən populyar üsul — Math.Round metodudur. O, ədədi ən yaxın tam ədədə (və ya lazım olan vergüldən sonrakı rəqəm sayına) yuvarlaqlaşdırır.
Math.Round(ədəd[, rəqəm_sayı[, MidpointRounding]])
- ədəd — nəyi yuvarlaqlaşdırırıq.
- rəqəm_sayı — vergüldən sonra neçə rəqəm saxlamaq (default 0, yəni tam ədədə qədər).
- MidpointRounding — yarımçıq ədədlərin yuvarlaqlaşdırma üsulu (tezliklə danışacağıq).
Nümunələr:
double x = 2.71828;
Console.WriteLine(Math.Round(x)); // 3
Console.WriteLine(Math.Round(x, 2)); // 2.72
Console.WriteLine(Math.Round(x, 3)); // 2.718
Vizualizasiya:
| Giriş dəyəri | Math.Round(x) | Math.Round(x, 2) |
|---|---|---|
| 2.3 | 2 | 2.3 |
| 2.5 | 2 | 2.5 |
| 2.7 | 3 | 2.7 |
| 2.71828 | 3 | 2.72 |
Nəticənin tipi:
Bu dərsdəki bütün funksiyalar double tipini qaytarır, ona görə də əgər yuvarlaqlaşdırmanın nəticəsini təyin etmək istəsəniz, səhv ala bilərsiniz:
double result = 10.0 / 5.0; // Nəticə 2.0
int x = Math.Round(x); // Səhv! double tipini int tipli dəyişənə birbaşa vermək olmaz
Əgər double tipini int tipli dəyişənə vermək istəyirsinizsə, tip çevirməsini açıq şəkildə göstərməlisiniz:
double result = 10.0 / 5.0; // Nəticə 2.0
int x = (int) Math.Round(x); // Hər şey əladır!
2) Böyüyə və ya kiçiyə yuvarlaqlaşdırma
C# təkcə "klassik" yuvarlaqlaşdırmanı yox, həm də məcburi yuxarı və ya aşağı yuvarlaqlaşdırmanı dəstəkləyir.
Kiçiyə yuvarlaqlaşdırma (Math.Floor)
Math.Floor metodu sadəcə kəsr hissəni "atır" (mənfi sonsuzluğa doğru). Yəni həmişə aşağı yuvarlaqlaşdırır!
Console.WriteLine(Math.Floor(2.99)); // 2
Console.WriteLine(Math.Floor(-2.99)); // -3
Böyüyə yuvarlaqlaşdırma (Math.Ceiling)
Math.Ceiling metodu — Floor-un əksidir: həmişə yuxarı yuvarlaqlaşdırır (müsbət sonsuzluğa doğru).
Console.WriteLine(Math.Ceiling(2.01)); // 3
Console.WriteLine(Math.Ceiling(-2.01)); // -2
Müqayisəli sxem:
| Funksiya | 2.3 | -2.3 |
|---|---|---|
| Math.Round | 2 | -2 |
| Math.Floor | 2 | -3 |
| Math.Ceiling | 3 | -2 |
3) Truncate: sadəcə kəsr hissəni kəsmək
Math.Truncate metodu — "sakit cərrah". O, sadəcə kəsr hissəni silir, yuvarlaqlaşdırma baxımından riyazi düzgünlüyə fikir vermir. Əgər x müsbətdirsə — nəticə Floor kimi, mənfidirsə — Ceiling kimi.
Console.WriteLine(Math.Truncate(2.99)); // 2
Console.WriteLine(Math.Truncate(-2.99)); // -2
3. Math.Round "yarımçıq" üçün necə işləyir? (MidpointRounding)
Təsəvvür et: səndə 2.5 var. Yuvarlaqlaşdırmaq lazımdır — bəs hara? Sanki 2 və 3 arasında "bərabərdir". Riyaziyyatda iki məşhur yanaşma var:
- Böyüyə yuvarlaqlaşdırma ("ən yaxın böyüyə qədər")
- Ən yaxın cütdə yuvarlaqlaşdırma (Banker's rounding)
C# default olaraq ikinci yanaşmanı istifadə edir — ən yaxın cütdə yuvarlaqlaşdırma ("banker's rounding", ya da "cütdə yuvarlaqlaşdırma").
Console.WriteLine(Math.Round(2.5)); // 2
Console.WriteLine(Math.Round(3.5)); // 4
Niyə? Çünki iki bərabər məsafəli tam ədəddən cüt olan "qalib gəlir". Bu ona görədir ki, çoxlu yuvarlaqlaşdırmada nəticə sistematik olaraq artmaya və ya azalmaya getməsin. Bu, məsələn, bankda böyük məbləğləri hesablarkən çox vacibdir (ad da buradan gəlir).
Əgər həmişə yuxarı yuvarlaqlaşdırmaq istəyirsənsə, istədiyin rejimi açıq şəkildə göstərə bilərsən:
// Həmişə "sıfırdan uzağa" yuvarlaqlaşdır
Console.WriteLine(Math.Round(2.5, 0, MidpointRounding.AwayFromZero)); // 3
Console.WriteLine(Math.Round(-2.5, 0, MidpointRounding.AwayFromZero)); // -3
MidpointRounding rejimləri cədvəli:
| Giriş dəyəri | Round (Default) | AwayFromZero | ToZero / ToEven |
|---|---|---|---|
| 2.5 | 2 | 3 | 2 |
| 3.5 | 4 | 4 | 4 |
| -2.5 | -2 | -3 | -2 |
4. Lazım olan rəqəm sayına yuvarlaqlaşdırma: "səkkizlərə" və "üçlərə" diqqət et!
Bəzən tam ədədə yox, məsələn, iki vergüldən sonrakı rəqəmə qədər yuvarlaqlaşdırmaq lazımdır (məsələn, pul və ya faiz çıxışı üçün).
double price = 149.9999;
double roundedPrice = Math.Round(price, 2);
Console.WriteLine(roundedPrice); // 150
Bəs biz sadəcə artıq rəqəmləri "atmaq", amma yuvarlaqlaşdırmamaq istəsək? Məsələn, 123.4567-dən 123.45 etmək.
Bunu kiçik bir trick ilə etmək olar:
double num = 123.4567;
double result = Math.Floor(num * 100) / 100;
Console.WriteLine(result); // 123.45
Biz əl ilə vergülü "sürüşdürürük", kəsr hissəni kəsirik və geri qaytarırıq.
5. Çıxış formatlaşdırılması vs yuvarlaqlaşdırma
Çıxışın formatlaşdırılması ({x:F2}) — bu həmişə "gerçək" yuvarlaqlaşdırma deyil, sadəcə ekranda ədədin necə göründüyünün "maskası"dır. Yaddaşda o, yenə də uzun "quyruqlu" double olaraq qalacaq. Əgər sən həqiqətən dəyəri yuvarlaqlaşdırıb saxlamaq istəyirsənsə, Math.Round istifadə et.
Budur bir nümunə, harada fərq kritik ola bilər:
double value = 2.555;
Console.WriteLine($"{value:F2}"); // 2.56
Console.WriteLine(Math.Round(value, 2)); // 2.56
double stored = Math.Round(value, 2);
Console.WriteLine(stored); // 2.56
// Amma əgər sadəcə formatla çıxarsan, yuvarlaqlaşdırmadan...
Console.WriteLine($"{value:F2}"); // 2.56, amma yaddaşda — 2.555
6. Tipik səhvlər və nüanslar
- Maliyyə hesablamalarında double ilə yuvarlaqlaşdırmadan istifadə etmə! Pul üçün .NET-də xüsusi decimal tipi var — o, "float oyunları" etmir (ətraflı — növbəti dərslərdə).
- Bədbəxt "asılı səkkizlər": ikili yaddaşda saxlanmaya görə bütün ədədlər "gözə görə" məntiqli yuvarlaqlaşmır. Məsələn, 0.1 + 0.2 heç də həmişə 0.3 olmur.
- Math.Floor və Math.Round qarışdırma! Birinci həmişə aşağı, ikinci — riyaziyyat necə deyirsə elə.
- Nəzarətsiz səhv yığılması: əgər tez-tez aralıq nəticələri yuvarlaqlaşdırırsansa (məsələn, dövrün içində), yekun nəticə gözlənilmədən "qaça" bilər. Adətən yalnız son nəticəni yuvarlaqlaşdırmaq daha yaxşıdır, bütün aralıq addımları yox.
7. Son cədvəl: hansı metod nə verir?
| Giriş dəyəri | Math.Round(x) | Math.Floor(x) | Math.Ceiling(x) | Math.Truncate(x) |
|---|---|---|---|---|
| 3.2 | 3 | 3 | 4 | 3 |
| 3.5 | 4 | 3 | 4 | 3 |
| -3.2 | -3 | -4 | -3 | -3 |
| -3.5 | -4 | -4 | -3 | -3 |
8. Maraqlı faktlar
- Bir dəfə NASA kosmik aparatını koordinatların qeyri-dəqiq yuvarlaqlaşdırılması və metrik/imperial vahid fərqinə görə itirdi. Əsas: yuvarlaqlaşdırmanı düşünərək et!
- Banklar çoxdan "banker's rounding"-ə keçib ki, qəpik itirməsinlər — əvvəllər hamı "köhnə qayda" ilə yuxarı yuvarlaqlaşdırırdı və müştərilər hər köçürmədə sentin hissəsini itirirdilər.
- C#-da hətta Math.Sign metodu var, hansı ki, ədədin işarəsini qaytarır — bəzən yuvarlaqlaşdırmadan əvvəl faydalıdır, özün seçmək üçün hara "kəsmək" lazımdır.
GO TO FULL VERSION