Neden yüzer / çift gerekir?


29

Http://www.joelonsoftware.com/items/2011/06/27.html izliyordum ve Jon Skeet şakasına güldü yaklaşık 0.3 değil 0.3. Şahsen hiçbir zaman yüzer / onluk / çiftler ile problem yaşamadım ama sonra hatırlıyorum ki 6502'yi çok erken öğrendim ve programlarımın çoğunda hiçbir zaman yüzmeye ihtiyaç duymadım. Kullandığım tek zaman, yanlış sayıların iyi olduğu ve çıktıların ekran için olduğu ve saklanmaması (db, dosyada) veya bağımlı olması gereken grafikler ve matematik içindi.

Benim sorum şu ki, nerelerde normalde yüzer / ondalık / çift kullanıyorsunuz? Bu yüzden bu gotchalara dikkat etmeyi biliyorum. Para ile bir oyunda bir nesnenin hızı için uzun süre kullandım ve değerleri saklıyorum. Bir piksel eklemem gerekip gerekmediğini bilmek için, bir oyunda bir nesnenin hızını int olarak ekliyorum ve bölüyorum (ya da bitshift). (6502 gün içinde nesneyi hareket ettirdim, ayrılığımız veya yüzmememiz fakat kaymam oldu).

Bu yüzden çoğunlukla merak ediyordum.


10
çünkü çok önemlidir, çünkü ipoteğe ödediğim faiz 12.6.
Chani

1
"6502'yi çok erken öğrendim ve programlarımın çoğunda hiçbir zaman yüzmeye ihtiyaç duymadım ... bir nesnenin hızı için inç eklediğim ve bir pikselin hareket edilip edilmeyeceğini bilmek için değeri böldüm." Bunlar, modern uygulamalarda bu görevleri yerine getirmek için alışılmadık yollardır, paranın uzun sentez gösterilmesi dışında.
jprete

İyi ki bilgisayar değirmencileri anlıyor.
tylermac

1
Veya ek olarak, kesirleri kullanabiliyorken neden ondalık kullanıyorsunuz?
tylermac

6
@Scrooge - ironik bir şekilde floatta 0.6'yı temsil edemezsiniz.
Martin Beckett,

Yanıtlar:


28

Çünkü çoğu amaç için tamsayılardan daha hassastırlar.

Şimdi bu nasıl? “Oyunda bir nesnenin hızı için ...” Bu böyle bir durum için iyi bir örnek. Mermiler gibi çok hızlı nesnelere sahip olmanız gerektiğini söyleyin. Hareketlerini tamsayı hız değişkenleriyle tanımlayabilmek için, hızların tamsayı değişkenleri aralığında olduğundan emin olmanız gerekir; bu, isteğe bağlı olarak iyi bir raster alamayacağınız anlamına gelir.

Ancak, saatin saati gibi bazı çok yavaş nesneleri de tanımlamak isteyebilirsiniz. Bu, mermi nesnelerinden yaklaşık 6 derece büyüklüğünde olduğundan, ilk ld (10⁶) ≈ 20 bit sıfırdır, bu short inttiplerden başlayarak kurallara aykırıdır . Tamam, bugün longher yerde var, bu da bizi rahat bir 12 bit ile bırakıyor. Ancak o zaman bile, saat hızı yalnızca dört ondalık basamağa kadar kesin olacak. Bu çok iyi bir saat değil ... ama kesinlikle bir oyun için uygun. Sadece, rasteri olduğundan çok daha kaba yapmak istemezsiniz.

... bir gün yeni, hatta daha hızlı bir nesne türü tanıtmak istemeniz durumunda sorunlara yol açar. Geride "headroom" kalmadı.

Bir şamandıra tipi seçersek ne olur? Aynı boyutta 32 bit, ancak şimdi tüm nesneler için tam 24 bit hassasiyetiniz var . Bu, saatin yıllar boyunca eşit kalmaya yetecek kadar hassas olduğu anlamına gelir. Mermilerin daha yüksek bir hassasiyeti yoktur, ancak yine de sadece bir saniyenin kesirleri için “yaşarlar”, öyleyse tamamen yararsız olurdu. Ve sen tanımlamak istiyorsanız bile çok daha hızlı nesneleri sorun her türlü içine (neden olmasın ışık? Hayır sorun hız) veya çok daha yavaş olanları alamadım. Bir oyunda kesinlikle böyle şeylere ihtiyacınız olmayacak, ama bazen fizik simülasyonlarında da kullanabilirsiniz.

Ve kayan noktalı sayılarla, bu kesinliği her zaman ve ilk önce açıkça görülmeyen rasterleri akıllıca seçmek zorunda kalmadan elde edersiniz. Bu belki de en önemli nokta, çünkü bu tür seçim gereklilikleri hataya açık.


Tamsayılar tamamen doğru. Yanlışlık, yanlış hesaplamaya bağlıdır.
fjdumont

15
Tamsayılar, yalnızca tamsayı (ℤ) sayılarını göstermek için kullandığınızda tam olarak doğrudur. Başka bir şeyi temsil etmek, aslında yanlış hesaplama anlamına gelir. Böyle bir durumda, iki olasılık vardır: ya gerçekten temsil etmek istediğiniz numaralara tam olarak uyan bir tip tanımlayın. bu mümkündür, örneğin Mathematica bunu yapabilir. Ancak bu çok karmaşık ve zaman açısından pahalı ve genellikle çabaya değmeyecek çünkü gerçekten kusursuz bir hassasiyete ihtiyacınız yok. Fakat iyi bir hassasiyete ihtiyacınız var ve bu, yüzerlerin genelde tamsayılardan daha iyi bir iş çıkardığı yerdir.
leftaroundabout

53

Kesikli bir değer yerine sürekli bir değeri tanımlarken bunları kullanırsınız . Tarif etmek bundan daha karmaşık değil. Sadece ondalık basamaklı bir değerin sürekli olduğunu varsayma hatasını yapmayın. Parçalarda aynı anda değişirse, bir kuruş eklemek gibi, ayrıktır.


28

Burada gerçekten iki sorum var.

Neden birileri kayan nokta matematiğine ihtiyaç duyuyor?

Karl Bielefeldt'in belirttiği gibi, kayan nokta sayıları sürekli miktarları modellemenize izin verir - ve bunların her yerini bulursunuz - yalnızca fiziksel dünyada değil, iş ve finans gibi yerlerde bile.

Programlama kariyerimdeki birçok alanda kayan nokta matematiğini kullandım: kimya, AutoCAD üzerinde çalışıyor ve hatta finansal tahminler yapmak için bir Monte Carlo simülatörü yazıyor. Aslında, David E. Shaw adında bir adam var ve Wall Street'e milyarlarca uygulama yapmak için kayan nokta tabanlı bilimsel modelleme tekniklerini uyguladı.

Ve elbette, bilgisayar grafikleri var. Kullanıcı arayüzleri için göz şekeri geliştirmeye danışıyorum ve bugünlerde kayan nokta, trigonometri, analiz ve lineer cebir hakkında katı bir anlayış olmadan bunu yapmaya çalışıyorum, bir çakı ile silahla savaşmak gibi bir şey olurdu.

Neden biri bir çifte karşı yüzmeye ihtiyaç duyar ki ?

IEEE 754 standart gösterimleriyle, 32 bitlik bir kayan nokta size yaklaşık 7 ondalık basamak ve 10 - 38 - 10 38 aralığında üsler verir . 64 bitlik bir çift, yaklaşık 15 ondalık basamak ve 10 - 307 - 10 307 aralığındaki üst düzeyler sunar .

Bir şamandıranın herhangi birinin makul olarak ihtiyaç duyacağı şeyler için yeterli olacağı düşünülüyor olabilir, ama değil. Örneğin, birçok gerçek dünya büyüklüğü 7 ondalık basamağın üzerinde ölçülür.

Ancak, daha zekice, halk arasında "yuvarlama hatası" adı verilen bir sorun var. İkili kayan nokta gösterimleri, yalnızca kesirli kısımları 2, 1/2, 1/4, 3/4, vb. Gibi bir gücü olan bir paydası olan değerler için geçerlidir. 1/10 gibi diğer kesirleri temsil etmek için "yuvarlak" En yakın ikili kesir için değer, ancak biraz yanlış - bu "yuvarlama hatası". O zaman bu yanlış sayılarla matematik yaptığınızda, sonuçlardaki yanlışlıklar başladığınızdan çok daha kötü olabilir - bazen hata yüzdeleri çoğalır, hatta üstel olarak birikebilir.

Her neyse, ne kadar fazla ikili rakamla çalışmak zorundaysanız, yuvarlanmış ikili gösteriminiz, temsil etmeye çalıştığınız numaraya ne kadar yakınsa, bu nedenle de yuvarlama hatası daha küçük olacaktır. Daha sonra üzerinde matematik yaparsanız, üzerinde çalışılacak çok sayıda rakam varsa, kümülatif roundoff hatası bir problemin üzerine çıkmadan önce çok daha fazla işlem yapabilirsiniz.

Aslında, 64 bit 15 basamağıyla iki katına çıkıyor ve birçok uygulama için yeterli değil. 1985 yılında 80 bit kayan nokta sayıları kullanıyordum ve IEEE artık kullanabileceğini hayal edebileceğim bir 128 bit (16 bayt) kayan nokta türü tanımlıyor.


2
+1 Bob, astronomi için teleskop gibi yüksek çözünürlüklü kontrol sistemleriyle olan deneyimim, terimlerinizi sıralamadıkça 64bit'in iki katının yeterince iyi olmadığıdır. Yangın kontrolü ve uzun menzilli navigasyon için
aynen

20

Bu yaygın bir yanılgıdır, parayla uğraştığınız her yerde, değerini tamsayı (kuruş) olarak saklamanız gerekir. Çevrimiçi mağaza gibi bazı basit durumlarda doğru olsa da, daha gelişmiş bir şeye sahipseniz çok işe yaramaz.

Örnek verelim: bir geliştirici yılda 100.000 dolar kazanıyor. Tam ayının maaşı nedir? Tamsayı kullanarak, $ 12333.33 (¢ 833333) elde edersiniz, bu sayı 12 ile çarpılır ve 99,999,96 dolar olur. Tamsayı yardımı olarak tutmak mı? Hayır yapmadı.

Bankalar her zaman ondalık / tam sayı değerlerini kullanır mı? İşlem parçası için yapıyorlar. Ancak, örneğin, yatırım bankacılığı konuşmaya başlar başlamaz, fiili işlemleri takip etmek dışında, diğer her şey yüzer. Hepsi kurum içi kod olduğundan, onu göremezsiniz, ancak QuantLib'te en yüksek seviyeye çıkabilirsiniz , bu aslında aynıdır (çok daha temiz hariç ;-)).

Neden yüzer yüzer? Ondalık kullanmak, karekök, logaritmalar, tamsayı olmayan üslerle güç vb. İşlevler kullanırken hiç de yardımcı olmaz. Ve tabii ki, kayanlar Ondalık türlerden çok daha hızlıdır.


1
@Job - Ondalık sayılar ve kayanlar çok farklıdır. Sen edebilirsiniz ondalık tipinde tam 0.1 saklamak değil, Bir tayin veya çift.
Scott Whitlock

3
Başka bir sorum var. Eğer ödedi $100,000/12ve şamandıra kullandıysanız. Neden sonuç tam olarak 100.000 dolar olsun ki? Bir kişiye her ödendiğinde neden şamandıra (veya ondalık) yukarı veya aşağı yuvarlanmıyor? Çek yazarken (yüzde

@ asit: >>> x = 100000 / 12.0 >>> x * 12
100000.0

yorumumu tekrar okudun mu? Sorum her ay bir çek oluşturmak için yazılım kullandığımda. Kişi yüzde 1 ödeyemediği için, kişi bir yıl sonra tam tutarı nasıl elde eder?

2
@acid: tamsayı, ondalık veya float sonra bölme işleminden bağımsız olarak, düz bölme kullanamazsınız. İşte bütün mesele, ondalık kullanmak bu durumda yardımcı olmuyor.
vartec

4

Tanımladığınız şey, tüm giriş ve çıkışları kontrol ettiğiniz durumlar için mükemmel bir çalışma ortamıdır .

Gerçek anlamda durum böyle değil. Verilerini bir miktar hassasiyete gerçek değer olarak sağlayan ve verileri aynı formatta döndürmenizi bekleyen sistemler ile başa çıkmanız gerekecektir. Bu tür durumlarda, olacak bu sorunlarla.

Aslında, listelediğiniz püf noktaları kullansanız bile bu sorunlarla karşılaşacaksınız. Bir fiyata% 17.5 vergi hesaplarken, değeri dolar veya sent olarak saklasanız da kesirli sent elde edersiniz. Yeterince ödeme yapmazsanız, vergi mükellefi çok sinirlendiğinden, yuvarlama işlemini doğru yapmalısınız. Doğru moneytürleri kullanmak (kullandığınız dilde ne olursa olsun) sizi bir acı dünyasından kurtaracaktır.


Para tipi nedir? (dil veya referans bağlantısı) ve neden bu 'doğru' tür? 128 bit veya daha fazla bir şey olduğu için mi? Diğer neden "numaralarmı" kullanmak yanlış olur? Yüzde bir tam sayıya sahipsiniz. .175 ile çarparsanız, tam bir sayı alırsınız ve istediğiniz ne için kullanırsınız. Örneğinizi düşününce, float değerimi yeterince hassasiyetle tutabildiğini düşünüyorum ama 0.3f == 0.3d yanlış olma konusunda endişelenmek zorunda kalmayacağım. -edit- ve +1

1
@ acidzombie24 - Belirli bir tip demek istemedim, fakat dilinizin ne tür bir değeri para değerlerini temsil etmek için kullanıyor. Ayrıca 10 kuruşunuz varsa ve 0,175 ile çarptıysanız, 1,75 kuruşunuz var - bunun tamsayı aritmetiği ile nasıl başa çıkıyorsunuz? 1 kuruş mu, yoksa 2 kuruş mu? Yanlış anlayın ve müşteriniz vergi görevlisine çok para kazandırabilir.
ChrisF

Asla 10 (bir tam sayı) ile .175 (gerçek / değişken sayı) ile çarpmamalısınız, çünkü kesin sayıları tam sayılarla tam olmayan sayılarla karıştırmamalısınız; sonuç yanlış olacaktır. Başka bir deyişle, kesin sayılar sisteminde, 175 gibi bir değer asla bulunmaz ve bu yüzden bu duyusal olmayan bir hesaplamadır. Daha iyi bir çözüm, 10000 x 175'i çarpmak ve uygun olduğunda elle bir ondalık basamağı eklemek.
Barry Brown

8
@Barry - biliyorum. Aldığınız problem türünü göstermeye çalışıyordum. Ayrıca, vergi oranı% 17,5 ise 0.175 gibi bir değer söz konusudur ve vergiyi 10 sentlik bir mal için hesaplamanız gerekir.
ChrisF

1
@acidzombie: Para için kullanılacak doğru tür, yüksek (en az 4 ondalık nokta) hassasiyetle sabit nokta ondalıktır. Hiç bahane istemiyorum. Para değerlerini sentek olarak saklamak yeterli değildir , çünkü pratikte sadece iki hassasiyet noktası verir.
Aarona

3

"Tanrı bütün sayıları yarattı, her şey İnsanın işidir." - Leopold Kronecker (1886).

Tanım olarak, başka herhangi bir sayı türüne ihtiyacınız yoktur . Bir programlama dili için bütünlüğün korunması, çeşitli sayılar arasındaki basit ilişkilere dayanır. Tam sayılarla çalışabiliyorsanız (a / k / a doğal sayılar), her şeyi yapabilirsiniz.

Soru biraz aldatıcı çünkü onlara ihtiyacın yok. Belki uygun ya da en uygun ya da daha ucuz ya da başka bir şey istersiniz?


7
Bunları aynı zamanda tam sayılarla dağıtabiliriz, çünkü bunlardan yalnızca küme teorisi işlemleri ve boş küme kullanılarak da yapılandırılabilir. Ancak, hem bunlar hem de Turing'in bütünlüğünden savunarak, aşırıya taşınan akademik indirgemecilik var.
Bob Murphy

4
Ayrıca, Turing eksiksizliği yalnızca hesaplama için geçerlidir. Ne tam sayılar, ne de gerekçeler bile matematiksel olarak tamamlanmadı, çünkü ikisi de Cauchy dizilerinin yakınsamasına kapalı değildi. Yani Kronecker sıcak havayla doluydu: tam sayıları içeren tam bir metrik boşluk istiyorsanız, gerçek olmalısınız
Bob Murphy

1
@Bob Murphy: "Akademik indirgemecilik aşırıya kaçtı". Tam. Soru zayıftır ve bu mümkün cevabı yol açar.
S.Lott

2

Bir cümleyle, kayan noktalı ondalık türler, tamsayı değerlerini içine alır ve tamsayı değerlerinden (tüm bilgisayarın ikili düzeyde nasıl işleneceğini bilir; ikilide ondalık sayı yoktur) mantıksal, genellikle kolay olanı sağlar. Ondalık sayıların hesaplanması için arayüzü anlar.

Açıkçası, yüzmeye ihtiyacınız olmadığını söylemek, çünkü tamsayıları kullanarak ondalık matematiği nasıl yapacağınızı bilmek, aritmetik el yazısını nasıl yapacağınızı bilmek gibi bir şey, öyleyse neden bir hesap makinesi kullanıyorsunuz? Yani kavramı biliyorsun; Bravo. Bu, her zaman bu bilgiyi kullanmanız gerektiği anlamına gelmez. Sig incirlerini bir tamsayı miktarına dönüştürmekten ziyade, ikili bir whiz için basitçe 3.5 + 4.6 = 8.1 demek daha hızlı, daha ucuz ve daha anlaşılır bir durumdur.


1

Kayan nokta türlerinin birincil avantajı, çalışma zamanı açısından, hesaplama amaçlarının hızlı çoğunluğu için iki veya üç biçimin (daha fazla dil destekli 80 bit formatlar olmasını diliyorum) yeterli olacağıdır. Programlama dilleri bir sabit nokta tiplerini kolayca destekleyebiliyorsa, belirli bir performans seviyesi için gereken donanım karmaşıklığı genellikle sabit nokta tiplerinde, kayan noktalardan daha düşük olacaktır. Ne yazık ki, böyle bir destek sağlamak "kolay" olmaktan uzaktır.

Uygulamaların sayısal ihtiyaçlarının% 98'ini verimli bir şekilde karşılayan bir programlama dili için, düzinelerce tür içermesi ve yüzlerce kombinasyonun ne olabileceği ile ilgili işlemleri tanımlaması gerekir; ayrıca, bir programlama dili harika sabit nokta desteğine sahip olsa bile, bazı uygulamaların kayan nokta gerektirmek için yeterince geniş bir aralıkta kabaca sabit göreceli hassasiyet sağlamaları gerekecektir. Kayan nokta matematiğinin herhangi bir olayda bazı durumlarda gerekli olacağı göz önüne alındığında, donanım tedarikçilerinin iki veya üç kayan nokta formatı ile matematik performansına odaklanması ve bu formatları oldukça iyi çalıştıklarında bu formatları kullanmaları genellikle daha iyi sonuç verecektir. sabit puanlı matematik davranışını optimize etmeye çalışmaktan çok "paranın karşılığını bang".

Bu arada, sabit noktalı matematik 8-bit ve 16-bit işlemcilerde 32-bit işlemlerden daha avantajlıdır. 8 bit işlemcide, 32 bitin yeterli olmayacağı bir durumda, 40 bitlik bir tür yalnızca 32 bit türünden yalnızca% 25 daha fazla alana,% 25-50 daha fazla zamana mal olur ve% 37,5 gerektirir 64 bit türünden daha az yer ve% 37,5-60 daha az zaman. 32 bit platformunda, 32 bit türü bir şey için yeterli olmazsa, 64 bitten daha azını kullanmak için genellikle çok az neden vardır. 48 bit sabit nokta türü yeterliyse, 64 bit "çift", sabit nokta türüyle olduğu gibi çalışır.


0

Genel olarak, onları kullanırken çok dikkatli olmalısınız. Basit hesaplamalardan bile kaynaklanabilecek hassasiyet kaybını anlamak zordur. Örneğin, bunun gibi bir sayı listesinin ortalaması alınması çok kötü bir fikirdir:

double average(List<Double> data) {
  double ans = 0;
  for(Double d : data) {
    ans += d;
  }
  return ans / data.size();
}

Bunun nedeni, yeterince büyük listeler için, yeterince büyüdüğünde temelde tüm veri noktalarını kaybetmenizdir ans(örneğin, buna bakınız ). Bu kodun sorunu, küçük listeler için muhtemelen işe yaracağıdır - kırıldığı ölçüde.

Şahsen, onları yalnızca şu durumlarda kullanmanız gerektiğini düşünüyorum: a) hesaplama gerçekten hızlı olmalı; b) sonucun ortaya çıkmasının muhtemel olması umrunda değil (ne yaptığınızı gerçekten bilmiyorsanız).


-1

Bir düşünce, tamsayı aralığının dışındaki değerlerle uğraşmanız gerektiğinde kayan veya çift gösterimleri kullanmanız gerektiğidir.

Günümüz mimarileri (kabaca), +/- 2,147,483,647 (32 bit) veya +/- 9,223,372,036,854,775,807 (64 bit) imzalı bir tamsayı aralığına sahiptir. İmzasız, bunu 2 katına kadar uzatır.

IEEE 754 yüzer (kabaca) +/- 1,4 × 10 ^ −45 ila 3,4 × 10 ^ 38 arasında değişir. Bu aralığı +/- 5 × 10−324 ± 2.225 × 10 ^ −308 aralığında, burada belirtilmeyen birçok koşul ve özellik ile iki katına çıkarır.

Tabii ki, en çarpıcı açık sebep, -0 ;-) 'ı temsil etmeniz gerekebilir.


Öncelikle wikipedia makalelerinden sayılar ve açıklayıcı olması amaçlanmıştır. -0 dışında, sadece eğlence için.
Stephen

Sorun şu ki, bu geniş aralıkta hiç temsil edilmeyen çok sayıda tamsayı var.
Barry Brown

@BarryBrown Kesinlikle doğru. "birçok şart ve şartname çıkarıldı".
Stephen

-1

Genel sebep, JVM'nin genellikle temel donanım desteğini kullandığından hızlı olmalarıdır (strictfp kullanmıyorsanız).

Bkz https://stackoverflow.com/questions/517915/when-to-use-strictfp-keyword-in-java strictfp ima ne için.


Kayan nokta matematik tamsayılı matematikten daha mı hızlı? Kayan nokta hesaplamaları hangi işlemcide tamsayılı hesaplamalardan daha az döngü gerçekleştirir?
this.josh

1
@ this.josh, kesinlikle numaranızdaki rakam sayısına bağlıdır. Ayrıca tamsayılar, hangisi önemli olabilecek veya olmayabilir kesin olarak bölünemezler.

-2

Bu yüzden 256bit işletim sistemine ihtiyacımız var.

Tahta uzunluğu (ölçebileceğiniz en küçük mesafe) = 10 ^
-35m Gözlenebilir evren, = 10 ^ 25m boyunca 14Bn parsektir.
Böylece, yalnızca 200 bit hassasiyetiniz varsa, Plank uzunluğundaki birimlerdeki tamsayıları ölçebilirsiniz.


2
-1: ya gözlemlenebilir evrenden daha büyük ölçekte şeyler simüle ediyorsanız?
amara

2
@sparkleshy, FAR göstericileri bunun için!
Martin Beckett
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.