Kayan nokta tuzaklarından kaçınmak için programlama dillerinde neler yapılabilir?


28

Kayan nokta aritmetiğinin ve onun eksikliklerinin yanlış anlaşılması, programlamada sürpriz ve karışıklığın temel bir nedenidir (Yığın Taşması ile ilgili "doğru eklenmeyen sayılarla ilgili soru sayısını düşünün"). Pek çok programcının henüz sonuçlarını anlamadığı göz önüne alındığında, birçok süptil hata (özellikle finansal yazılıma) dahil etme potansiyeli vardır. Programlama dilleri, kavramları anlamayan kişiler için tuzaklardan kaçınmak için ne yapabilir, aynı zamanda kavramları anlayanlar için doğruluk kritik olmadığında da hızını sunarken ne yapabilir ?


26
Bir programlama dilinin kayan nokta işlemenin tuzaklarından kaçınmak için yapabileceği tek şey, onu yasaklamaktır. Bunun, finansal uygulamaların önceden uyarlanmış olması dışında, genel olarak yanlış olan 10 tabanlık kayan noktasını da içerdiğine dikkat edin.
David Thornley

4
Bu "Nümerik Analiz" içindir. Kayan nokta tehlikelerinin - yani hassas kaybın nasıl en aza indirileceğini öğrenin.

Kayan nokta sorununa iyi bir örnek: stackoverflow.com/questions/10303762/0-0-0-0-0
Austin Henley

Yanıtlar:


47

Evcil hayvanlarımdan birisini getiren "özellikle finansal yazılımlar için" diyorsunuz: para bir şamandıra değil, bir int .

Elbette, bir şamandıra gibi görünüyor. Orada bir ondalık basamağı var. Ama bunun nedeni, sorunu kafayla karıştıran birimlere alışkın olmanız. Para her zaman tam sayılarda gelir. Amerika'da sent. (Bazı bağlamlarda değirmen olabileceğini düşünüyorum , ancak şimdilik bunu görmezden gelin.)

Yani 1,23 dolar derken, bu gerçekten 123 sent. Her zaman, her zaman, her zaman matematiğinizi bu şartlarda yapın ve iyi olacaksınız. Daha fazla bilgi için bakınız:

Soruyu doğrudan cevaplayarak, programlama dilleri sadece makul bir ilkel olarak bir Para tipi içermelidir.

güncelleştirme

Tamam, üç kere değil, sadece “her zaman” demeliydim. Para gerçekten her zaman bir int; aksi halde düşünenler bana 0.3 sent göndermeyi ve bana banka ekstrenizdeki sonucu göstermeyi deneyebilirler. Ancak yorum yapanların işaret ettiği gibi, para benzeri sayılar üzerinde kayan nokta matematiği yapmanız gerektiğinde nadir istisnalar vardır. Örneğin, belirli türden fiyatlar veya faiz hesaplamaları. O zaman bile, bunlara istisnalar gibi davranılmalıdır. Para gelir ve tamsayılar olarak gider, bu nedenle sisteminiz buna ne kadar yaklaşırsa, o kadar akılda kalır.


20
@JoelFan: platforma özel bir uygulama için bir konsept yanlışlıyorsunuz.
whatsisname,

12
Bu o kadar basit değil. Faiz hesaplamaları, diğerleri arasında, kesirli sentler üretmekte ve belirli bir yönteme göre bir noktada yuvarlatılmalıdır.
kevin cline

24
Kurgusal -1, çünkü aşağı oy için bir temsilci yoksundur :) ... Bu, cüzdanınızdakiler için doğru olabilir, ancak yüzde onda biri veya daha küçük kesirler ile iyi başa çıkabileceğiniz birçok muhasebe durumu olabilir. BununlaDecimal başa çıkmak için tek akıl sağan sistemi ve yorumunuz " şimdilik görmezden
gelin"

9
@kevin cline: Hesaplamalarda kesirli sentler var, fakat bunların nasıl kullanılacağına dair sözleşmeler var. Finansal hesaplamaların amacı matematiksel doğruluk değil, aynı zamanda bir hesap makinesine sahip bir bankacının elde edeceği sonuçların aynısını almaktır.
David Thornley

