CodeGym /Kurslar /JAVA 25 SELF /Dəqiqlik problemləri və xüsusi dəyərlər

Dəqiqlik problemləri və xüsusi dəyərlər

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Elə görünür ki, kompüter “ağıllıdırsa”, 0.1 + 0.2 sadəcə 0.3 olmalıdır. Amma tam olaraq belə deyil. Gəlin sadə bir nümunə ilə aydınlaşdıraq.


double x = 0.1;
double y = 0.2;
double sum = x + y;
System.out.println(sum); // Proqram nə çıxaracaq?
Həqiqi ədədlərin toplanması: 0.3 gözləyirik, bəs əslində nə çıxır?

İndi isə 0.3 ilə müqayisə edin:

System.out.println(sum == 0.3); // Bəs burada true olacaq, yoxsa false?

Əgər false görsəniz, təəccüblənməyin!

Səbəb ədədlərin yaddaşda təmsil olunmasındadır

Kompüterlər ədədlərlə ikilik sistemdə işləyir. Amma onlu kəsrlərin heç də hamısını sonlu ikilik kəsr kimi təqdim etmək olmur, tıpkı 1/3-ü dəqiq onluq kəsr kimi yazmağın mümkün olmaması kimi (0.333...). Məsələn, 0.1 ikilik sistemdə sonsuz kəsrdir və onu saxlamaq üçün “yuvarlaqlaşdırmaq” lazım gəlir.

Sadə dillə desək, double bəzən sanki ədədinizi dəqiq saxlayırmış kimi “davranır”, amma əslində yalnız çox yaxın təxmini dəyəri saxlayır.

2. double ilə arifmetikada hansı “qəribəliklər” olur?

Gəlin praktiki nümunələrə baxaq.

Nümunə 1. Klassik 0.1 + 0.2 “möcüzəsi”

double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println(sum);            // 0.30000000000000004
System.out.println(sum == 0.3);     // false

Kompüter 0.3 deyil, 0.30000000000000004 çıxardı. Fərq kiçikdir, amma məsələn, maliyyə ilə məşğulsunuzsa — bu artıq kritikdir.

Nümunə 2. Təkrarlanan toplama

double result = 0;
for (int i = 0; i < 10; i++)
{
    result += 0.1;
}
System.out.println(result); // 0.9999999999999999

1.0 istəyirdiniz — bir az az alındı. Yenə də səbəb double daxilindəki yuvarlaqlaşdırmadadır.

Bu, real tapşırıqlarda niyə vacibdir

Çoxları belə düşünür: “Nə fərqi var, cüzi bir səhvdir!” Gəlin ödənişlər dünyasından bir nümunəyə baxaq.

Tutaq ki, internet bankınız 100 tranzaksiyanı 0.1 avrodan toplayır. Əgər proqramınız hər iterasiyada avronun yüz mində birini “itirirsə”, bank miqyasında artıq real pullar “itəcək”. Bu anda mühasib dərhal yanınıza gəlib soruşacaq: “Pulumuz hanı?!”

3. Həqiqi ədədləri düzgün necə müqayisə etməli

double çox vaxt gözlədiyiniz dəyəri tam dəqiq saxlaya bilmədiyi üçün, birbaşa == ilə müqayisə sizi aldada bilər. Bunun əvəzinə ədədlərin fərqinin modulunu müəyyən çox kiçik ədədlə (epsilon) müqayisə etmək qəbul olunub.

Toleransla müqayisə nümunəsi

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;

if (Math.abs(a - b) < epsilon)
{
    System.out.println("Demək olar ki, bərabərdir!"); // Bu cür müqayisə daha təhlükəsizdir
}

Burada deyirik: “Əgər ədədlər arasındakı fərq bir milyonda birindən kiçikdirsə, ədədləri bərabər sayırıq.”
Qeyd: Math.abs(value) funksiyası verilən ədədin mütləq qiymətini (modulunu) qaytarır.

4. double üçün xüsusi dəyərlər: Infinity, NaN, -Infinity

double tipi təkcə ədədləri deyil, xüsusi dəyərləri də saxlayır. Bunlar, riyaziyyat müəlliminin adi tələbəyə qəti qadağan edəcəyi hallarda yaranır.

