Float sayıların çarpımı yanlış çıkıyor?

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
ovural
Üye
Mesajlar: 167
Kayıt: 22 Eki 2003 10:20
İletişim:

Float sayıların çarpımı yanlış çıkıyor?

Mesaj gönderen ovural »

yazdıgım programlardan birisini YTL ye ceviriyordum .. baktım yanlıs sonuc cıkartıyor .. .adım adım takip ederek yanlısın nerede olduguna baktım ..


mesela ..

Kod: Tümünü seç

if Query1.FieldbyName('Bilmemne').AsFloat=hangi*1.5 then
Begin
End
else
Begin
End;
gibi bir kod var ..
simdi gelelim can alıcı noktaya
Query1.Fieldbyname('Bilmemne').AsFloat in deger = 23.4
hangi*1.5 un degeride 23.4 ...

yani aynı ve esitlik saglanıyor dolayısıyla 1. begin endi yapması gerekiyor .. ama ikinciyi yapıyor .. ve durum 23.4 te oluyor yanlıs oluyor .. ama baska bir sayıda esitlik saglanıyor .. hadi basına FloatToStr koyayım dedim ve

Kod: Tümünü seç

if FloatToStr(Query1.FieldbyName('Bilmemne').AsFloat)=FloatToStR(hangi*1.5) then
Begin
End
else
Begin
End;

yaptım .. esitlik oldu .. ama bu seferde baska bir degerde yanlıs deger cıkartıyor .. aslında esit ... nedendir ?makinamda mı bir arıza var ... acaba
Ram lerimde bir vida mı eksildi
:D
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Float sayılarda virgülden sonraki değerlerde bazı farklılıklar olabilir. Ancak sen bu sayıların eşit olduğunu varsaymak isteyebilirsin.

Mesela:

1,1233322 ile 1,1233321 sayılarının yaklaşık eşit olması gibi.

Float sayıları = ile sınamak istediğinde bu sayıları eşit değil olarak gösterecektir. Bunun için Delphi'de Math unitinde CompareValue isimli bir function var. Delphi yardım'dan bunun farklı varyasyonlarını ve aldığı parametreleri bulabilirsin. Bu function ile bir "Epsilon" değer vererek virgülden sonra kaçıncı basamaktan itibaren eşit varsayılacağını belirtebilirsin.

Son olarak Float sayı karşılaştırması yaparken "=" kullanmamalısın. Çalışmasını beklediğinden daha farklı çalışabilir.
Kullanıcı avatarı
ovural
Üye
Mesajlar: 167
Kayıt: 22 Eki 2003 10:20
İletişim:

Mesaj gönderen ovural »

iyide ben bu değerlerin esit oldugundan eminim ..


adım adım takip ettigimde esitligin oldugu yerde degerlere bakıyorum ..


ve sayılar gercekten esit ... ama olmuyor ...
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Bazı teknolojik problemler yüzünden float sayılarda eşitlik kontrolü her zaman doğru sonuç vermeyebilir bu yüzden CompareValue kullanmalısın. Bir de eğer parasal işlem yapıyorsan muhakkak currency kullan. Float değil. Currency bütün yuvarlama problemlerini otomatik halledecektir. Karşılaştırmalarda da daha doğru sonuç verir.
En son fduman tarafından 07 Oca 2005 09:56 tarihinde düzenlendi, toplamda 2 kere düzenlendi.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Daha detaylı bilgi istiyorsan bkz. http://efd.home.mindspring.com/acc101.htm

Burada senin olayı anlatan bir bölüm var ki şu:
Floating Point = Approximation

Try the following where D is a Double floating point type:

D := 1/3;
if (D+D+D)=1.0 then ShowMessage('Equal') else ShowMessage('Not Equal');

Some programmers are surprised when "Not Equal" is displayed. The explanation is simple; a 100% accurate floating point representation of 1/3 simply won't fit within 8 bytes of memory; the size of a Double. The best that can be done is to store the first 16 digits or so. 0.3333333333333333 may be "close" to 1/3 but it is not "exactly" 1/3. This is not Intel's fault; it is not Microsoft's or Borland's fault; it stems directly from our mathematical system. In other words, the problem here is more scientific rather than technological. 1/3 is just one example of a whole class of real numbers called infinite "repeating decimals". All the memory in the world is not enough to store an exact floating point representation of a single repeating decimal. Another class of real numbers with similar infinity properties are so-called "irrational numbers"; examples include the square root of 2 and the value of Pi.

The point of all this is that floating point types promise nothing more than a convenient approximation. A small margin of error is inherent in floating point math. The currently accepted rules of mathematics make it so. As the example above shows; without some sort of allowance for this inexact nature, floating point comparisons can and will produce unexpected results. See the CmpFloat function in HyperString for approximate comparison of floating point types.
Kullanıcı avatarı
ovural
Üye
Mesajlar: 167
Kayıt: 22 Eki 2003 10:20
İletişim:

Mesaj gönderen ovural »

sorunu çözdüm ..

if Qrt.FieldByname('ucret').asFloat=(hakemfiyati*1.5) then dedigimde duzeldi ..

yani esitligin sag tarfını parantez icine aldım ..

ama aslında parantez olmadanda esitligin True dondurmesi gerekiyor ..

ekran goruntusunude gonderiyorum ....


Resim
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Düzelmesine sevindim. Ancak kendi programımda float sayı eşitlik doğrulamasını bu şekilde yapmazdım demek istiyorum. Kolay gelsin.
ertug
Üye
Mesajlar: 82
Kayıt: 10 Ara 2004 05:41

Mesaj gönderen ertug »

"coderlord" arkadaşımız haklı. İki reel sayı karşılaştırılırken "=" kullanılmamalıdır. Tesadüfi olarak bazen iki eşit reel sayı eşit çıkmayabilir.

Bilgisayarların en büyük sorunlarından biri reel sayılardır. Bir "float" 8 byte yer kaplar. Ancak yalnızca 1.00 ila 2.00 arasında dahi sonsuz adet reel sayı vardır. 8 bayt ile sonsuz seçenek tutamazsınız, bilgisayar noktadan sonraki bölüm için bir şeyler yapmalıdır. İşte *bu* işlemler neticesinde, iki eşit reel sayı bilgisayarda eşit olmayabilir. Tersi olarak eşit olmayan iki reel sayı da eşit değerlendirilebilir.

Ertuğ Kaya
Çağrıbey
Üye
Mesajlar: 40
Kayıt: 26 Kas 2004 11:25
Konum: Ankara

Float ve Currency alanlariyla islem

Mesaj gönderen Çağrıbey »

matematiksel islem yaparken bende soyle bir sorunla karsilasmistim.
örneğin: S_katsayi 'nin alan degeri 0,000673 olsun ve aşağıdaki işlemi yaptığımızda
AdoQuery1S_EnyuksekAylik.AsCurrency:= (AdoQuery1S_MustGostergesi.AsCurrency + AdoQuery1S_MustEkGostergesi.AsCurrency) * AdoQuery1S_Katsayi.AsCurrency;

Sonuç : 6,65 olarak yanlış bir işlem yapıyor,
eğer yukardaki S_Katsayi.AsCurrency alanini AsFloat olarak tanimlarsak sonuç: 6,39 olarak çıkıyor. burada çıkması gereken sonuç 6,39 dur.
Gelecek günden ne dilersen, doğacak günler onu getirir
Cevapla