6
"
İnteger

15

Ondalık tür için destek sağlamak birçok durumda yardımcı olur. Birçok dilde ondalık bir tür vardır, ancak bunlar kullanılmamaktadır.

Gerçek sayıların gösterimi ile çalışırken ortaya çıkan yaklaşımı anlamak önemlidir. Hem ondalık hem de kayan nokta türlerini kullanmak 9 * (1/9) != 1doğru bir ifadedir. Sabit olduğunda, bir optimize edici hesaplamayı doğru yapmak için optimize edebilir.

Bir yaklaşık operatör sağlamak, yardımcı olacaktır. Bununla birlikte, bu tür karşılaştırmalar problemlidir. 0,9999 trilyon doların yaklaşık 1 trilyon dolara eşit olduğunu unutmayın. Aradaki farkı banka hesabıma yatırabilir misiniz?


2
0.9999...Aslında trilyon dolar 1 trilyon dolara eşit.
SADECE

5
@JUST: Evet, ancak tutacak kayıtları olan hiçbir bilgisayarla karşılaşmadım 0.99999.... Hepsi bir noktada kesiliyor ve eşitsizlikle sonuçlanıyor. 0.9999mühendislik için yeterince eşittir. Finansal amaçlar için değil.
BillThor

2
Peki ne tür bir sistem dolar yerine temel birim olarak trilyonlarca dolar kullandı?
Brad

@Brad Hesap makinenizde (1 Trilyon / 3) * 3 hesaplamayı deneyin. Hangi değeri alıyorsun?
BillThor

8

Üniversiteye gittiğimde ilk sene bilgisayar dersinde ne yapmam gerektiğini söylemiştim (bu ders aynı zamanda çoğu fen dersi için ön koşuldur)

“Kayan nokta sayıları yaklaşık değerlerdir. Para için tamsayı türleri kullanın. (ve daha sonra, ikili kayan noktalarda doğru şekilde temsil edilmesi imkansız olan 0.2 klasik örneğini kullanarak yaklaşıma işaret etti). Bu da o hafta laboratuvar alıştırmalarında ortaya çıktı.

Aynı ders: "Kayan noktadan daha fazla doğruluk elde etmek istiyorsanız, terimlerinizi sıralayın. Büyük sayılar için değil, küçük sayıları bir araya getirin." Aklımda sıkışmış.

Birkaç yıl önce, çok doğru ve hala hızlı olması gereken küresel bir geometriye sahiptim. PC'lerde 80 bit çift kesmiyordu, bu yüzden değişmeli işlemleri gerçekleştirmeden önce terimleri sıralayan programa bazı türler ekledim. Sorun çözüldü.

Gitarın kalitesinden şikayet etmeden önce çalmayı öğrenin.

Dört yıl önce JPL'de çalışan bir meslektaşım vardı. FORTRAN'ı bazı şeylerde kullandığımız konusundaki inancını dile getirdi. (Çevrimdışı olarak hesaplanan süper doğru sayısal simülasyonlara ihtiyacımız vardı.) “Tüm FORTRAN'ı C ++ ile değiştirdik” dedi gururla. Neden bir gezegeni özlediklerini merak ettim.


2
Doğru iş için doğru aleti + 1'leyin. Gerçi ben FORTRAN kullanmıyorum. Neyse ki ben de işyerinde finansal sistemler üzerinde çalışmıyorum.
James Khoury,

"Kayan noktadan daha fazla doğruluk elde etmeniz gerekiyorsa, terimlerinizi sıralayın. Büyük sayılara değil, küçük sayıları birlikte ekleyin." Bu konuda örnek var mı?
mamcx

