for dongusu icindeki float sayiyi bulma

Başlatan Yuunus, 02 Nisan 2022, 01:32:33

Yuunus

merhaba, asagidaki kodda float degiskenin degeri ile sabit bir float sayiyi karsilastirip mesaj ile bildirmek istiyorum lakin sayiyi karsilastirip mesaji yazamiyor, nerede hata yapiyorum, ortam linux, ide stm32cubeide compiler g++. tesekkurler.
#include <stdio.h>
#include <stdlib.h>

float f;

int main(void) {

for(f=0; f<=1; f+=0.000001)
{

	if(f==float(0.081267))
	{
		printf("sayi bulundu");
	}
}
	return EXIT_SUCCESS;
}

Tagli

#1
Yazılımın temel kurallarından biridir: Float değişkenlerle doğrudan eşitlik testi yapılmaz. Bu kurala bağlı olarak float değişkenler döngü sayacı olarak da kullanılmazlar.

Bunun sebebi işlemcilerin 10'luk değil 2'lik tabanla çalışması. Bu yüzden 10'luk tabanda yazılan bir sayının 2'lik tabanda tam karşılığı olmayabilir. Atıyorum, 1.0 yazdığın sayı işlemci tarafından gerçekte 1.000000001 veya 0.99999998 olarak algılanmış olabilir (sadece örnek verdim, yoksa 1.0'ın 2'lik tabanda da tam karşılığı olsa gerek).

Peki ne yapmalı? Öncelikle yazılım kalitesi açısından döngü sayacı olarak float kullanmayı tamamen aklından çıkar. Teknik olarak imkansız olmasa da hataya açık yanlış bir uygulamadır. İkincisi, float sayılarda eşitlik karşılaştırması yaparken, küçük bir hata payı bırakarak karşılaştırma yap. Yani, mesela a ve b float ise, if (a == b) değil, if (abs(a - b) < 0.00001) gibi bir ifade kullan.
Gökçe Tağlıoğlu

Yuunus

#2
@Tagli zaten buyuk yada kucuk esit gibi kontroller ile esitligi kontrol ettim sagol ama merak ettigim neden increment degerini milyonda bir artirirken istedigim kontrolu yapamiyorum benim artis oranim 0.000001, 0
.0000013 filan degilki, asil anlamadigim bu.
yani float degisken uzerinde bolme islemi filan yapmiyorum bu kusurat isi nerden geliyor, kaldiki "f" nin degerini dongu icinde ekrana yazdirdigimda aradigim degiskeni orada goruyorum, o zaman aklima su geliyor bu derleyici beni kandiriyor.
birde for dongusunun govde parametrelerini integer yapsamda benim yine float degiskeni 0.000001 oraninda artirma yapip o sekilde islem yapmam gerekiyor ki ayni durum ile yine karsilasacagimi dusunuyorum, biraz derleyici hatasi gibi geliyor bana  elinde visual c yada borland c olan birisi de ayni islemi deneyebilir mi acaba.
tesekkurler.
Not: pi nin degerini filan nasil hesapliyorlar o zaman bilmem kac hane, degisken boyle kafasina gore davraniyorsa ortaya katastrofik hatalar cikmaz mi.

mr.engineer

   double dval1 = 0.1;     //gercek degeri 0.100000...56     
   double dval2 = 0.25;    //gercek degeri 0.25             
   double dval2 = 0.3;     //gercek degeri 0.29999....989

0.25 sayısı için; bizim verdiğimiz değer ile makine düzeyinde de aynı değere sahip olmasının nedeni 0.25 sayısını makine 2^(-2) şeklinde ifade edebiliyor.

0.1 i.in binary karşılığı 2^(-4) + 2^(-5) + 2^(-8) +2^(-9).... şeklinde sonsuza kadar gidiyor. Benim derleyicim de sayıyı yukarıda yazdığım gibi  0.100000...56 ifade ediyor. Yani tam 0.1 değil daha büyük bir değer üretti.

Eğer float veya double sayılarda işlem yaparsanız 0.1 + 0.1 toplamı değil 0.100000...56 + 0.100000...56 ifadelerini toplayacaksınız. Değeri yazdırırken emin değilim ama büyük ihtimalle yuvarlama yapıyor ve sizin görmek istediğiniz sayıyı yazdırıyor.

Kısacası derleyici hatası yok. Daha detaylı bilgi için IEEE 754 floating point standardına bakabilirsiniz. C/C++'da (derleyiciye göre değişebilir) yaygın olarak bu standart kullanılıyor.


erpay

