25 Temmuz 2018 Çarşamba

IEEE754 ve Exception

Giriş
IEEE754 kayan nokta işlemlerinde exception atma yeteneği kapalı olarak başlar. Hataları yakalamak için bazı çağrılar ile bu yeteneği etkinleştirmek gerekiyor.

Exceptionlar Nelerdir
Bir sayının sıfıra bölünmesi (division by zero), taşma (overflow) gibi olaylar hardware trap'e sebep olur. Bu trap ise işletim sistemi tarafından yakalanır. Yakalanan trap'in software exception'a dönüştürülmesi gerekir.

1. Sıfıra Bölme (Division By Zero)
Bölünen sıfırdan farklı ve bölen sıfır ise IEEE754 sonucun artı veya eksi infinity çıkmasını söylüyor. Açıklaması şöyle.
  • Invalid operation: mathematically undefined, e.g., the square root of a negative number. By default, returns qNaN.
  • Division by zero: an operation on finite operands gives an exact infinite result, e.g., 1/0 or log(0). By default, returns ±infinity.
  • Overflow: a result is too large to be represented correctly (i.e., its exponent with an unbounded exponent range would be larger than emax). By default, returns ±infinity for the round-to-nearest modes (and follows the rounding rules for the directed rounding modes).
  • Underflow: a result is very small (outside the normal range) and is inexact. By default, returns a subnormal or zero (following the rounding rules).
  • Inexact: the exact (i.e., unrounded) result is not representable exactly. By default, returns the correctly rounded result.
Örnek
Şöyle yaparız
double a = 5.;
double b = 0.;
double c = a / b; //divide by zero
C++
IEEE754 ve Division By Zero yazısına taşıdım.

Örnek - C#
C++ ile aynı şekilde çalışır. Bölen 0 ise sonuç +inf veya -inf çıkar. Şöyle yaparız.
double total = 3.0;
int numberOf = 0;

var tot = total / numberOf; // tot is double, tot == double.PositiveInfinity
Örnek - Java
Şöyle yaparız.
double a = 1.0;
double b = 0.0;
double c = a / b;
boolean flag = Double.isNaN(c);
System.out.println(flag); // False?
System.out.println(c); // Infinity
2. Overflow 
Şeklen şöyle


Örnek
Şöyle yaparız.
double a = DBL_MAX;
double b = 10.0;
double c = a * b; //Burada exception atılabilir.
C99
Exceptionlarla ilgili metodlar fenv.h içinde tanımlı. Aslında exception kelimesini kullanıyorum ancak C dilinde gerçekte exception olmadığı için, hatalar bazı bitlerin kaldırılması şeklinde vurgulanıyor.
fetestexcept metodu
fetestexcept() ile kayan nokta işlemlerindeki hataları yakalamak mümkün.
feclearexcept() metodu
fetestexcept() ile hata bitlerini almadan önce feclearexcept() ile bitleri temizlemek gerekiyor. Örnek programı buradaki soruyu okurken gördüm.

C++11
C ile aynı şekilde kullanılıyor. Tek fark metodların std namespace içinde olması. Örneğin std::fetestexcept() gibi.

Windows
Visual Studio 2012'ye kadar C99 uyumlu olmadığı için başka metodları kullanmak lazım. Yukarıda anlatılan hardware trap'in software exception'a dönüşmesi için VS içinde bazı ayarlar yapmak gerekir.
Properties / Code Generation / Enable C++ Exceptions : Yes with SEH Exceptions seçeneğini etkinleştirmek gerekir. SEH (Structured Exception Handling) hem donanım hem de yazılım exceptionları için kullanılır.

_control87 metodu
Örnekte ilk _control87() çağrısı ile atanmış bitler alınıyor. Bazı bitler sıfırlanıyor ve ikinci _control87 çağrısı ile tekrar atanıyor.
void TurnOnFloatingExceptions()
{
  unsigned int cw;
  // Note : same result with controlfp
  cw = _control87(0,0) & MCW_EM;
  cw &= ~(_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW);
  _control87(cw,MCW_EM);

}
_controlfp_s metodu
_controlfp_s metodu yazısına taşıdım.

Hiç yorum yok:

Yorum Gönder