@mamcx Yalnızca bir basamak önceliğe sahip bir ondalık kayan nokta sayısı düşünün. Her ara sonuç yuvarlandığı için hesaplama 1.0 + 0.1 + ... + 0.1(10 kez tekrarlanan) döner 1.0. O başka bir yol yuvarlak yaparsanız son ara sonuçlar elde 0.2, 0.3, ..., 1.0ve nihayet 2.0. Bu aşırı bir örnektir, ancak gerçekçi kayan nokta sayılarıyla benzer sorunlar ortaya çıkar. Temel fikir, boyuta benzer sayılar eklemenin en küçük hataya yol açmasıdır. Toplamları daha büyük olduğu için en küçük sayılarla başlayın ve bu nedenle daha büyük sayıları eklemek için daha uygun olur.
maaartinus 19

Fortran ve C ++ 'daki kayan nokta olayları çoğunlukla aynı olacak. Her ikisi de doğru ve çevrimdışı, ve Fortran’ın yerel BCD gerçekleri olmadığından eminim ...
Mark

8

Uyarı: Kayan nokta tipi System.Double , doğrudan eşitlik testi için hassasiyetten yoksundur.

double x = CalculateX();
if (x == 0.1)
{
    // ............
}

Dil düzeyinde bir şey yapılabileceğine veya yapılması gerektiğine inanmıyorum.


1
Uzun zamandır bir şamandıra ya da iki katı kullanmadım, bu yüzden merak ediyorum. Bu mevcut bir derleyici uyarısı mı, yoksa sadece görmek istediğiniz mi?
Karl Bielefeldt

1
@Karl - Şahsen ben görmedim ya da ihtiyacım olmadı, ancak yeşil geliştiriciler için işe yarayacağını hayal ediyorum.
ChaosPandion 19

1
İkili kayan nokta tipleri, Decimaleşitlik testinden daha iyi veya daha kötü nitelikte değildir . Arasındaki fark 1.0m/7.0m*7.0mve 1.0mdaha az arasındaki farktan daha birçok büyüklük sırası olabilir 1.0/7.0*7.0, ama bu sıfır değil.
supercat

1
@Patrick - Neye bulaştığınızdan emin değilim. Bir vaka için doğru olan ile tüm durumlar için doğru olan arasında çok büyük bir fark vardır.
ChaosPandion

1
@ChaosPandion Bu yazıdaki örnekteki sorun eşitlik karşılaştırması değil, kayan nokta değişmezi. Kesin değeri 1.0 / 10 olan şamandıra yoktur. Kayan nokta matematiği, mantis içine uyan tamsayı sayıları ile hesaplanırken% 100 doğru sonuçlar verir.
Patrick 20:

7

Varsayılan olarak, diller tam sayı olmayan sayılar için rasgele kesinlikli rasyonlar kullanmalıdır.

Optimize edilmesi gerekenler her zaman yüzdürme isteyebilir. Bunları varsayılan olarak kullanmak C ve diğer sistem programlama dillerinde anlamlıdır, ancak bugün pek çok dilde kullanılmamaktadır.


1
Öyleyse irrasyonel sayılarla nasıl başa çıkıyorsun?
dsimcha

3
Yüzdürme ile aynı şekilde yaparsınız: yaklaşım.
Waquo

1
Bunun çok anlamlı olduğunu düşünüyorum. Kesin sayıya ihtiyaç duyan çoğu insanın mantıksız değil rasyonellere ihtiyacı vardır (bilim ve mühendislik mantıksızları kullanabilir, ancak daha sonra tekrar yaklaşık bir aleme dönersiniz, ya da oldukça özel bir saf matematik yapıyorsunuz)
jk.

1
İsteğe bağlı hassas rasyonel hesaplamalara sahip hesaplamalar, genellikle donanım destekli hesaplara göre daha yavaş (muhtemelen MANY büyüklük derecelerinde) olacaktır double. Bir hesaplamanın milyonda bir kısmı için doğru olması gerekiyorsa, bir mikrosaniyeyi milyarda birkaç parçaya hesaplamak için harcayarak daha iyi bir hesaplama yapmaktan daha iyidir.
supercat 15