Super PI diye bir program var bununla bir CPU'nun ne kadar pi basamağı hesapladığı ölçülüyor yani CPU performansı belirleniyor. Pi hesaplama işi basit bir işlem değil yani. Diğer yandan FPU diye bir şey var ki amacı bu ondalıklı sayıları işlemek, gereksinimler değiştikçe böyle işlemcilere kayılıyor. Basit işlemcilerde floatlardan olabildiğince kaçmak gerek bence.

Yuunus

IEEE 754 https://tr.wikipedia.org/wiki/IEEE_754
standardina baktim ozetle diyor ki bit genisligi musaitse virgulden sonrasi gosterilir, eger yer yoksa yuvarlanir diyor,simdi benim sayim float tip gosterim alanindan tasiyor mu da bana yuvarlayip gosteriyor. g++ vs zaten hala 32 bit calisiyor, float tip degiskeniminde tasdigini dusunmuyorum, diyorsaniz ki tasiyor; daha buyuk float sayi ile islem yaptigimda tasmamasi gerekirki denedim hicbir degisiklik yok hala esit olan sayiyi bulamiyor.
@mr.engineer
   double dval1 = 0.1;     //gercek degeri 0.100000...56     
   double dval2 = 0.25;    //gercek degeri 0.25             
   double dval2 = 0.3;     //gercek degeri 0.29999....989
bu ornekleri nerden buldunuz.

muuzoo

Alıntı yapılan: Yuunus - 02 Nisan 2022, 23:06:33IEEE 754 https://tr.wikipedia.org/wiki/IEEE_754
standardina baktim ozetle diyor ki bit genisligi musaitse virgulden sonrasi gosterilir, eger yer yoksa yuvarlanir diyor,simdi benim sayim float tip gosterim alanindan tasiyor mu da bana yuvarlayip gosteriyor. g++ vs zaten hala 32 bit calisiyor, float tip degiskeniminde tasdigini dusunmuyorum, diyorsaniz ki tasiyor; daha buyuk float sayi ile islem yaptigimda tasmamasi gerekirki denedim hicbir degisiklik yok hala esit olan sayiyi bulamiyor.
@mr.engineer
   double dval1 = 0.1;     //gercek degeri 0.100000...56     
   double dval2 = 0.25;    //gercek degeri 0.25             
   double dval2 = 0.3;     //gercek degeri 0.29999....989
bu ornekleri nerden buldunuz.
Şu hesap makinesi size yardımcı olur. Taşma olması için sayınızın çok büyük olmasına gerek yok. Gösterim biçiminden kaynaklı olarak bir miktar hata oluşabilir.

https://www.h-schmidt.net/FloatConverter/IEEE754.html
gunluk.muuzoo.gen.tr - Kişisel karalamalarım...

mr.engineer

Alıntı yapılan: Yuunus - 02 Nisan 2022, 23:06:33IEEE 754 https://tr.wikipedia.org/wiki/IEEE_754
standardina baktim ozetle diyor ki bit genisligi musaitse virgulden sonrasi gosterilir, eger yer yoksa yuvarlanir diyor,simdi benim sayim float tip gosterim alanindan tasiyor mu da bana yuvarlayip gosteriyor. g++ vs zaten hala 32 bit calisiyor, float tip degiskeniminde tasdigini dusunmuyorum, diyorsaniz ki tasiyor; daha buyuk float sayi ile islem yaptigimda tasmamasi gerekirki denedim hicbir degisiklik yok hala esit olan sayiyi bulamiyor.
@mr.engineer
   double dval1 = 0.1;     //gercek degeri 0.100000...56     
   double dval2 = 0.25;    //gercek degeri 0.25             
   double dval2 = 0.3;     //gercek degeri 0.29999....989
bu ornekleri nerden buldunuz.

Visual stduio'da "dval1 = 0.1" yazıp mouse ile 0.1 in üstüne gelince size gerçek değeri gösteriyor.

Olayın taşma ile alakası yok. 32 bit değil 256 bit de olsa siz 0.1 sayısını tam olarak ifade edemezsiniz.
Sadece şu sorunun cevabını verin: 0.1 sayısını 2'nin kuvvetleri şeklinde nasıl yazarsınız??? Ve yazdığınız ifade gerçekten tam olarak 0.1 oluyor mu yoksa 0.1'e çok yakın bir değer mi oluyor? 
0.1'e sonsuzda erişirsiniz.

Yuunus

#8
herkese tesekkur ederim.

sifirzero

Araya printf ile f degerini kaç ile basladigina bakabilirsin. Matematiksel olarak. Sayi degerlerini ayarlarsin
sifirzero.blogspot.com [email]sifirrzero@gmail.com[/email] iman hem nurdur hem kuvvettir