IEEE 754 etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
IEEE 754 etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

9 Aralık 2019 Pazartesi

Matematik Kütüphanesi

Giriş
C için Şu satır dahil edilir.
#include <math.h>
abs - mutlak değer (absolute value)
std::abs yazısına taşıdım.

acos metodu
Şöyle yaparız.
const double pi = std::acos(-1);
exp 
e üssü x hesaplamasını yapar. e Euler sayısıdır. Bu metod exp (a) yerine pow (e,a) şeklinde de yazılabilir ancak muhtemelen daha yavaş çalışır.

exp2
2 üssü x hesaplamasını yapar.

fma (floating multiply and add)
Bu fonksisyon tam nerede kullanılıyor bilmiyorum ancak fma (x,y,z) = ((x*y)+z) anlamına geliyor.

std::fmod (bölme sonucunda kalanı bulma)
std::fmod yazısına taşıdım

frexp (fraction ve exponent'a ayırma)
Bu fonksiyon ile verilen sayıyı significand ve exponent olarak ayırmak mümkün. Metodun döndürdüğü significand/mantissa ya 0 veya [0.5 - 1.0) aralığında oluyor.

Burada bir şekil var bu görülebiliyor. Exponent'in 2 nin üssü şeklinde verildiğini unutmamak lazım. 
Yani şekilde exponent olarak 5 verilse bile aslında 2 ^ 5 yani 32 olarak düşünmek lazım. 
0.965625 * 32 = 30.9

Bu yöntemden farklı olarak eğer ondalık sayıyı tam sayı ve küsurat olarak ayırmak istersek aşağıdakine benzer bir kodu da kullanabiliriz.

log metodu
İki tane log metodu var.
std::log (5.5); // Gives natural log with base e
std::log10 (5.5); // Gives common log with base 10
log10 metodu
std::log10 metodu yazısına taşıdım.

M_PI Sabiti
Pi sayısıdır. Bu sabit sanırım C++ standardında tanımlı değil ancak bir çok kütüphane sunuyor.

Eğer Kendimiz Tanımlama İstersek
Örnek
Şöyle yaparız.
constexpr double pi = 3.14159265358979323846;
Örnek
Şöyle yaparız.
const double pi = std::acos(-1);
Örnek
Monte Carlo kullanarak hesaplanabilir.

Örnek
Şöyle yaparız.
double area(Circle radius) {
  return M_PI * radius * radius;
}
modff
modff metodu yazısına taşıdım

sqrt - kare kök (square root)
Üç tane farklı imza var.
double sqrt(double _X);
float sqrt(float _X);
long double sqrt(long double _X);
Bu metod yerine kendimiz kodlamak istersek Newton-Raphson yöntemi kullanılabilir.

std::remainder
std::remainder yazısına taşıdım

sin metodu
Şöyle yaparız.
sin (angle * M_PI/180);
tgamma metodu
1'den büyük sayılar için factorial ile aynıdır. Şöyle yaparız.
for (int i = 1 ; i != 10 ; i++) {
    printf("%lld %f\n", factorial(i), tgamma(i+1));
}
Çıktı olarak şunu alırız.
1 1.000000
2 2.000000
6 6.000000
24 24.000000
120 120.000000
720 720.000000
5040 5040.000000
40320 40320.000000
362880 362880.000000

10 Nisan 2019 Çarşamba

IEEE 754 ve İki Sayının Eşitliği

Giriş
Yöntemler şöyle
1. Her sayı belli bir küsurat hanesine yuvarlanır ve >, < işlemine sokulur.
2. Epsilon veya diğer ismiyle tolerans değeri kullanılarak karşılaştırma yapılır.

3. Belirtilen ULP (x ve y değeri arassındaki kaç tane double olduğu) kadar yakın olup olmadığının karşılaştırması yapılır.

Mutlak Epsilon'a Göre Karşılaştırmak
Açıklaması şöyle. x ve y küçük sayılar iken kullanışlı. Burada sadece tek bir epsilon aralığına bakılıyor.
For numbers between 1.0 and 2.0 FLT_EPSILON represents the difference between adjacent floats. For numbers smaller than 1.0 an epsilon of FLT_EPSILON quickly becomes too large, and with small enough numbers FLT_EPSILON may be bigger than the numbers you are comparing (a variant of this led to a flaky Chromium test)!

For numbers larger than 2.0 the gap between floats grows larger and if you compare floats using FLT_EPSILON then you are just doing a more-expensive and less-obvious equality check. That is, if two floats greater than 2.0 are not the same then their difference is guaranteed to be greater than FLT_EPSILON. For numbers above 16777216 the appropriate epsilon to use for floats is actually greater than one, and a comparison using FLT_EPSILON just makes you look foolish. We don’t want that.
Örnek
Şöyle yaparız.
bool absoluteToleranceCompare(double x, double y)
{
  return std::fabs(x - y) <= std::numeric_limits<double>::epsilon() ;
}
Relative Epsilon'a Göre Karşılaştırmak
Açıklaması şöyle. x ve y büyük sayılar ilen kullanışlı. Burada daha fazla büyük epsilon aralığına bakılıyor.
The idea of a relative epsilon comparison is to find the difference between the two numbers, and see how big it is compared  to their magnitudes. In order to get consistent results you should always compare the difference to the larger of the two numbers. In English:

To compare f1 and f2 calculate diff = fabs(f1-f2). If diff is smaller than n% of max(abs(f1),abs(f2)) then f1 and f2 can be considered equal.
Epsilon şöyle hesaplanır.
double Epsilon = std::max(x, y) * std::numeric_limits<double>::epsilon();
Örnek
Şöyle yaparız. Yukarıdaki Epsilon hesaplamadan farklı olarak x ve y'nin mutlak değerinin max()'ı alınıyor. Fark yaratır mı bilmiyorum.
bool relativeToleranceCompare(double x, double y)
{
  double maxXY = std::max( std::fabs(x) , std::fabs(y) ) ;
  return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXY ;
}
Eğer her iki örneği birleştirmek istersek şöyle yaparız
bool combinedToleranceCompare(double x, double y)
{
  double maxXYOne = std::max( { 1.0, std::fabs(x) , std::fabs(y) } ) ;

  return std::fabs(x - y) <= std::numeric_limits<double>::epsilon()*maxXYOne ;
}
Örnek
The art of computer programming by Knuth kitabındaki örnekler şöyle. approximatelyEqual() metodu relativeToleranceCompare() metodu ile aynı. essentiallyEqual() metodunu anlamadım.
bool approximatelyEqual(float a, float b, float epsilon)
{
  return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool essentiallyEqual(float a, float b, float epsilon)
{
  return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyGreaterThan(float a, float b, float epsilon)
{
  return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyLessThan(float a, float b, float epsilon)
{
  return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}
ULP'ye Göre Karşılaştırmak
Açıklaması şöyle.
We already know that adjacent floats have integer representations that are adjacent. This means that if we subtract the integer representations of two numbers then the difference tells us how far apart the numbers are in float space. 
Yani
In other words, if you subtract the integer representations and get one, then the two floats are as close as they can be without being equal. If you get two then they are still really close, with just one float between them. The difference between the integer representations tells us how many Units in the Last Place the numbers differ by. This is usually shortened to ULP, as in “these two floats differ by two ULPs.”
Şöyle yaparız.
// Usable AlmostEqual function    
bool AlmostEqual2sComplement(float A, float B, int maxUlps)    
{    
    // Make sure maxUlps is non-negative and small enough that the    
    // default NAN won't compare as equal to anything.    
    assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);    
    int aInt = *(int*)&A;    
    // Make aInt lexicographically ordered as a twos-complement int    
    if (aInt < 0)    
        aInt = 0x80000000 - aInt;    
    // Make bInt lexicographically ordered as a twos-complement int    
    int bInt = *(int*)&B;    
    if (bInt < 0)    
        bInt = 0x80000000 - bInt;    
    int intDiff = abs(aInt - bInt);    
    if (intDiff <= maxUlps)    
        return true;    
    return false;    
}