5
@supercat: Önerdiğin şey sadece erken optimizasyonun poster çocuğu. Şu anki durum, programcıların büyük çoğunluğunun hızlı matematik için hiçbir şeye ihtiyaç duymadığı ve daha sonra kayan nokta (yanlış) davranışını anlamak zor tarafından ısırıldığı, böylece hızlı matematik gerektiren çok az sayıda programcının bunu yapmadan alabilmesi Tek bir ekstra karakter girmek için Bu yetmişli yıllarda anlamlıydı, şimdi sadece saçmalık. Varsayılan değer güvenli olmalıdır. Hızlı ihtiyacı olanlar bunu sormalı.
Waquo

4

Kayan nokta sayılarını içeren en büyük iki problem:

  • hesaplamalara uygulanan tutarsız birimler (bunun aynı zamanda tamsayı aritmetiğini de aynı şekilde etkilediğine dikkat edin)
  • FP sayılarının bir yaklaşım olduğunu ve nasıl yuvarlama ile nasıl başa çıkılacağını anlamadaki başarısızlık .

İlk arıza tipi ancak değer ve birim bilgisini içeren bir bileşik tip sağlayarak giderilebilir. Örneğin , üniteyi içeren a lengthveya areadeğeri (sırasıyla metre veya metrekare veya feet ve metrekare). Aksi halde, daima bir ölçü birimi ile çalışmak ve cevabı bir insanla paylaştığımızda sadece diğerine çevirmek konusunda gayretli olmalısınız.

İkinci tip başarısızlık kavramsal bir başarısızlıktır. Başarısızlıklar, insanlar onları mutlak sayılar olarak düşündüklerinde kendini gösterir . Eşitlik işlemlerini, kümülatif yuvarlama hatalarını vb. Etkiler. Örneğin, bir sistem için iki ölçümün belirli bir hata payı içinde eşdeğer olduğu doğru olabilir. Yani, 999 ve 1,001, +/- 1'den küçük farklar umursamadığınızda kabaca 1.0 ile aynıdır. Ancak, tüm sistemler o kadar yumuşak değildir.

Gerekli herhangi bir dil seviyesi tesisi varsa, o zaman ona eşitlik hassasiyeti derdim . NUnit, JUnit ve benzer şekilde oluşturulmuş test çerçevelerinde, doğru kabul edilen kesinliği kontrol edebilirsiniz. Örneğin:

Assert.That(.999, Is.EqualTo(1.001).Within(10).Percent);
// -- or --
Assert.That(.999, Is.EqualTo(1.001).Within(.1));

Örneğin, C # veya Java hassas bir operatör içerecek şekilde değiştirildiyse, şuna benzer bir şey olabilir:

if(.999 == 1.001 within .1) { /* do something */ }

Ancak, böyle bir özellik sağlarsanız, +/- tarafların aynı olmadığı durumlarda eşitliğin iyi olduğu durumunu da göz önünde bulundurmanız gerekir. Örneğin, + 1 / -10, bir tanesi 1 veya daha fazla ilk sayıdan 10 daha az olsaydı, iki sayıya denk gelirdi. Bu durumu ele almak için, bir rangeanahtar kelime de eklemeniz gerekebilir :

if(.999 == 1.001 within range(.001, -.1)) { /* do something */ }

2
Siparişi değiştirirdim. Kavramsal problem yaygındır. Birim dönüşüm sorunu, karşılaştırmaya göre nispeten azdır.
S.Lott

Hassas bir operatör kavramını sevdim, ama daha da bahsettiğiniz gibi, kesinlikle iyi düşünülmesi gerekir. Şahsen ben kendi sözdizimsel yapı olarak görmeye daha yatkın olurdum.
ChaosPandion

Ayrıca bir kütüphanede çok kolay bir şekilde yapılabilir.
Michael K

1
@ dan04: "Yüzde bir yüzde için doğru olan tüm hesaplamalar" veya benzerleri hakkında daha fazlasını düşünüyordum. Ölçü işleme birimi olan katran çukuru gördüm ve çok uzak duruyorum.
TMN

