C'de Temel Fonksiyonların İşleyişleri

Başlatan FxDev, 10 Mayıs 2011, 23:40:17

FxDev

Hepimiz C ve C dilinde math.h kütüphanesini bir kere de olsa kullanmışızdır. Hepimizin bildiği üzere içinde bulunan sin cos ve sqrt gibi işlemler işimizi oldukça kolaylaştırmakta. Peki bu kod yapısı örneğin 3'ün karekökünü bana nasıl veriyor? Ya da bir sayının sin cos'unu nasıl hesaplıyor. İçeriğindeki mantık nedir?

Erol YILMAZ

#1
Numerik Hesaplama Yöntemleri kullanılıyor.
Misal karekök için birçok yöntem varmış...

http://en.wikipedia.org/wiki/Methods_of_computing_square_roots

Araştırdıkça konu hoşuma gitmeye başladı.
Özellikle Newton matematik için ciddi gelişimler yapmış. Bkn. Türev ve İntegral :)

Tamsayı Karekök Algoritması:
http://www.embedded-systems.com/98/9802fe2.htm

Diğerlerini bulan arkadaşların çözümlerini de bekleriz.

Tagli

Trigonometrik fonksiyonlar için tablo kullanılıyor olabilir. Bunları ekleyince program hafızası kullanımında ciddi bir artış gözleniyor. Emin değilim ama.

Ayrıca, fonksiyonları kullanmak bir kenara, floating point ile işlem yapmak bile ayrı bir mesele. Floating point ile dört işlem yapılırken bile arka planda bir dolu iş yapılıyor. C18'de bu alt işlemlerin her birine karşılık gelen ayrı asm dosyaları var.

Fonksiyonlarla ilgili kodların bir kısmını C18'in klasörü içinde bulmak mümkün ama benim bulduklarım sistemin nasıl çalıştığı hakkında tam bir bilgi vermiyor. Belki de ben görememişimdir.
Gökçe Tağlıoğlu

Erol YILMAZ

Trigonometrik ifadelerin de açılımı var,
Gördüğüm kadarı ile gayet kolay hesaplabiliyor.
Float sayı ile hesabı gerektiğinden uzun süren işlemler olabilir.

http://www.pdfill.com/example/Numerical_Methods.pdf


serdararikan

#4
aradığınız cevap Taylor serisi olabilirmi?

http://dotancohen.com/eng/taylor-sine.php

z

Hesaplayicilarda sikca kullanilan algoritma Cordic algoritmasidir.

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muuzoo

#6
Bu konuyu araştırırken çok ilginç bir kod buldum. Yöntem aslında 1990'larda geliştirilmiş. 1999 yılında Quake III oyun motorunda kullanılmış, 2002,2003 yıllarında unix forumlarına düşümüş fakat 2005 yılında quake3 kodlarının paylaşılması ile patlama yapmış. Bu kadar bilgiden sonra önce kaynak sayfa :

http://en.wikipedia.org/wiki/Fast_inverse_square_root

Ve yöntem. En başlarda olay pek anlaşılamamış, zaten kod açıklamalarından göreceksiniz  ;) Tüm olay şu sihirli sayıda : 0x5f3759df

float Q_rsqrt( float number )
{
        long i;
        float x2, y;
        const float threehalfs = 1.5F;
 
        x2 = number * 0.5F;
        y  = number;
        i  = * ( long * ) &y;                       // evil floating point bit level hacking [sic]
        i  = 0x5f3759df - ( i >> 1 );               // what the fuck? [sic]
        y  = * ( float * ) &i;
        y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//    y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed
 
        return y;
}


32bit fp için 0x5f3759df
64bit fp için 0x5fe6eb50c7aa19f9.
gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

NaMcHo

y  = * ( float * ) &i   şurdaki yapılan işlem nedir?   stm32 nin kütüphanelerindede   *(x *) şeklinde çok tanımlama var burdada görünce dayanamadım sorim dedim.

jackal183

trigonometrik işlemlerin çözümü için, seriye açılımları kullanılıyor, seriye açılımları birçoğunuz üniversitede mat2 dersinde görmüşsünüzdür, derleyiciler hangi seriye açılımı kullanıyor bilmiyorum ama arkadaşın da söylediği gibi taylor serisi kullanılan yöntemlerden biridir, bunun dışında mclourin serisi de vardır

Tagli