Sonsuzluq (Infinity)

1-i 0-a bölsəniz nə olacaq?

double result = 1.0 / 0.0;
System.out.println(result); // Infinity

Java-da (və bir çox dildə) double üçün 0-a bölmə istisna yaratmır! Bunun əvəzinə nəticə xüsusi “müsbət sonsuzluq” dəyərinə çevrilir.

Mənfi sonsuzluq (-Infinity)

Mənfi ədədi 0-a bölsəniz, mənfi sonsuzluq alacaqsınız:

double result = -1.0 / 0.0;
System.out.println(result); // -Infinity

“Ədəd deyil” (NaN — Not a Number)

Tamamilə qəribə bir əməliyyat etsəniz, məsələn, mənfi ədədin kvadrat kökünü hesablamağa çalışsanız:

double result = Math.sqrt(-1);
System.out.println(result); // NaN

Yaxud 0.0 / 0.0 bölməsinin nəticəsi:

double result = 0.0 / 0.0;
System.out.println(result); // NaN

NaN — real həyatda ədəd sayılmayacaq hər şeydir.

Xüsusi dəyərləri yoxlama

Java-da xüsusi dəyərləri yoxlamaq üçün funksiyalar var:

System.out.println(Double.isInfinite(result));    // sonsuzluq olarsa true
System.out.println(Double.isNaN(result));         // NaN olarsa true

Cədvəl: double qeyri-adi əməliyyatlara necə reaksiya verir

Əməliyyat Nəticə double-da nə saxlanılır
1.0 / 0.0
Infinity +∞
-1.0 / 0.0
-Infinity -∞
0.0 / 0.0
NaN Ədəd deyil
Math.sqrt(-1)
NaN Ədəd deyil

5. Həqiqi ədədlərlə işləyərkən tipik səhvlər

Səhv №1: Kəsr ədədləri == ilə müqayisə etmək
Ən yaygın tələ: iki hesablanmış üzən nöqtəli ədədin bərabərliyini adi müqayisə ilə yoxlamağa cəhd. Yuvarlaqlaşdırma xətalarının yığılması səbəbindən demək olar ki, həmişə gözlənilməz nəticə alacaqsınız. Həmişə toleransla müqayisədən (epsilon) istifadə edin.

Səhv №2: Hesablamalarda gözlənilməz NaNInfinity
Əgər 0-a bölməni və ya mənfi ədədlərin kökünü nəzarətsiz buraxsanız, proqramda NaN və ya Infinity yarana və sonrakı bütün hesablamaları “yoluxdura” bilər. Şübhəli dəyərləri Double.isNaN()Double.isInfinite() ilə yoxlamağı unutmayın — bu, xoşagəlməz sürprizlərin qarşısını almağa kömək edəcək.

Səhv №3: NaN-i “işarə” kimi istifadə etmək
Bəzi yeni başlayanlar NaN-i xüsusi dəyər kimi yoxlamada istifadə edirlər, məsələn, “əgər tapılmadısa — NaN qaytaraq”. Amma yadınızda saxlayın: NaN hiyləgərdir və == ilə müqayisə işləməyəcək! Yalnız xüsusi metodlarla yoxlayın.

Səhv №4: 0.0-a böləndə istisna gözləmək
Tam ədədlərin bölünməsindən fərqli olaraq, double üçün 0.0-a bölmə səhv yaratmır, Infinity və ya NaN qaytarır. Bu isə səssiz və çətin tutulan xətalara səbəb ola bilər — nəticə var, amma gözlədiyiniz kimi deyil.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Kimyəvi məhlulun dəqiqliyinin yoxlanması 🧪
Kimyəvi məhlulun dəqiqliyinin yoxlanması 🧪
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Hesablama kainatının sərhədlərini öyrənmək 🌌
Hesablama kainatının sərhədlərini öyrənmək 🌌
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Naməlumu hesablamağa cəhd ❓
Naməlumu hesablamağa cəhd ❓
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Yüksək dəqiqlikli lazerin kalibrlənməsi 🔬
Yüksək dəqiqlikli lazerin kalibrlənməsi 🔬
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION