26 Ağustos 2019 Pazartesi

IEEE754 ve Division By Zero

Giriş
Bu yazıda hem floation point için division by zero hem de integer için division by zero ele alınıyor.

Açıklaması şöyle.
C++ standard does not force the IEEE 754 standard, because that depends mostly on hardware architecture.
1. IEEE 754  Destekleniyorsa
Eğer IEEE 754 standardı destekleniyorsa açıklaması şöyle.
If the second operand is zero, the behavior is undefined, except that if floating-point division is taking place and the type supports IEEE floating-point arithmetic (see std::numeric_limits::is_iec559), then:
  • if one operand is NaN, the result is NaN
  • dividing a non-zero number by ±0.0 gives the correctly-signed infinity and FE_DIVBYZERO is raised
  • dividing 0.0 by 0.0 gives NaN and FE_INVALID is raised
- Madde 1 bölen veya bölünen NaN ise sonuç NaN'dır diyor.
- Madde 2 eğer bölen artı veya eksi 0 ise ve bölünen sıfırdan farklı bir rakam ise sonu artı veya eksi sonsuzdur diyor.
- Madde 3 hem bölen hem de bölünen 0 ise sonuç NaN'dır diyor.

Bu maddeleri toplarsak şu açıklama uygun olur. Yani ters bir durum varsa sonuç NaN veya +Infinity veya -Infinity çıkar.
Floating point division by zero is well defined by IEEE and gives infinity (either positive or negative according to the value of the numerator (or NaN for ±0) ).
Benzer bir açıklama şöyle.
If the hardware/compiler implement correctly the IEEE 754 standard, the division will provide the expected INF, -INF and NaN,
Örnek
Elimizde şöyle bir kod olsun.
float f = 42;
float g = f / 0.0f;
printf("%f\n", g);
Çıktı olarak şunu alırız.
inf
Hardware Exception
Açıklaması şöyle. Hardware exception ile C++ exception farklı şeylerdir.
"If the divisor is zero and the dividend is a finite nonzero number, then the division by zero exception shall be signaled. The default result shall be a correctly signed infinity" (IEE 754 paragraph 7.2) (the “exception”
here refers to the IEEE 754 FP exception, not C++ exception...
Hardware exception'ı test etmek için std::fetestexcept() metodu kullanılır. C kullanıyorsak fetestexcept() metodu kullanılır.

Hardware Exception'ı C++'a exception'a çevirme işi tamamen derleyiciye özel.
GCC için GNU feenableexcept yazısına bakınız.
MSVC için Visual Studio _set_se_translator yazısına bakınız.

Exception Tipleri
Açıklaması şöyle.
IEEE 754 defines five basic types of floating point exceptions: invalid operation, division by zero, overflow, underflow and inexact. The first three (invalid, division, and overflow) are sometimes collectively called common exceptions. These exceptions can seldom be ignored when they occur. ieee_handler(3m) gives an easy way to trap on common exceptions only. The other two exceptions (underflow and inexact) are seen more often--in fact, most floating point operations incur the inexact exception--and they can usually, though not always, be safely ignored.
Hardware Exception ve Trap Yani Signal
Açıklaması şöyle.
Often, programmers do not write programs with exceptions in mind, so when an exception is detected, the first question asked is: Where did the exception occur? One way to locate where an exception occurs is to test the exception flags at various points throughout a program, but to isolate an exception precisely by this approach can require many tests and carry a significant overhead.

An easier way to determine where an exception occurs is to enable its trap. When an exception whose trap is enabled occurs, the operating system notifies the program by sending a SIGFPE signal (see the signal(5) manual page). Thus, by enabling trapping for an exception, you can determine where the exception occurs either by running under a debugger and stopping on receipt of a SIGFPE signal or by establishing a SIGFPE handler that prints the address of the instruction where the exception occurred. Note that trapping must be enabled for an exception to generate a SIGFPE signal; when trapping is disabled and an exception occurs, the corresponding flag is set and execution continues with the default result specified in TABLE 4-1, but no signal is delivered.
Örnek
Şöyle yaparız. Burada IEEE 754 standardının desteklendiğini ve exception fırlatmanın kapalı olduğunu varsaydık. Sonuç olarak a +inf , b -inf, c NaN değerini alır
double a = 1.0 / 0; //Madde 2
double b = -1.0 / 0; //Madde 2
double c = 0.0 / 0; //Madde 3
std::cout << a << b << c;
2. IEEE 754  Desteklenmiyorsa
Eğer IEEE 754 desteklenmiyorsa sonuç undefined. Açıklaması şöyle
C++ Standard 5.6.4
... If the second operand of / or % is zero the behavior is undefined
Bir çok C++ kütüphanesi bu durumu ele alabilmek için ayarlanabilir bir çağrı veriyor. Açıklaması şöyle
If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [ Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. —end note ]
Örnek - C++
Bazı C++ derleyicileri uyarı üretebilir. Elimizde şöyle bir kod olsun.
double d = 15.50;
std::cout<<(d/0)<<std::endl;
Şu uyarıyı üretebilir.
warning: division by zero [-Wdiv-by-zero]
     std::cout<<(d/0)<<std::endl;
3. Integer İçin Divison By Zero
Açıklamsası şöyle.
The behaviour of integer division by zero is undefined by the C++ standard. It is not required to throw an exception. Floating point division by zero is also undefined but IEEE754 defines it.
Örnek
Elimizde şöyle bir kod olsun. Bu kod hiç bir hata vermeyebilir. Visual Studio'da ise Exit Code -1073741676 ile uygulama sonlanır.
int d = 0;
d /= d;


Hiç yorum yok:

Yorum Gönder