1
Yaklaşık 25 yıl önce, bir miktar için maksimum ve minimum değerleri temsil eden bir çift kayan nokta sayısından oluşan bir tür içeren sayısal bir paket gördüm. Sayılar hesaplamalardan geçerken, maksimum ve minimum arasındaki fark artacaktır. Etkili olarak, bu hesaplanan bir değerde ne kadar gerçek hassasiyet bulunduğunu bilmenin bir yolunu sağlamıştır.
supercat

3

Programlama dilleri ne yapabilir? Bu soruya bir cevap verilip verilmediğini bilmiyorum, çünkü derleyici / tercümanın programcının adına hayatını kolaylaştırmak için yaptığı her şey genellikle performansa, açıklığa ve okunabilirliğe karşı çalışır. Hem C ++ yolunun (sadece ihtiyacınız olan şey için ödeme yapın) hem de Perl yolunun (en az sürpriz prensibi) her ikisinin de geçerli olduğunu düşünüyorum, ancak uygulamaya bağlı.

Programcıların hala dille çalışması ve kayan noktaları nasıl ele aldığını anlaması gerekiyor, çünkü eğer yapmazlarsa, varsayımlarda bulunacaklar ve bir gün açıklanan davranışlar varsayımlarıyla eşleşmeyecek.

Programcının bilmesi gerekenleri benim üstlenmem:

  • Hangi kayan nokta tipleri sistemde ve dilde mevcuttur?
  • Ne tür gerekli
  • Kodda hangi tür ihtiyaç duyulduğuna ilişkin niyetler nasıl ifade edilir?
  • Doğruluğu korurken netliği ve verimliliği dengelemek için herhangi bir otomatik tür promosyondan nasıl doğru şekilde faydalanılır

3

Programlama dilleri, [kayan nokta] tuzaklarından kaçınmak için ne yapabilir?

Mantıklı varsayılanlar kullanın, örneğin ondalık kodlar için dahili destek.

Groovy bunu oldukça iyi yapıyor, ancak bir miktar çaba ile kayan nokta hassasiyetini tanıtmak için hala kod yazabilirsiniz.


3

Dil düzeyinde yapacak bir şey olmadığı konusunda hemfikirim. Programcılar bilgisayarların ayrık ve sınırlı olduğunu ve içinde temsil edilen matematiksel kavramların çoğunun yalnızca yaklaşık değerler olduğunu anlamalıdır.

Sakın kayan noktaya aldırma. Bit modellerinin yarısının negatif sayılar için kullanıldığını ve tam sayı aritmetiğindeki tipik sorunlardan kaçınmak için aslında 2 ^ 64'ün oldukça küçük olduğunu anlamak gerekir.


katılmıyorum, çoğu dil şu anda ikili kayan nokta türleri için çok fazla destek veriyor (neden yüzmeler için bile == tanımlanıyor?) ve rasyonel veya ondalık sayılar için yeterli destek yok
jk.

@ jk: Herhangi bir hesaplamanın sonucu hiçbir zaman başka bir hesaplamanın sonucuna eşit olarak garanti edilmese bile, aynı değerin iki değişkene atandığı durumlarda eşitlik karşılaştırması yine de faydalı olacaktır (eşitlik kuralları belki de uygulanmış olsa da) çünkü x== ybir hesaplama xyapmanın, aynı hesaplamanın yapıldığı ile aynı sonucu vereceği anlamına gelmez y).
supercat

@ supercat hala karşılaştırmaya ihtiyacınız var, ancak dil, her kayan nokta karşılaştırması için bir tolerans belirtmemi istedi, daha sonra yine de tolerans = 0'ı seçerek yine eşitliğe geri dönebilirim, ancak en azından bunu yapmak zorundayım seçim
jk.

3

Dillerin yapabileceği bir şey var - eşitlik karşılaştırmasını NAN değerleriyle doğrudan karşılaştırmanın dışında kayan nokta türlerinden kaldırın.

Eşitlik testi sadece iki değeri ve bir deltayı alan işlev çağrısı olarak veya türlerin diğer değeri ve deltayı alan bir EqualsTo yöntemine sahip olmasına izin veren C # gibi diller için geçerlidir.


3

Lisp ailesinin rasyonel sayı numarasını hiç kimsenin işaret etmemesini garip buluyorum.

Cidden, sbcl'yi açın ve şunu yapın: (+ 1 3)ve 4 *( 3 2)elde edin (/ 5 3).

Bu, bazı durumlarda biraz yardımcı olmalı, değil mi?


Merak ediyorum, bir sonucun 1/3 olarak mı gösterilmesi gerektiğini yoksa kesin bir ondalık olabileceğini bilmek mümkün mü?
mamcx

iyi öneri
Peter Porfy 10:15

3

Ben görmek istiyorum bir şey olduğunu bir tanıma olacağını doubleüzere floatiken, genişleyen dönüşüm olarak kabul edilmelidir floatiçin double(*) daraltıyor. Bu sezgisel görünebilir gibi görünebilir, ancak türlerin gerçekte ne anlama geldiğini düşünün:

  • 0.1f "13,421,773.5 / 134,217,728, artı veya eksi 1 / 268,435,456 ya da öylesine" anlamına gelir.
  • 0,1 gerçekten 3,602,879,701,896,397 / 36,028,797,018,963,968, artı veya eksi 1 / 72,057,594,037,927,936 veya daha fazla anlamına gelir.

Eğer biri double"onda biri" miktarının en iyi temsilini elinde tutarsa ​​ve onu dönüştürürse float, sonuç "13,421,773.5 / 134,217,728, artı veya eksi 1 / 268,435,456 ya da öylesine" olacaktır, ki bu değerin doğru bir açıklamasıdır.

Buna karşılık, float"onda biri" miktarının en iyi temsilini elinde tutan ve bunu dönüştüren doublesonuç varsa, sonuç "13,421,773,5 / 134,217,728, artı veya eksi 1 / 72,057,594,037,927,936 veya benzeri" - zımni doğruluk düzeyi olacaktır. 53 milyonun üzerinde bir faktör tarafından yanlış.

IEEE-744 standardı kayan nokta matematik yapılması gerektiği halde sanki her kayan noktalı sayı kayan nokta değerleri aslında tam olarak o temsil ettiğini ima etmek alınmamalıdır onun aralığın ortasında tam kesin sayısal miktarını temsil sayısal büyüklükler. Aksine, değerlerin aralıklarının merkezinde olduğu varsayılması gerekliliği üç olguya dayanır: (1) hesaplamalar, işlenenler belirli belirli kesin değerlere sahipmiş gibi yapılmalıdır; (2) tutarlı ve belgelenmiş varsayımlar tutarsız veya belgesiz olanlardan daha yararlıdır; (3) eğer biri tutarlı bir varsayımda bulunacaksa, bir niceliğin menzilinin merkezini temsil ettiğini varsaymaktan daha iyi başka hiçbir tutarlı varsayım kabul edilemez.

Bu arada, yaklaşık 25 yıl önce hatırlıyorum, birisi her biri bir çift 128-bitlik yüzerden oluşan "aralık türlerini" kullanan C için sayısal bir paket buldu; Tüm hesaplamalar, her sonuç için mümkün olan minimum ve maksimum değerleri hesaplayacak şekilde yapılacaktır. Eğer biri büyük, uzun bir yinelemeli hesaplama yaptıysa ve [12.53401391134 12.53902812673] değerine sahipse, birçok hassas basamağın yuvarlama hatalarından kaybedilmesine rağmen sonucun makul ölçüde 12.54 olarak ifade edilebileceğinden emin olabilir (ve bu değer y ... t gerçekten 12.9 veya 53.2). Ana akım dillerde bu tür bir destek görmedim, özellikle de paralel olarak birden fazla değerde çalışabilecek matematik birimlerine çok yakışırlar, çünkü şaşırdım.

(*) Pratikte, tek duyarlıklı sayılarla çalışırken ara hesaplamaları tutmak için çift duyarlıklı değerlerin kullanılması yararlı olur; bu nedenle, tüm bu işlemler için bir yazım denetimi kullanmak can sıkıcı olabilir. Diller, çift olarak hesaplamaları yapabilen ve serbestçe bekarlara tek tek basmak için kullanılabilecek "bulanık çift" türüne sahip olarak yardımcı olabilir; bu özellikle tip doubleve dönüş parametrelerini alan fonksiyonların doubleişaretlenebilmesi için faydalı olacaktır, böylece otomatik olarak "bulanık çift" i kabul eden ve döndüren bir aşırı yük oluşturacaklardı.


2

Daha fazla programlama dili veritabanlarından bir sayfa aldıysa ve geliştiricilerin sayısal veri türlerinin uzunluğunu ve kesinliğini belirlemelerini sağladıysa, kayan nokta ile ilgili hataların olasılığını önemli ölçüde azaltabilirdi. Bir dil bir geliştiricinin Float (2) olarak bir değişken ilan etmesine izin verirse, iki ondalık basamağa sahip bir kayan nokta sayısına ihtiyaç duyduklarını belirten matematiksel işlemleri çok daha güvenli bir şekilde gerçekleştirebilir. Bunu yaptıysa, değişkeni dahili olarak bir tamsayı olarak temsil ederek ve değeri göstermeden önce 100'e bölerek yaparsa, daha hızlı tamsayı aritmetik yollarını kullanarak hızı artırabilir. Bir Float (2) 'nin semantiği ayrıca, geliştiricilerin, Float (2) doğal olarak verileri iki ondalık noktaya yuvarlayacağından, çıktı vermeden önce sürekli veri toplama ihtiyacından kaçınmasını sağlar.

Elbette, geliştiricinin bu hassaslığa sahip olması gerektiğinde bir geliştiricinin maksimum hassasiyetli kayan nokta değeri istemesine izin vermeniz gerekir. Ayrıca, aynı matematiksel işlemin biraz farklı ifadelerinin, geliştiriciler değişkenlerinde yeterince hassasiyet taşımadığında, ortadaki yuvarlama işlemleri nedeniyle potansiyel olarak farklı sonuçlar ürettiği sorunları ortaya koyarsınız. Ama en azından veritabanı dünyasında, bu çok büyük bir şey gibi görünmüyor. Çoğu insan, ara sonuçlarda çok fazla hassasiyet gerektiren türde bilimsel hesaplamalar yapmıyor.


Uzunluk ve hassasiyet belirtilmesi çok az işe yarar. 10 puanlık sabit bir tabana sahip olmak, insanların yüzer noktadan aldığı sürprizlerin çoğunu ortadan kaldıracak finansal işlemler için faydalı olacaktır.
David Thornley

@David - Belki bir şeyleri özlüyorum ama sabit nokta tabanlı 10 veri türü önerdiğimden farklı mı? Örneğimdeki bir Float (2) sabit bir 2 ondalık basamağa sahip olacak ve otomatik olarak en yakın yüzdeye yuvarlanır ki bu basit finansal hesaplamalar için kullanacağınız şeydir. Daha karmaşık hesaplamalar, geliştiricinin daha fazla sayıda ondalık basamak tahsis etmesini gerektirir.
Justin Mağarası

1
Avukatlık yaptığınız şey, programcı tarafından belirlenen hassasiyete sahip, sabit nokta temelli bir 10 veri türüdür. Programcı tarafından belirlenen hassasiyetin çoğunlukla anlamsız olduğunu ve COBOL programlarında rastladığım türden hatalara yol açacağını söylüyorum. (Örneğin, değişkenlerin kesinliğini değiştirdiğinizde, değerin geçtiği bir değişkeni kaçırmak çok kolaydır. Bir başkası için, ortadaki sonuç büyüklüğünü iyi olmaktan çok daha fazla düşünmek gerekir.)
David Thornley

4
Bir Float(2)senin gibi değil denilen teklif Floatburada yüzen bir şey, kesinlikle "ondalık noktası" bulunmadığından,.
Paŭlo Ebermann

1
  • dillerin ondalık türü desteği vardır; Tabii ki bu problemi gerçekten çözmüyor, hala örneğin ⅓;
  • Bazı DB'ler ve çerçeveler Para tipi desteğine sahiptir, bu temelde sent sayısını tamsayı olarak depolar;
  • rasyonel sayı desteği için bazı kütüphaneler var; ⅓ problemini çözer ancak √2 problemini çözmez;