Alıntı yapılan: NaMcHo - 11 Mayıs 2011, 10:39:39
y  = * ( float * ) &i   şurdaki yapılan işlem nedir?   stm32 nin kütüphanelerindede   *(x *) şeklinde çok tanımlama var burdada görünce dayanamadım sorim dedim.
O değişkenin adresinde tutulan değeri tam sayı olarak değil float olarak değerlendir demek istiyor.

Yanlış anlamadıysam, üzerinde bit işlemleri yapabilmek için öncelikle float y'nin long olduğunu varsayıp kaydırma yapmış. Sonra çıkan sonucu tekrar derleyiciye "bu aslında bir float'tır" diye göstermiş.
Gökçe Tağlıoğlu

Klein

Alıntı yapılan: NaMcHo - 11 Mayıs 2011, 10:39:39
y  = * ( float * ) &i   şurdaki yapılan işlem nedir?   stm32 nin kütüphanelerindede   *(x *) şeklinde çok tanımlama var burdada görünce dayanamadım sorim dedim.

burada ilk yıldız , i nin gösterdiği adreste bulunan veriyi al ifadesidir. eğer * koymasaydı alacağımız değer  i nin adresi  olacaktı.

float ifadesi Tagli'nin dediği gibi tip dönüşüm ifadesidir. Sonucu float olaak değerlendir demek.  float ifadesinin sağındaki * ise   sonucun da bir pointer ile aktarılacağını ifade ediyor.

aşağıdaki kod parçacıkları eeproma float değer yazma ve okuma işi yaparlar.  bu örnek belki durumu biraz daha iyi açıklar.
void ee_read_float(unsigned int addr , float *floatptr){
unsigned char edata;
unsigned int I;
	for(I=0;I<4;I++){
		edata=ee_read_byte(I+addr);	
  		*((unsigned char *)floatptr+I) = edata;
	}
}

void ee_write_long(unsigned int addr , long int *longptr){
unsigned char edata;
unsigned int I;
 	for(I=0;I<4;I++){
		edata = *((unsigned char *)longptr+I);
		ee_write_byte(addr+I,edata);
	}
}

Klein

yukarıdakialgoritmada anlamadığım bir şey var.

const float threehalfs = 1.5F;
 x2 = number * 0.5F;


buradaki 1.5F ve 0.5F  daha önceden  #define ile tanımlanmış sabitler mi? yoksa benim bilmediğim bir jargon mu?

Tagli

Yani aslında yapılan iş bir çeşit derleyiciyi kandırmak. O alanlarda aslında float saklanıyor ama sen derleyiciye "Hayır, bu bir long. Sen işlemini ona göre yap." diyorsun. Elbette ilgili sayıyı long gibi alıp üzerinde işlem yaparsan, float değerine çok garip şeyler olabilir  ;). Yukarıdaki kodu garip yapan şey de bu. Adam float sayıyı long gibi gösterip üzerinde garip işlemler yapmış...

Dikkat edilmesi gereken şey casting diye bilinen bu işlemin, değişken üzerinde değil, onun pointer'ı üzerinde yapılıyor olması. float değerini long'a cast etseydi, fazla kafa karıştırmazdı. Örneğin 5.256 ifadesi 5 olurdu. Ama pointer'ı cast etmesi bambaşka birşey.

Klein, bildiğim kadarıyla sonlarında bulunan F, o değerlerin float tipinde olduğunu gösteriyor derleyiciye. Varsayılan değer nedir bilmiyorum. Bilgisayarda genelde double oluyor, yani hiçbir şey eklemezsen sonuna. float olarak alınmasını istiyorsan özellikle F ekliyorsun sonuna. Bu tür şeyler genelde gerekmiyor ama bazen hiç ummadığın yerlerde kıllık çıkarabiliyor. Şu başlığı bir incele.
Gökçe Tağlıoğlu

yamak

int main(void)
{
  long i=5;
  float y;
  y=*(float*)&i;
  printf("%f",y);
    getch();

arkadaşlar yukarıdaki kodu denemek için şöyle küçük bir program yazdım sonucunu 0.0fakat derleyici sonucu 0.000 olarak verdi nedeni nedir acaba?

Tagli

Wikipedia'daki başlığı bir incele (kodu bilgisayarda yazdığını varsayıyorum).





Şimdi, kutuların içinde "00000000 00000000 00000000 00000101" olduğunu varsay, yani 5.

Olay kafamda yanlış canlanmadıysa, bunu float gibi düşündüğünde çok küçük bir sayı çıkacak. Bu yüzden ekrana 0 olarak basılıyor olabilir.
Gökçe Tağlıoğlu