Yukarıdakiler bazı durumlarda geçerlidir, ancak gerçek değerlerle başa çıkmak için genel bir çözüm değildir. Asıl çözüm, sorunu anlamak ve onunla nasıl başa çıkılacağını öğrenmektir. Kayan nokta hesaplamaları kullanıyorsanız, algoritmalarınızın sayısal olarak kararlı olup olmadığını her zaman kontrol etmelisiniz . Problemle ilgili devasa bir matematik / bilgisayar bilimi alanı var. Buna Sayısal Analiz denir .


1

Diğer cevapların da belirttiği gibi, finansal yazılımdaki kayan nokta tuzaklarından kaçınmanın tek gerçek yolu onu kullanmak değildir. Bu aslında mümkün olabilir - finansal matematiğe yönelik iyi tasarlanmış bir kütüphane sağlarsanız .

Kayan nokta tahminlerini içe aktarmak için tasarlanan işlevler, açıkça açıkça belirtilmeli ve bu işleme uygun parametrelerle sağlanmalıdır.

Finance.importEstimate(float value, Finance roundingStep)

Genel olarak kayan nokta tuzaklarından kaçınmanın tek gerçek yolu eğitimdir - programcıların Kayan Nokta Aritmetiği Hakkında Bilmeniz Gerekenler gibi her şeyi okuması ve anlaması gerekir .

Yine de yardımcı olabilecek birkaç şey:

  • "Kayan nokta için tam olarak eşitlik testi neden yasal bile?"
  • Bunun yerine, bir isNear()işlev kullanın .
  • Kayan nokta akümülatör nesnelerinin kullanımını sağlayın ve teşvik edin (kayan nokta değerlerinin dizilerini, hepsini basit bir kayan nokta değişkenine eklemekten daha kararlı biçimde ekler).

-1

Programcıların çoğu COBOL'un bu hakkın elde edilmesine şaşıracaktı ... COBOL'un ilk sürümünde kayan nokta yoktu, sadece ondalık ve COBOL'deki gelenek, bir sayıyı bildirirken ilk sayının ondalık olduğunu düşündüğümüze kadar devam etti. .. kayan nokta ancak gerçekten ihtiyaç duyduğunuzda kullanılır. C geldiğinde, bir nedenden ötürü, ilkel bir ondalık tür yoktu, bu yüzden bence, tüm problemlerin başladığı yer burası.


1
C bir ondalık tipe sahip değildi, çünkü ilkel değil, herhangi bir donanım ondalık komutuna sahip çok az bilgisayar var. BASIC ve Pascal'ın neden ona sahip olmadığını sorabilirsiniz, çünkü metale yakından uyum sağlamak üzere tasarlanmadılar. COBOL ve PL / I, böyle bir şeye sahip olduğum zamandan tanıdığım tek dil.
David Thornley

3
@JoelFan: Peki COBOL'da ⅓ nasıl yazıyorsunuz? Ondalık herhangi bir sorunu çözmüyor, üs 10, üs 2 kadar yanlış.
vartec

2
Ondalık, "İş Odaklı" bir dil için faydalı olan, dolar ve kuruşları tam olarak temsil etme sorununu çözer. Ancak, aksi takdirde, ondalık kullanışsızdır; Aynı tür hataları (örneğin, 1/3 * 3 = 0.99999999) çok daha yavaş olurken . Ki bu yüzden olduğunu değil özellikle muhasebe için tasarlanmış değildi dilde varsayılan.
dan04 0

1
Ve on yıldan fazla bir süre önce C'yi öldüren FORTRAN'ın da standart ondalık desteği yoktur.
dan04 5

1
@JoelFan: Eğer üç ayda bir değeriniz varsa ve aylık değere ihtiyacınız varsa, onu neyle çarpmanız gerektiğini tahmin edin ... hayır, bu 0.33 değil, bu ⅓.
vartec
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.