30 Soru: Kayan nokta matematiği bozuk mu?

tarafından oluşturulan soru Mon, Apr 29, 2019 12:00 AM

Aşağıdaki kodu göz önünde bulundurun:

 
0.1 + 0.2 == 0.3  ->  false
 
0.1 + 0.2         ->  0.30000000000000004

Bu yanlışlıklar neden oluyor?

    
2655
  1. Kayan nokta değişkenleri tipik olarak bu davranışa sahiptir. Donanımda nasıl depolandıklarından kaynaklanır. Daha fazla bilgi için Kayan nokta sayılarıyla ilgili Wikipedia makalesine bakın.
    2009-02-25 21: 41: 51Z
  2. JavaScript, ondalık sayıları kayan nokta sayıları , yani toplama gibi işlemler yuvarlama hatasına neden olabilir. Bu makaleye bir göz atmak isteyebilirsiniz: Her Bilgisayar Bilim Adamının Neleri Öğrenmesi Gerekenler Kayan Nokta Aritmetiği
    2009-02-25 21: 42: 49Z
  3. Sadece bilgi için, javascript'teki TÜM sayısal türler IEEE-754 Çiftler'dir.
    2010-04-11 13: 01: 33Z
  4. JavaScript, Matematik için IEEE 754 standardını kullandığından, 64 bit değişken sayıları kullanır. Bu, kayan nokta (ondalık) hesaplamaları yapılırken kısaca, Taban 2 'de çalışan bilgisayarların ondalık basamağı Taban 10 olduğu için hassas hatalara neden olur.
    2018-05-07 04: 57: 28Z
  5. 2018-11-15 16: 10: 43Z
  6. 30 Yanıtlar                              30                         

    İkili kayan nokta matematiği bu şekildedir. Çoğu programlama dilinde, IEEE 754 standardına dayanmaktadır. JavaScript, Java'nın double ile aynı olan 64 bit kayan nokta gösterimini kullanır. Sorunun temel noktası, sayıların bu sayı biçiminde bir tam sayı çarpı iki gücüyle temsil edilmesidir; paydası ikisinin gücü olmayan rasyonel sayılar (0.1 gibi 1/10 gibi) tam olarak gösterilemez.

    Standart 0.1 biçimindeki binary64 için, gösterim tam olarak aynı şekilde yazılabilir

    •  Ondalık 0.1000000000000000055511151231257827021181583404541015625 veya
    •  0x1.999999999999ap-4 C99 altıgen gösterimi 'de.

    Buna karşılık, 0.1 olan 1/10 rasyonel numarası tam olarak yazılabilir

    •  Ondalık 0.1 veya
    •  0x1.99999999999999...p-4, 999'un bitmeyen bir dizisini temsil ettiği, C99 hexfloat notasyonu analogunda ...'u gösterir.

    Programınızdaki 0.2 ve 0.3 sabitleri aynı zamanda gerçek değerlerine de yakın olacaktır. En yakın double ila 0.2'un rasyonel sayı 0.2'dan daha büyük olduğu, ancak en yakın double ila 0.3'un rasyonel sayı 0.3'dan daha küçük olduğu görülür. 0.1 ve 0.2’un toplamı 0.3 rasyonel sayısından daha büyük olduğundan ve kodunuzdaki sabitle aynı fikirde olmadığınızı gösterir.

    Kayan nokta aritmetik sorunlarının oldukça kapsamlı bir tedavisi Her Bilgisayar Bilim İnsanının Kayan Nokta Aritmetiği Hakkında Bilmeniz Gerekenler . Sindirimi daha kolay bir açıklama için, bkz. floating-point-gui.de .

    Yan Not: Tüm konumsal (temel-N) sayı sistemleri bu sorunu hassasiyetle paylaşır

    Eski düz ondalık basamak (sayı 10) aynı sorunlara sahiptir, bu yüzden 1/30,33333333 olarak p ...

    Ondalık sistemde gösterilmesi kolay olan ancak ikili sisteme uymayan bir sayıya (3/10) rastladınız. Her iki yönde de (bir dereceye kadar) gider: 1/16, ondalık sayıdaki (0.0625) çirkin bir sayıdır, ancak ikili dosyada, 10.000'in ondalık basamağındaki kadar düzgün görünüyor (0.0001) ** - eğer Günlük yaşamlarımızda 2 numaralı bir sayı sistemini kullanma alışkanlığı, o sayıya bile bakarsınız ve bir şeyi yarıya indirmek, tekrar yarıya indirmek ve tekrar tekrar oraya varabileceğinizi içgüdüsel olarak anlarsınız.

    ** Elbette, kayan nokta sayılarının bellekte depolandığı tam olarak bu değildir (bir bilimsel gösterim şekli kullanırlar). Bununla birlikte, ikili kayan nokta kesinlikli hassasiyet hatalarının çoğalmaya meyilli olduğu noktasını göstermektedir, çünkü birlikte çalışmakla genellikle ilgilendiğimiz "gerçek dünya" sayıları, çoğu zaman onluk güçlerdir - ancak yalnızca ondalık sayı sistemi kullandığımız için- bugün. Bu yüzden "her 7 kişiden 5'i" yerine% 71 gibi şeyler söyleyeceğiz (% 71 bir yaklaşımdır, çünkü 5/7 tam olarak herhangi bir ondalık sayı ile gösterilemez).

    Öyleyse hayır: ikili kayan nokta sayıları bozulmaz, sadece diğer her N temel sayı sistemi gibi kusursuz olurlar :)

    Yan Taraf Not: Programlamada Yüzenlerle Çalışma

    Uygulamada, bu hassaslık sorunu, kayan nokta sayılarınızı, görüntülemeden önce ilgilendiğiniz birçok ondalık basamağa yuvarlamak için yuvarlama işlevlerini kullanmanız gerektiği anlamına gelir.

    Eşitlik testlerini bazı toleranslara izin veren karşılaştırmalarla değiştirmeniz de gerekir; bunun anlamı:

    Yapma yapma yapma if (float1 == float2) { ... }

    Bunun yerine if (Math.Abs(float1 - float2) < myToleranceValue) { ... } yapın.

    myToleranceValue, 1/2 ^ 16 (0.0000152587890625) gibi bir şey olabilir. Javascript'te, tolerans olarak kullanmanız için Number.EPSILON değeri verilmiştir.

        
    2002
    2019-05-17 22: 22: 06Z
    1. 'Bazı hata sabitleri', Epsilon değeri olarak da bilinir.
      2010-04-09 12: 47: 06Z
    2. "Bazı hata sabiti" nin "Epsilon" dan daha doğru olduğunu düşünüyorum çünkü her durumda kullanılabilecek bir "Epsilon" yok. Farklı durumlarda farklı epsilonların kullanılması gerekir. Ve makine epsilon neredeyse hiç kullanılmayacak kadar iyi bir sabit değildir.
      2010-09-04 23: 33: 57Z
    3. Tüm kayan nokta matematiğinin IEEE [754] standardına dayandığı kesin değil . Örneğin, eski IBM onaltılık FP'ye sahip bazı sistemler var ve hala IEEE-754 aritmetiğini desteklemeyen grafik kartları var. Bununla birlikte, makul bir yaklaşım için de geçerlidir.
      2013-01-03 23: 36: 29Z
    4. Cray, IEEE-754'ün hıza uyumunu engelledi. Java, optimizasyon olarak bağlılığını da gevşetti.
      2013-02-12 03: 12: 57Z
    5. Bu cevaba, paradaki hesaplamaların her zaman, her zaman tamsayıları üzerinde sabit nokta aritmetik ile yapılması gerektiği hakkında bir şeyler eklemeniz gerektiğini düşünüyorum. çünkü para ölçülür. (Bir kuruşun küçük kesirlerinde veya en küçük para biriminiz ne olursa olsun, iç muhasebe hesaplamaları yapmak mantıklı gelebilir - bu genellikle örneğin "aylık 29,99 $" bir günlük ücrete dönüştürürken yuvarlama hatasını azaltmada yardımcı olur - ancak hala sabit nokta aritmetiği olabilir.)
      2014-05-12 22: 23: 27Z

    Bir Donanım Tasarımcısının Perspektifi

    Kayan nokta donanımı tasarlayıp oluşturduğum için buna bir donanım tasarımcısı bakış açısı eklemem gerektiğine inanıyorum. Hatanın kökenini bilmek, yazılımda neler olup bittiğini anlamada yardımcı olabilir ve nihayetinde, bunun kayan nokta hatalarının neden oluştuğunun ve zaman içinde birikmiş gibi görünmesinin nedenlerini açıklamaya yardımcı olacağını umuyorum.

    1. Genel Bakış

    Mühendislik açısından bakıldığında, kayan nokta işlemlerinin çoğu kayan nokta yapan donanımdan bu yana bazı hata unsurlarına sahip olacaktır.hesaplamalar sadece en son bir ünitenin yarısından daha az bir hataya sahip olmak için gereklidir. Bu nedenle, çoğu donanım, özellikle kayan nokta bölmelerinde sorunlu olan tek bir işlem için en son bir ünitenin yarısından daha az bir hata vermesi için gereken kesinlikte duracaktır. Tek bir işlemi oluşturan şey, ünitenin kaç tane opera aldığına bağlıdır. Çoğu için, iki, ancak bazı birimler 3 veya daha fazla opera alır. Bu nedenle, zaman içinde yapılan hataların artmasından dolayı tekrarlanan işlemlerin istenen bir hataya neden olacağının garantisi yoktur.

    2. Standartlar

    Çoğu işlemci IEEE-754 standardını izler, ancak bazılarının denormalize veya farklı standartlar kullandığını . Örneğin, IEEE-754'te çok küçük kayan nokta sayılarının hassasiyet pahasına gösterilmesine izin veren denormalize bir mod vardır. Bununla birlikte, aşağıdakiler, tipik çalışma modu olan normalleştirilmiş IEEE-754 modunu kapsayacaktır.

    IEEE-754 standardında, donanım tasarımcılarına en son yerdeki bir birimin yarısından az olduğu sürece herhangi bir hata /epsilon değerine izin verilir ve sonuç yalnızca bir birimin yarısından az olması gerekir bir operasyon için son yerde. Bu, tekrarlanan işlemler olduğunda neden hataların toplandığını açıklar. IEEE-754 çifte hassasiyet için bu 54. bittir, çünkü 53 bit, kayan nokta sayısının (ör. 5.3e5'teki 5.3) mantis olarak da adlandırılan sayısal parçayı (normalize edilmiş) temsil etmek için kullanılır. Sonraki bölümler, çeşitli kayan nokta işlemlerinde donanım hatasının nedenleri hakkında daha ayrıntılı bilgi vermektedir.

    3. Bölümdeki Yuvarlama Hata Nedeni

    Kayan nokta bölümündeki hatanın ana nedeni bölümü hesaplamak için kullanılan bölme algoritmalarıdır. Bilgisayar sistemlerinin çoğu, çoğunlukla Z=X/Y, Z = X * (1/Y)’da çarpımı kullanarak bölmeyi hesaplar. Bir bölme, yinelemeli olarak hesaplanır, yani her döngü, IEEE-754 için en sonda bir birimden daha az hata içeren bir şey olan istenen kesinliğe ulaşılana kadar bölümün bazı bitlerini hesaplar. Y (1 /Y) 'nin karşılıklı giriş tablosu, yavaş bölümdeki bölüm seçim tablosu (QST) olarak bilinir ve bölüm seçim çizelgesinin bit cinsinden büyüklüğü, genellikle sayı tabanının genişliği veya bir dizi bit olur. bölüm, her bir yinelemede hesaplanmıştır, ayrıca bir kaç koruma bitidir. IEEE-754 standardı için, çift duyarlıklı (64 bit), bölücünün yarı çapının büyüklüğü, artı k>=2 olan birkaç koruyucu uç k olacaktır. Bu nedenle, örneğin, bir anda 2 bit hesaplayan (radix 4) bir bölücü için tipik bir Bölüm Seçim Tablosu, 2+2= 4 bit (artı birkaç isteğe bağlı bit) olacaktır.

    3.1 Bölüm Yuvarlama Hatası: Karşılıklıya Yaklaşım

    Bölüm seçimi tablosundaki karşılık gelenler bölme yöntemine bağlıdır: SRT bölümü gibi yavaş bölme veya Goldschmidt bölümü gibi hızlı bölme; Her giriş, bölme algoritmasına göre, mümkün olan en düşük hatayı verme çabasıyla değiştirilir. Her halükarda olsa da, tüm karşılıklı varlıklar, gerçek karşıtın yaklaşıklarıdır ve bazı hatalar ortaya koyarlar. Hem yavaş bölünme hem de hızlı bölme yöntemleri, bölümü yinelemeli olarak hesaplar, yani bölümün bazı bitleri her adımda hesaplanır, daha sonra sonuç, temettüden çıkarılır ve bölücü, hata bir bölüden daha küçük olana kadar adımları tekrarlar son yerde birim. Yavaş bölme yöntemleri, her adımda bölümün sabit bir basamağını hesaplar ve genellikle inşa edilmesi daha düşük maliyetlidir ve hızlı bölme yöntemleri, adım başına değişken basamak sayısını hesaplar ve genellikle yapımı daha pahalıdır. Bölme yöntemlerinin en önemli kısmı, çoğunun bir karşılıklılığın yaklaşımı ile tekrarlanan çarpma işlemine dayanmasıdır, bu yüzden hataya açıktırlar.

    4. Diğer İşlemlerde Yuvarlama Hataları: Kesme İşlemi

    Tüm işlemlerde yuvarlama hatalarının bir başka nedeni de, IEEE-754'ün izin verdiği son cevabın farklı kesme modlarıdır. Kesik, sıfıra doğru yuvarlak, en yakına (varsayılan), yuvarlak var aşağı ve yukarı doğru. Tüm yöntemler, tek bir işlem için en son yerde bir üniteden daha az hata unsuru sunar. Zaman içinde ve tekrarlanan işlemler sırasında, kesme ayrıca ortaya çıkan hataya kümülatif olarak da eklenir. Bu kesme hatası, özellikle tekrar tekrar çarpmanın bir türünü içeren, üstelimde sorunludur.

    5. Tekrarlanan İşlemler

    Har'dan beriKayan nokta hesaplamaları yapan donanıma sadece tek bir işlem için son bir yerde bir birimin yarısından daha az bir hatayla sonuç verilmesi gerekir, izlenmediği takdirde hata tekrarlanan işlemlere göre artar. Bunun nedeni sınırlı bir hata gerektiren hesaplamalarda, matematikçilerin en yakına yaklaşan son hanesinde bile rakam , çünkü zaman içinde hataların birbirini iptal etme olasılığı daha yüksektir ve Aralık Aritmetiği , IEEE varyasyonlarıyla birlikte Yuvarlama hatalarını tahmin etmek ve düzeltmek için 754 yuvarlama modu Diğer yuvarlama modlarına kıyasla düşük göreceli hatası nedeniyle, en yakın düz basamağa (en son sırada), IEEE-754'ün varsayılan yuvarlama modudur.

    Varsayılan yuvarlama kipinin, en yakın yuvarlanmaya kadar en son basamakta bile olduğunu unutmayın. a>, bir operasyon için son yerdeki bir birimin yarısından daha az bir hatayı garanti eder. Kısaltmanın kullanılması, tek başına yuvarlama ve tek başına yuvarlama, son yerdeki bir birimin yarısından büyük, ancak son yerdeki bir üniteden daha az bir hataya neden olabilir; Aralık Aritmetrisinde kullanılır.

    6. Özet

    Kısacası, kayan nokta işlemlerinde hataların temel nedeni, donanımdaki kesilmenin ve bölünme durumunda karşılıklı kesmenin kesilmesidir. IEEE-754 standardı, tek bir işlem için son bir yerde yalnızca bir birimin yarısından daha az bir hata gerektirdiğinden, tekrarlanan işlemler üzerindeki kayan nokta hataları düzeltilmedikçe eklenecektir.

        
    560
    2018-04-13 16: 42: 24Z
    1. (3) yanlıştır. Bir bölümdeki yuvarlama hatası, en sondaki bir birimden daha az değil, en sondaki birimin yarısından daha azdır.
      2014-04-23 22: 31: 22Z
    2. @ gnasher729 İyi yakalama. Çoğu temel işlem, varsayılan IEEE yuvarlama modunu kullanarak en son bir birimden 1/2 sinden daha az hata yapar. Açıklamayı düzenledi ve ayrıca kullanıcı varsayılan yuvarlama modunu geçersiz kılarsa hatanın bir ulp'in 1 /2'sinden büyük, ancak 1 ulp'den küçük olabileceğini belirtti.
      2014-04-24 11: 17: 14Z
    3. (1) Kayan nokta sayılar hata yok. Her kayan nokta değeri tam olarak budur. işlemlerin kayan noktaların çoğu (tümü değil) kesin sonuç verir. Örneğin, tam olarak 1.0 /10.0'a eşit olan bir ikili kayan nokta değeri yoktur. Bazı işlemler (örneğin, 1.0 + 1.0), yapar diğer yandan da kesin sonuçlar verir.
      2014-06-10 16: 31: 54Z
    4. "Kayan nokta bölümündeki hatanın ana nedeni, bölümü hesaplamak için kullanılan bölme algoritmalarıdır", çok yanıltıcıdır söylemek. IEEE-754 uyumlu bir bölüm için, kayan nokta bölümündeki sadece hatanın nedeni, sonucun sonuç biçiminde tam olarak gösterilememesidir; aynı sonuç kullanılan algoritmadan bağımsız olarak hesaplanır.
      2015-02-23 20: 23: 31Z
    5. @ Matt Geç cevap için özür dilerim. Temel olarak kaynak /zaman sorunları ve değişimlerden kaynaklanıyor. Uzun bölünme /daha 'normal' bölme yapmanın bir yolu var, buna, iki katına sahip SRT Bölme denir. Bununla birlikte, bu tekrar tekrar bölücüyü temettüden ayırır ve çıkarır ve saat devri başına sadece bir bit hesapladığından birçok saat döngüsü alır. Karşılıklı tablolar kullanırız, böylece döngü başına bölümden daha fazla bit hesaplayabiliriz ve etkin performans /hız değişimleri yapabiliriz.
      2016-02-01 15: 33: 30Z

    .1 veya 1/10'u taban 2'ye (ikili) dönüştürdüğünüzde, ondalık noktadan sonra yinelenen bir düzen elde edersiniz, tıpkı 10'da 1/3 göstermeye çalışır gibi normal kayan nokta yöntemleri ile tam matematik yapmayın.

        
    422
    2009-02-25 22: 07: 00Z
    1. Harika ve kısa cevap. Yinelenen desen, 0,000110011001100110011001100110011001100110011001100110011 ... gibi görünüyor
      2012-06-16 14: 22: 35Z
    2. Bu, neden ilk başta ikili dosyalara dönüşmeyen daha iyi bir algoritma kullanılmadığını açıklamıyor.
      2016-05-10 14: 43: 53Z
    3. Çünkü performans. İkili dosya kullanımı birkaç bin kat daha hızlıdır çünkü makine için doğaldır.
      2016-05-10 19: 30: 37Z
    4. Kesin ondalık değerler veren ARE yöntemleri var. BCD (İkili kodlu ondalık) ya da diğer ondalık sayı biçimleri. Ancak, bunlar hem daha yavaştır (LOT yavaş) hem de ikili kayan nokta kullanmaktan daha fazla depolama alırlar. (bir örnek olarak, paketlenmiş BCD bir baytta 2 ondalık basamak saklar. Bu, bir baytta gerçekte 256 olası değer depolayabilen 100 olası değerdir ya da bir baytın olası değerlerinin yaklaşık% 60'ını boşa harcayan 100/256'dır.)
      2016-06-21 16: 43: 02Z
    5. @ Jacksonkr-10'da hala düşünüyorum. Bilgisayarlar temel 2'dir.
      2016-11-14 16: 03: 08Z

    Buradaki çoğu cevap bu soruyu çok kuru ve teknik olarak ele almaktadır. Bunu normal insanların anlayabileceği şekilde ele almak isterim.

    Pizza dilimlemeye çalıştığınızı hayal edin. Tam pizza dilimlerini yarıya kesebilen robot bir pizza kesiciniz var. Bir pizzayı yarıya indirebilir veya mevcut bir dilimi yarıya indirebilir, ancak her durumda yarıya da her zaman kesindir.

    Bu pizza kesicinin çok iyi hareketleri var ve eğer bütün bir pizzayla başlarsanız, o zaman bunu ikiye bölün ve en küçük dilimi yarıya devam ettirin, dilimden önce yarıyı 53 kez yapabilirsiniz. yüksek hassasiyetli yetenekleri için bile çok küçük. Bu noktada, artık çok ince bir dilimi yarıya çıkaramazsınız, ancak onu olduğu gibi içermeli veya hariç tutmalısınız.

    Şimdi, tüm dilimleri bir onda birine (0.1) veya beşte birine (0.2) kadar pizza ekleyebilecek şekilde nasıl hazırlarsınız? Gerçekten düşün ve çalışmayı dene. Elinizde efsanevi bir hassas pizza kesiciniz varsa, gerçek bir pizza kullanmayı da deneyebilirsiniz. : -)


    Çoğu deneyimli programcı, elbette, gerçek cevabı bilir; bu da ne kadar ince dilimleseniz yapın, bu dilimleri kullanarak pizzaların onda birini veya beşte birini bir araya getirmenin bir yolu yoktur. onlar. Oldukça iyi bir yaklaştırma yapabilirsiniz ve 0,1 yaklaşımıyla 0,2 yaklaşımı eklerseniz, 0,3 ile oldukça iyi bir yaklaşıma sahip olursunuz, ancak yine de bir yaklaşımdır.

    İkili hassas sayılar için (bu, pizzalarınızı 53 kez yarıya almanıza izin veren hassasiyettir), 0,1'den az ve daha büyük sayılar, 0,0999999999999999999733231530032000000000055511151231257827021541500150000000000555111512312578270815415445515415445515445515545615345345345350549797979504914491449144914491449144949497949494935353579795505505505797920151515157979111015157979111015157979 Diğer Sipariş Sonuncusu öncekinden 0.1'e biraz daha yakındır, bu nedenle sayısal bir ayrıştırıcı, 0.1 girdisi verildiğinde ikincisini lehine çevirir.

    (Bu iki sayı arasındaki fark, ya yukarı doğru bir önyargı sağlayan ya da aşağı doğru bir önyargı getiren dışlamanın dahil edilmesine karar vermemiz gereken en küçük dilimdir. Bu en küçük dilim için teknik terim: href = "https://en.wikipedia.org/wiki/Unit_in_the_last_place"> ulp .)

    0.2 durumunda, sayılar tamamen aynıdır, sadece 2 kat ölçeklenir. Yine, 0.2'den biraz yüksek olan değeri tercih ederiz.

    Her iki durumda da, 0,1 ve 0,2 için yaklaşık değerlerin bir değeri olduğuna dikkat edin.t yukarı doğru önyargı. Bu önyargıları yeterince eklersek, sayıyı istediğimizden daha ileri ve uzağa iteceklerdir, ve aslında 0,1 + 0,2 olması durumunda, önyargı, ortaya çıkan sayı artık en yakın sayı olmayacak kadar yüksek olacaktır. 0.3’e.

    P.S.. Bazı programlama dilleri ayrıca dilimleri tam onda birine bölen pizza kesicileri de sağlar. Her ne kadar bu tür pizza kesiciler nadir olsa da, birine erişiminiz varsa, bir dilimin tam olarak onda biri veya beşte birini alabilmeniz önemli olduğunda bunu kullanmalısınız.

    (Aslen Quora'da gönderildi.)

        
    274
    2014-11-22 04: 44: 18Z
    1. Kesin matematik içeren bazı diller olduğunu unutmayın. Bir örnek, örneğin GNU Guile aracılığıyla Şemadır. Bkz. draketo.de/english/exact-math-to-the-rescue - bunlar matematiği kesirler olarak tutar ve sadece sonunda kesilir.
      2014-11-20 06: 40: 16Z
    2. @ FloatingRock Aslında, çok az sayıda ana programlama dilinin yerleşik rasyonel sayıları vardır. Arne benim gibi bir Schemer, yani bunlar şımarık olduğumuz şeyler.
      2014-11-25 16: 56: 48Z
    3. @ ArneBabenhauserheide Bunun sadece rasyonel sayılarla çalışacağını eklemeye değer olduğunu düşünüyorum. Yani, pi gibi irrasyonel sayılarla biraz matematik yapıyorsanız, onu bir pi olarak saklamanız gerekir. Elbette, pi içeren herhangi bir hesaplama, tam bir ondalık sayı olarak gösterilemez.
      2015-03-11 13: 06: 23Z
    4. @ connexo Tamam. Pizza döndürücünüzü 36 derece almaya nasıl programladınız? 36 derece nedir? (İpucu: Bunu tam olarak tanımlayabiliyorsanız, aynı zamanda onuncu bir pizza kesiciye de sahip olursunuz.) Başka bir deyişle, aslında 1/360 (derece) veya 1 /Sadece ikili kayan noktalı 10 (36 derece).
      2015-08-13 14: 50: 56Z
    5. @ connexo Ayrıca, "her salak" bir pizzayı tam olarak 36 derece döndüremez. İnsanlar bu kadar kesin bir şey yapamayacak kadar hataya açık.
      2015-08-13 14: 51: 44Z

    Kayan nokta yuvarlama hataları. 0,1, üs-10'da, 5-eksik asal çarpanı nedeniyle taban-10'da olduğu gibi doğru gösterilemez. 1/3 gibi, ondalık sayıda temsil etmek için sonsuz sayıda basamak alır, ancak taban-3'te "0.1" olur. 0,1, üs-2’de sonsuz sayıdaki basamağı alır, burada üs-10’da bulunmaz. Ve bilgisayarların sonsuz miktarda belleği olmaz.

        
    204
    2009-02-25 21: 41: 23Z
    1. bilgisayarların 0,1 + 0,2 = 0,3 sağ elde etmek için sonsuz miktarda belleğe ihtiyacı yoktur
      2011-10-15 16: 27: 52Z
    2. @ Pacerier Elbette, bir kesriyi temsil etmek için iki sınırlandırılmamış hassas tamsayı kullanabilirler veya alıntı notasyonu kullanabilirler. Bu imkansız kılan “ikili” veya “ondalık” kavramıdır - bir ikili /ondalık basamak dizisi ve orada bir yerde bir sayı tabanı noktası olduğu fikri. Kesin rasyonel sonuçlar almak için daha iyi bir biçime ihtiyacımız var.
      2011-10-15 19: 45: 03Z
    3. @ Pacerier: Ne ikili ne de ondalık kayan nokta tam olarak 1/3 veya 1/13 depolayamaz. Ondalık kayan nokta türleri kesin olarak M /10 ^ E, biçimini temsil edebilir, ancak diğer kesirlerin çoğunu temsil etmeye gelince, benzer boyuttaki ikili kayan nokta sayılarından daha az hassastır . Pek çok uygulamada, birkaç "özel" olanla kusursuz bir kesinlik elde etmekten çok, isteğe bağlı kesirlerle daha yüksek kesinlik elde etmek daha yararlıdır.
      2014-04-24 16: 43: 59Z
    4. @ Pacerier Sayıları, iki noktadaki değişkenler olarak saklıyorlarsa, yaparlar .
      2014-08-14 22: 04: 46Z
    5. @ chux: İkili ve ondalık türler arasındaki duyarlık farkı büyük değil, ondalık sayı için en iyi durumla en kötü durum duyarlığında 10: 1 fark var türleri, ikili türlerle 2: 1 farkından çok daha büyüktür. Ne donanımda ne de yazılımda verimli bir şekilde uygulanmaya elverişli görünmeyeceğinden, herhangi birinin ondalık tiplerden herhangi birinde etkin bir şekilde çalışmak için donanım veya yazılıma sahip olup olmadığını merak ediyorum.
      2015-08-26 19: 47: 05Z

    Diğer doğru cevaplara ek olarak, kayan nokta aritmetiğiyle ilgili sorunlardan kaçınmak için değerlerinizi ölçeklendirmeyi düşünebilirsiniz.

    Örneğin:

     
    var result = 1.0 + 2.0;     // result === 3.0 returns true
    

    ... yerine:

     
    var result = 0.1 + 0.2;     // result === 0.3 returns false
    

    0.1 + 0.2 === 0.3 ifadesi JavaScript'te false değerini döndürür, ancak neyse ki kayan noktadaki tamsayı aritmetiği kesindir, bu nedenle ondalık gösterim hatalarından ölçeklendirme ile kaçınılabilir.

    Pratik bir örnek olarak, doğruluğun en üst düzeyde olduğu kayan nokta sorunlarından kaçınmak için, parayı sent sayısını temsil eden bir tamsayı olarak ele almanız 1 önerilir. 2550 dolar yerine 25.50 sent.


    1 Douglas Crockford: JavaScript: İyi Parçalar : Ek A - Kötü Parçalar (sayfa 105) .

        
    113
    2010-09-05 02: 02: 26Z
    1. Sorun, dönüşümün kendisinin yanlış olmasıdır. 16.08 * 100 = 1607.9999999999998. Numarayı bölmeye ve ayrı olarak dönüştürmeye başvurmalı mıyız (16 * 100 + 08 = 1608'de olduğu gibi)?
      2011-10-07 19: 13: 23Z
    2. Buradaki çözüm, tüm hesaplamalarınızı tamsayıda yapmak ve sonra oranınıza göre bölmek (bu durumda 100) ve yalnızca verileri sunarken yuvarlamaktır. Bu, hesaplamalarınızın her zaman kesin olmasını sağlayacaktır.
      2011-12-08 21: 38: 04Z
    3. Sadece biraz nitpick yapmak için: tamsayı aritmetiği yalnızca bir noktaya kadar kayan noktalarda kesin (punto amaçlanmıştır). Sayı 0x1p53'ten büyükse (Java 7'nin onaltılık kayan nokta işaretini kullanmak için = = 9007199254740992), o zaman ulp bu noktada 2'dir ve bu nedenle 0x1p53 + 1 0x1p53'e yuvarlanır (ve 0x1p53 + 3 0x1p53 + değerine yuvarlanır) 4, çünkü yuvarlak bile). :-D Ama şüphesiz, numaran 9 katrilyondan küçükse, iyi olmalısın. :-P
      2014-12-03 13: 28: 49Z
    4. Öyleyse .1 + .2’un .3’u göstermesini nasıl sağlarsınız?
      2015-06-21 05: 58: 32Z
    5. Jason, sonucu yuvarlak yapmalısınız (int) (16.08 * 100 + 0.5)
      2015-12-23 09: 10: 39Z

    Cevabım oldukça uzun, ben de üç bölüme ayırdım GünahSoru, kayan nokta matematiği ile ilgili, makinenin gerçekte ne yaptığını vurguladım. Ayrıca çift (64 bit) hassasiyete özgü yaptım, ancak argüman herhangi bir kayan nokta aritmetiğine eşit olarak uygulanır.

    Başlangıç ​​

    Bir IEEE 754 çift duyarlıklı ikili kayan nokta biçimi (ikili64) sayı, formun bir sayısını temsil eder

      

    değer = (-1) ^ s * (1.m 51 m 50 ... m 2 m 1 m 0 ) 2 * 2 e-1023

    64 bit içinde:

    • İlk bit işaret bitidir : sayı negatifse 1, aksi takdirde 0 sup> 1 .
    • Sonraki 11 bit, üs bileşenidir. /en.wikipedia.org/wiki/Offset_binary 1023 itibariyle "rel =" noreferrer "> ofset . Başka bir deyişle, üst bitleri çift duyarlıklı bir sayıdan okuduktan sonra, 1023'ün gücünü elde etmek için çıkarılması gerekir. iki.
    • Kalan 52 bit, önemidir (veya mantis). Mantis'te, bir 'ima edilen' 1., her ikilik değerin en önemli biti 1 olduğu için her zaman 2 ihmal edilir.

    1 - IEEE 754, sıfır imzalı kavramına izin verir > - +0 ve -0 farklı muamele görür: 1 / (+0) pozitif sonsuzdur; 1 / (-0) negatif sonsuzdur. Sıfır değerler için, mantis ve üs bitlerinin tümü sıfırdır. Not: Sıfır değerler (+0 ve -0) açıkça 2 denormal olarak sınıflandırılmamıştır.

    2 - Bu, denormal sayılar için geçerli değildir. sıfır ofset üssüne sahip (ve ima edilen 0.). Denormal çift duyarlıklı sayılar aralığı d dak ≤ | x | ≤ d maks , burada d min (sıfırdan temsil edilemeyen en küçük sayı), 2 -1023 - 51 (≈ 4.94 * 10 - 324 ) ve d max (mantisanın tamamen 1 sn'den oluştuğu en büyük denormal sayı) 2 -1023 + 1 - 2 -1023 - 51 (≈ 2.225 * 10 -308 ).


    İkili hassasiyete bir sayıyı ikiliye çevirme

    İkili hassas kayan nokta sayısını ikiliye dönüştürmek için pek çok çevrimiçi dönüştürücü bulunur (örneğin, binaryconvert.com ), fakat işte çift duyarlıklı bir sayı için IEEE 754 gösterimini elde etmek için bazı örnek C # kodu. (Üç parçayı kolonlarla (:) ayırırım:

     
    public static string BinaryRepresentation(double value)
    {
        long valueInLongType = BitConverter.DoubleToInt64Bits(value);
        string bits = Convert.ToString(valueInLongType, 2);
        string leadingZeros = new string('0', 64 - bits.Length);
        string binaryRepresentation = leadingZeros + bits;
    
        string sign = binaryRepresentation[0].ToString();
        string exponent = binaryRepresentation.Substring(1, 11);
        string mantissa = binaryRepresentation.Substring(12);
    
        return string.Format("{0}:{1}:{2}", sign, exponent, mantissa);
    }
    

    Konuya gelmek: orijinal soru

    (TL için altına atla; DR sürümü)

    Cato Johnston (soru soran) neden 0.1 + 0.2! = 0.3 olduğunu sordu.

    İkili olarak yazılmıştır (üç parçayı ayıran iki nokta ile), değerlerin IEEE 754 gösterimleri:

     
    0.1 => 0:01111111011:1001100110011001100110011001100110011001100110011010
    0.2 => 0:01111111100:1001100110011001100110011001100110011001100110011010
    

    Mantinin, 0011'un tekrarlayan rakamlarından oluştuğunu unutmayın. Bu, hesaplamalarda neden bir hata olmadığının anahtarıdır - 0,1, 0,2 ve 0,3, sonlu sayıdaki tam olarak ikili olarak gösterilemez 1/9, 1/3 veya 1/7'den büyük ikili bitler, ondalık basamaklarda tam olarak gösterilebilir.

    Üstelik üsdeki gücü 52 azaltabileceğimizi ve ikili gösterimdeki noktayı sağa 52 yer değiştirebileceğimize dikkat edin (10 -3 * 1.23 == 10 -5 * 123). Bu, ikili gösterimi a * 2 p biçiminde temsil ettiği tam değer olarak göstermemizi sağlar. 'a' tam sayı olduğu yerde.

    Üsleyicileri ondalık değere dönüştürme, ofseti kaldırma ve zımni 1'u (köşeli parantez içinde) yeniden ekleme, 0,1 ve 0,2 şunlardır:

     
    0.1 => 2^-4 * [1].1001100110011001100110011001100110011001100110011010
    0.2 => 2^-3 * [1].1001100110011001100110011001100110011001100110011010
    or
    0.1 => 2^-56 * 7205759403792794 = 0.1000000000000000055511151231257827021181583404541015625
    0.2 => 2^-55 * 7205759403792794 = 0.200000000000000011102230246251565404236316680908203125
    

    İki sayı eklemek için, üs, aynı olmalıdır, yani:

     
    0.1 => 2^-3 *  0.1100110011001100110011001100110011001100110011001101(0)
    0.2 => 2^-3 *  1.1001100110011001100110011001100110011001100110011010
    sum =  2^-3 * 10.0110011001100110011001100110011001100110011001100111
    or
    0.1 => 2^-55 * 3602879701896397  = 0.1000000000000000055511151231257827021181583404541015625
    0.2 => 2^-55 * 7205759403792794  = 0.200000000000000011102230246251565404236316680908203125
    sum =  2^-55 * 10808639105689191 = 0.3000000000000000166533453693773481063544750213623046875
    

    Toplam, 2 n * 1. biçiminde olmadığından, {bbb} üssünü birer birer artırır ve elde etmek için ondalık ( ikili ) noktasını değiştiririz:

     
    sum = 2^-2  * 1.0011001100110011001100110011001100110011001100110011(1)
        = 2^-54 * 5404319552844595.5 = 0.3000000000000000166533453693773481063544750213623046875
    

    Mantisede 53 bit vardır (53. satır yukarıdaki köşeli parantez içindedir). IEEE 754 için varsayılan yuvarlama modu varsayılandır: '- yani, x sayısı a ve b iki değerinin arasına düşerse, en az anlamlı bitin sıfır olduğu değer seçilen.

     
    a = 2^-54 * 5404319552844595 = 0.299999999999999988897769753748434595763683319091796875
      = 2^-2  * 1.0011001100110011001100110011001100110011001100110011
    
    x = 2^-2  * 1.0011001100110011001100110011001100110011001100110011(1)
    
    b = 2^-2  * 1.0011001100110011001100110011001100110011001100110100
      = 2^-54 * 5404319552844596 = 0.3000000000000000444089209850062616169452667236328125
    

    Note a ve b yalnızca son bit için farklılık gösterir; ...0011 + 1 = ...0100. Bu durumda, en az anlamlı biti olan değer b 'dir, bu nedenle toplam:

     
    sum = 2^-2  * 1.0011001100110011001100110011001100110011001100110100
        = 2^-54 * 5404319552844596 = 0.3000000000000000444089209850062616169452667236328125
    

    0.3’ün ikili gösterimi şöyledir:

     
    0.3 => 2^-2  * 1.0011001100110011001100110011001100110011001100110011
        =  2^-54 * 5404319552844595 = 0.299999999999999988897769753748434595763683319091796875
    

    yalnızca 0,1 ve 0,2 toplamının ikili temsilinden farklı olarak -54 .

    0.1 ve 0.2'nin ikili gösterimi, IEEE 754 tarafından izin verilen sayıların en doğru gösterimleridir. Bu gösterimin, varsayılan yuvarlama modu nedeniyle eklenmesi, yalnızca farklı olan bir değere yol açar. en az anlamlı bite.

    TL; DR

    0.1 + 0.2'u bir IEEE 754 ikili gösteriminde (üç parçayı ayıran iki nokta ile) yazma ve 0.3 ile karşılaştırarak, bu (farklı bitleri köşeli parantez içine koydum):

     
    0.1 + 0.2 => 0:01111111101:0011001100110011001100110011001100110011001100110[100]
    0.3       => 0:01111111101:0011001100110011001100110011001100110011001100110[011]
    

    Ondalık basamağa dönüştürülen bu değerler şunlardır:

     
    0.1 + 0.2 => 0.300000000000000044408920985006...
    0.3       => 0.299999999999999988897769753748...
    

    Aradaki fark tam olarak 2 -54 , bu da ~ 5.5511151231258 × 10 -17 - orijinal değerlerle karşılaştırıldığında önemsiz (birçok uygulama için).

    Kayan nokta sayısının son birkaç bitini karşılaştırmak, doğası gereği tehlikelidir, çünkü ünlüleri okuyan herkes " Her Bilgisayar Bilim İnsanının Kayan Nokta Aritmetiği Hakkında Bilmeniz Gerekenler " (bu cevabın tüm ana kısımlarını kapsayan) bilecektir.

    Çoğu hesap makinesi, bu sorunu gidermek için 0.1 + 0.2’un vereceği sorunla baş etmek için ek güvenlik basamakları kullanır. 0.3: son birkaç bit yuvarlandı.

        
    92
    2019-04-09 10: 25: 28Z
    1. Cevabım gönderdikten kısa bir süre sonra oy kullanıldı. O zamandan beri pek çok değişiklik yaptım (orijinalinde ihmal ettiğim ikili ve 0,1 ve 0,2 yazarken yinelenen bitlerin açıkça belirtilmesi dahil). Aşağı adayın bunu görme şansı olmadığında, cevabımı geliştirmem için bana biraz geri bildirim verebilir misiniz? IEEE 754'teki toplamın tedavisi diğer cevaplarda aynı şekilde ele alınmadığından cevabımın yeni bir şey eklediğini hissediyorum. "Her bilgisayar bilimcisinin bilmesi gerekenler ..." aynı materyali içeriyor olsa da, cevabım özellikle 0.1 + 0.2 durumuyla ilgileniyor.
      2015-02-24 07: 29: 45Z

    Bilgisayarda depolanan kayan nokta sayıları iki bölümden oluşur; bir tam sayı ve tabanın tam sayı parçası tarafından alındığı ve çarpıldığı bir üst öğedir.

    Bilgisayar 10 tabanında çalışıyorsa, 0.1 1 x 10⁻¹, 0.2 2 x 10⁻¹ ve 0.3 3 x 10⁻¹ olur. Tamsayılı matematik kolay ve kesindir, bu nedenle 0.1 + 0.2 eklenmesi açıkça 0.3 ile sonuçlanacaktır.

    Bilgisayarlar genellikle taban 10'da çalışmaz, taban 2'de çalışırlar. Örneğin, 0.5, 1 x 2⁻¹ ve 0.25, 1 x 2⁻², 3 x 2⁻² ve 0.75 veya 0.1'da sonuçları ekleyerek kesin sonuçlar alabilirsiniz. Kesinlikle.

    Sorun, tam olarak taban 10'da temsil edilebilecek, ancak taban 2'de gösterilemeyen sayılarla geliyor. Bu sayılar en yakın değerlerine yuvarlanmalıdır. Çok yaygın olan IEEE 64-bit kayan nokta biçimini varsayarsak, 3602879701896397 x 2⁻⁵⁵'a en yakın sayı 0.2'dur ve 7205759403792794 x 2⁻⁵⁵'a en yakın sayı 10808639105689191 x 2⁻⁵⁵'dur; Bunları bir araya getirmek 0.3000000000000000444089209850062616169452667236328125 veya kesin bir

    function add(a, b, precision) {
        var x = Math.pow(10, precision || 2);
        return (Math.round(a * x) + Math.round(b * x)) / x;
    }
    
    değerinde olur. Kayan nokta numaraları genellikle görüntüleme için yuvarlanır.     
    53
    2018-01-20 05: 00: 08Z
    1. @ Mark Bu açık açıklama için teşekkür ederiz, ancak daha sonra neden 0.1 + 0.4'ün Python 3'teki en az 0,5'e ulaştığını sorusu ortaya çıkar. Ayrıca, Python 3'teki floatları kullanırken eşitliği kontrol etmenin en iyi yolu nedir?
      2018-01-20 03: 15: 40Z
    2. @ user2417881 IEEE kayan nokta işlemlerinde her işlem için yuvarlama kuralları vardır ve bazen yuvarlama iki sayı az da olsa kapalı bir yanıt verebilir. Ayrıntılar bir yorum için çok uzun ve ben zaten bir konuda uzman değilim. Bu cevapta gördüğünüz gibi 0,5 iİkili olarak temsil edilebilecek birkaç ondalık sayıdan biridir, ancak bu sadece bir tesadüf. Eşitlik testi için, bkz. stackoverflow.com/questions/5595425/… .
      2018-01-20 04: 35: 35Z
    3. @ user2417881 sorunuzun ilgisini çekti, bu yüzden soruyu tam bir soruya ve cevaba çevirdim: stackoverflow.com/q/48374522/5987
      2018-01-22 04: 27: 16Z

    Kayan nokta yuvarlama hatası. Her Bilgisayar Bilimcisi Kayan Nokta Aritmetiği Hakkında Bilmeniz Gerekenler :

      

    Sonsuz sayıda gerçek sayının sınırlı sayıda bit halinde sıkıştırılması yaklaşık bir gösterim gerektirir. Sınırsız sayıda tam sayı olmasına rağmen, çoğu programda tam sayı hesaplamaları sonucu 32 bit olarak saklanabilir. Buna karşılık, herhangi bir sabit sayıda bit verildiğinde, gerçek sayılarla yapılan çoğu hesaplama, bu kadar çok bit kullanılarak tam olarak temsil edilemeyen miktarlar üretecektir. Bu nedenle, kayan nokta hesaplamasının sonucu, sonlu temsiline uyması için sıklıkla yuvarlatılmalıdır. Bu yuvarlama hatası, kayan nokta hesaplamasının karakteristik özelliğidir.

        
    44
    2017-12-27 00: 38: 28Z

    Geçici çözümüm:

     0.2

    hassasiyeti , ekleme sırasında ondalık basamağın ardından korumak istediğiniz basamak sayısını belirtir.

        
    31
    2011-12-26 06: 51: 53Z

    Çok sayıda iyi yanıt gönderildi, ancak bir tane daha eklemek istiyorum.

    Tüm sayılar yüzer / iki kat ile gösterilemez Örneğin, "0.2" sayısı, IEEE754 kayan nokta standardında tek bir hassasiyetle "0.200000003" olarak gösterilecektir.

    Kaputun altındaki gerçek sayıları saklamak için kullanılan model şamandıra numaralarını aşağıdaki gibi gösterir:

     buraya resim açıklamasını girin

    Kolayca FLT_RADIX yazabilseniz de, DBL_RADIX ve

    0.1 + 0.2 = 0.30000000000000004 (BIGGER)
    0.1 + 0.7 = 0.7999999999999999 (SMALLER)
    ...
    1.7 + 1.9 = 3.5999999999999996 (SMALLER)
    1.7 + 2.2 = 3.9000000000000004 (BIGGER)
    ...
    3.2 + 3.6 = 6.800000000000001 (BIGGER)
    3.2 + 4.4 = 7.6000000000000005 (BIGGER)
    
    2'dir; "İkili Kayan Noktalı Aritmetik için IEEE Standardı (ISO /IEEE Std 754-1985)" kullanan FPU'lu bir bilgisayar için 10 değil.

    Bu nedenle, bu sayıları tam olarak göstermek biraz zor. Bu değişkeni herhangi bir ara hesaplama olmadan açıkça belirtmiş olsanız bile.

        
    27
    2017-12-27 06: 59: 19Z

    Bu ünlü çifte hassasiyet sorusu ile ilgili bazı istatistikler.

    0,1 (0,1 ila 100 arası) adımını kullanarak tüm değerleri ( a + b ) eklerken, ~% 15 hassasiyet hatası şansımız var. Hatanın biraz daha büyük veya daha küçük değerlere yol açabileceğini unutmayın. İşte bazı örnekler:

     
    0.6 - 0.2 = 0.39999999999999997 (SMALLER)
    0.5 - 0.4 = 0.09999999999999998 (SMALLER)
    ...
    2.1 - 0.2 = 1.9000000000000001 (BIGGER)
    2.0 - 1.9 = 0.10000000000000009 (BIGGER)
    ...
    100 - 99.9 = 0.09999999999999432 (SMALLER)
    100 - 99.8 = 0.20000000000000284 (BIGGER)
    

    0,1 (100 - 0,1) adımını kullanarak tüm değerleri ( a - b burada a > b ) çıkarırken % 34’e sahibiz hassas hata yapma şansı . İşte bazı örnekler:

     nextafter()

    *% 15 ve% 34 gerçekten çok büyüktür, bu nedenle hassasiyet çok önemliyken daima BigDecimal kullanın. 2 ondalık basamakla (adım 0.01) durum biraz daha kötüleşir (% 18 ve% 36).

        
    26
    2017-08-04 08: 41: 25Z

    Hayır, kırılmadı, ancak ondalık bölümlerin çoğuna yaklaşılması gerekiyor

      

    Özet

    Kayan nokta aritmetiği kesindir kesindir, ne yazık ki, her zamanki temel-10 sayı gösterimimizle iyi bir şekilde eşleşmiyor, bu yüzden genellikle ne biz yazdık.

    0.01, 0.02, 0.03, 0.04 ... 0.24 gibi basit sayılar bile tam olarak ikili kesirler olarak gösterilemez. 0,01, 0,02, 0,02 ... sayıyorsanız, 0,25 'e ulaşana kadar değil, 2 üssünde temsil edilebilecek ilk kesimi elde edersiniz. FP kullanarak denemeyi denediyseniz, 0.01'iniz biraz kapalı olurdu, bu yüzden 25 tanesini güzel bir tam 0.25 değerine eklemenin tek yolu, koruyucu uçları ve yuvarlamayı içeren uzun bir nedensellik zincirini gerektiriyordu. Tahmin etmek zor, bu yüzden ellerimizi fırlatıp "FP tam olmayan" diyoruz, ama bu doğru değil.

    FP donanımına sürekli olarak 10. adımda basit görünen, ancak 2. adımda yinelenen bir kesir olan bir şey veriyoruz.

      

    Bu nasıl oldu?

    Ondalık yazdığımız zaman, her kesir (özellikle, her ondalık sonlandırıcı) , formun rasyonel bir sayısıdır

    a /(2 n x 5 m )

    İkili dosyada, yalnızca 2n terimini alırız, yani:

    a /2 n

    Yani, ondalık basamağa 1 / 3 'yi temsil edemeyiz. Temel 10, temel faktör olarak 2'yi içerdiğinden, ikili bir kesir olarak yazabileceğimiz her sayı ayrıca , temel 10 kesir olarak yazılabilir. Ancak, 10 taban kısmı olarak yazdığımız neredeyse hiçbir şey ikili olarak gösterilebilir. 0.01, 0.02, 0.03 ... 0.99 aralığında, sadece üç sayı FP formatımızda gösterilebilir: 0.25, 0.50 ve 0.75, çünkü 1/4, 1/2, ve 3/4, yalnızca 2 n terimini kullanan asal çarpanlı tüm sayılar.

    10 tabanında 1 / 3 'i temsil edemeyiz. Ancak ikili dosyada 1/10 veya 1 / 3 .

    Böylece her ikili kesir ondalık biçimde yazılabilirken, tersi doğru değildir. Ve aslında, ondalık kesirlerin çoğu ikili olarak tekrarlanır.

      

    Bununla ilgilenmek

    Geliştiricilere genellikle yapmaları söylenir. epsilon karşılaştırmalar, daha iyi tavsiye, integral değerlerine yuvarlama olabilir (C kütüphanesinde: round () ve roundf (), yani, FP biçiminde kalın) ve sonra karşılaştırın. Belirli bir ondalık kesir uzunluğuna yuvarlama, çıktıyla ilgili çoğu sorunu çözer.

    Ayrıca, gerçek sayıdaki-sıkışma problemlerinde (FP'nin erken, korkunç pahalı bilgisayarlarda icat ettiği sorunlar) evrenin fiziksel sabitleri ve diğer tüm ölçümler yalnızca nispeten az sayıda önemli rakamlarla bilinir. Tüm sorun alanı zaten "tam" idi. FP "kesinlik" bu tür uygulamalarda bir sorun değildir.

    Bütün mesele, insanlar fasulyenin sayımı için FP kullanmaya çalıştıklarında ortaya çıkar. Bunun için çalışır, ancak yalnızca integral değerlere sadık kalırsanız, hangi türden onu kullanma noktasını yitirirse. Bu yüzden tüm bu ondalık kesir yazılımı kütüphanelerine sahibiz.

    Pizza'nın cevabını Chris ile seviyorum, çünkü her zamanki sorunu değil, asıl sorunu açıklıyor "yanlışlık" hakkında el yıkama. Eğer FP basitçe "yanlış" olsaydı, bunu onarabilirdik ve on yıl önce yapabilirdik. Yapmamamızın nedeni, FP formatının kompakt ve hızlı olması ve çok sayıda rakamı sıkıştırmanın en iyi yoludur. Ayrıca, uzay çağı ve silahlanma yarışının bir mirası ve küçük bellek sistemlerini kullanan çok yavaş bilgisayarlarla büyük sorunları çözme girişimlerinin erken. (Bazen, 1 bitlik depolama için bireysel manyetik çekirdekler , ancak bu başka bir hikayesi. )

      

    Sonuç

    Sadece bir bankadaki fasulye sayıyorsanız, ilk olarak ondalık basamaklı gösterimler kullanan yazılım çözümleri mükemmel şekilde çalışır. Ancak kuantum kromodinamik veya aerodinamiği bu şekilde yapamazsınız.

        
    24
    2018-10-10 22: 43: 27Z
    1. En yakın tamsayıya yuvarlama, her durumda karşılaştırma sorununu çözmek için güvenli bir yol değildir. 0,4999998 ve 0,500001, farklı tam sayılara göre, bu nedenle her yuvarlama noktasında "tehlike bölgesi" var. (Bu onayı biliyoruml dizeleri muhtemelen IEEE ikili kayan noktalarında tam olarak gösterilemez.)
      2016-12-09 03: 31: 33Z
    2. Ayrıca, kayan nokta bir "eski" biçim olsa da, çok iyi tasarlanmış. Şimdi yeniden tasarlarsa kimsenin değiştireceği bir şey bilmiyorum. Ne kadar çok şey öğrenirsem, o kadar çok tasarlandığını düşünüyorum. Örneğin. önyargılı üs, ardışık ikili şamandıraların ardışık tam sayı gösterimlerine sahip olduğu anlamına gelir, böylece
       if( (n * 0.1) < 100.0 ) { return n * 0.1 - 0.000000000000001 ;}
                          else { return n * 0.1 + 0.000000000000001 ;}    
      
      'u bir IEEE şamandırasının ikili gösterimi üzerinde bir tamsayı artışı veya azalması ile uygulayabilirsiniz. Ayrıca, kayan noktaları tamsayı olarak karşılaştırabilir ve her ikisi de negatif olmadıkça doğru işareti alabilirsiniz (işaret büyüklüğü - 2'nin tamamlayıcısı nedeniyle).
      2016-12-09 03: 35: 01Z
    3. Buna katılmıyorum, kayanlar ondalık sayı olarak depolanmalı ve ikili değil saklanmalı ve tüm sorunlar çözüldü.
      2017-02-19 19: 32: 15Z
    4. Olmamalı " x /(2 ^ n + 5 ^ n) " olmamalı " x /(2 ^ n * 5 ^ n) "?
      2018-02-05 07: 34: 25Z
    5. @ RonenFestinger - peki 1/3?
      2018-08-15 03: 32: 39Z

    Koli bandı çözümünü denedin mi?

    Hataların ne zaman ortaya çıktığını belirlemeye çalışın ve ifadeler kısasa bunları düzeltin, sorun değil ama bazı sorunlarda bu tek çözüm ve bu da onlardan biri.

     float

    Aynı sorunu c # 'daki bir bilimsel simülasyon projesinde de yaşadım ve kelebek etkisini görmezden gelirseniz büyük şişman bir ejderhaya dönüşeceğini ve sizi a ısırdığını söyleyebilirim.     

    18
    2013-06-19 18: 50: 36Z

    Bu garip sayılar, bilgisayarların hesaplama amacıyla ikili (temel 2) sayı sistemini kullanması nedeniyle görünürken, ondalık (10 numaralı taban) kullanıyoruz.

    Tam olarak ikili veya ondalık ya da her ikisinde de temsil edilemeyen kesirli sayıların çoğu vardır. Sonuç - Yuvarlanmış (ancak kesin) bir sayı sonuçları.

        
    15
    2013-10-14 16: 45: 17Z
    1. İkinci paragrafınızı hiç anlamıyorum.
      2017-12-27 00: 19: 54Z
    2. @ Nae İkinci paragrafı "Kesirlerin çoğunluğu tam olarak ya da ikili dosyasında gösterilemez." yuvarlatılmak - her ne kadar kullanılmakta olan gösterimde doğal olan bit /hane sayısına kesin olarak baksalar da. "
      2018-03-09 14: 19: 58Z

    Bu sorunun çok sayıda kopyası, kayan nokta yuvarlamanın belirli sayılar üzerindeki etkilerini soruyor. Uygulamada, sadece okumaktan ziyade, ilgi hesaplamalarının kesin sonuçlarına bakarak nasıl çalıştığını hissetmek daha kolaydır. Bazı diller bunu yapmanın yollarını sağlar - örneğin double veya BigDecimal’u Java’da (1/3+1/3=2/3)=true’a dönüştürme gibi.

    Bu dille ilgili bir soru olduğu için, gibi bir dille ilgili soruyu yanıtlaması gerekir. Kayan Nokta Dönüştürücüsüne Ondalık .

    Soruyu, sayı olarak kabul etmek, iki katına çıkarmak:

    0.1, 0.100000000000000000055511151231257827021181583404541015625’e dönüştürülür

    0.2, 0.200000000000000000011102230246251565404236316680908203125’e dönüştürülüyor

    0.3, 0.29999999999999998889776975374843459576368331909179687’ye dönüştürülür5 ve

    0.30000000000000004, 0.300000000000000000000444089209850062616169452667236328125’e dönüştürülür.

    İlk iki numarayı manuel olarak veya Tam Hassasiyetli Hesap Makinesi gibi bir ondalık hesaplayıcıya ekleme , gerçek girişlerin tam toplamını 0.30000000000000000000166533453693773481063544750213623046875’tir.

    Eğer 0.3 değerine yuvarlanırsa, yuvarlama hatası 0.0000000000000000277555756156289135105907917022705078125 olur. 0.30000000000000004 değerine kadar yuvarlama işlemi ayrıca 0.0000000000000000277955756156289135105907917022705078125 numaralı yuvarlama hatasını da verir. Yuvarlak-çift bağlantı kesici uygulanır.

    Kayan nokta dönüştürücüsüne geri dönüldüğünde, 0.3000000000000000004 için ham onaltılık, 3fd333333333333334'tür, bu da düz bir rakamla bitir ve bu nedenle doğru sonuçtur.

        
    13
    2017-11-22 16: 18: 30Z
    1. Düzenlemesini az önce geri aldığım kişiye: Kod kotasyonuna uygun kod tırnaklarını düşünüyorum. Dil açısından tarafsız olan bu cevap, hiçbir alıntı kodu içermiyor. Rakamlar İngilizce cümlelerde kullanılabilir ve bu kod içine dönüştürülmez.
      2017-11-22 16: 22: 08Z
    2. Bu olasıdır neden birileri numaralarınızı kod olarak biçimlendirdi - biçimlendirme için değil, okunabilirlik için.
      2018-01-12 18: 24: 54Z
    3. ... ayrıca, çifte eşit , ikili temsiline, değil ondalık gösterimi. bunu veya örneğin, this .
      2018-01-12 19: 33: 27Z

    Sadece ekleyebilir miyim; insanlar her zaman bunun bir bilgisayar sorunu olduğunu varsayarlar, ancak ellerinizle sayılırsanız (10 üssü), (1/10+2/10)!==3/10 sorununda olduğu gibi 0.333 ... ila 0.333 ... eklemek için sonsuzluğunuz olmadığı sürece

    parseFloat((0.1 + 0.2).toFixed(10)) => Will return 0.3
    
    elde edemezsiniz. üs 2'de, 0.333 + 0.333 = 0.666'ya kısaltırsınız ve muhtemelen teknik olarak yanlış olan 0.667'ye yuvarlarsınız.

    Üçlü olarak sayın ve üçte bir sorun olsa da sorun değil - belki her bir yandan 15 parmağınızla yarışmak, ondalık matematiğinizin neden kırıldığını sorabilir ...

        
    13
    2018-03-26 22: 00: 40Z
    1. İnsanlar ondalık sayılar kullandığından, kayan noktaların varsayılan olarak ondalık sayı olarak gösterilmemesinin iyi bir nedeni olmadığını görüyorum, bu nedenle doğru sonuçlara sahibiz.
      2017-02-19 19: 27: 48Z
    2. İnsanlar temel 10 (ondalık) dışında birçok taban kullanır, ikili hesaplama için en çok kullandığımız ikilidir. 'iyi bir sebep' her şeyi temsil edememenizdir her kaidede kesir ..
      2017-02-20 08: 59: 52Z
    3. @ RonenFestinger ikili aritmetik, bilgisayarlarda uygulamak kolaydır çünkü basamaklarla yalnızca sekiz temel işlem gerektirir: $a $, $b1 $0,1 $$'a hepiniz bilmeniz gereken $$operatorname {xor} (a, b) $ve $\operatorname {cb} (a, b) $, burada xor özeldir ve cb ise tüm durumlarda $0 $olan "carry biti" dir. $a = 1 = b $hariç, bu durumda bizde bir tane var (gerçekte tüm işlemlerin değişebilirliği size 2 $'lık tasarruf sağlıyor ve tek ihtiyacınız olan $6 $kuralları. Ondalık genişletme, her bit için 10 ABD Doları, 11 ABD Doları (onlu gösterimde) kasa ve her 10 ABD Doları için 10 ABD doları farklı durum gerektirir ve taşımadaki boşa harcar.
      2018-03-25 06: 36: 05Z

    En iyi çözümü sunmak için Aşağıdaki yöntemi keşfettiğimi söyleyebilirim:

     0.2

    Neden en iyi çözüm olduğunu açıklayayım. Yukarıda verilen diğer cevaplarda da belirtildiği gibi, sorunu çözmek için Javascript toFixed () işlevini kullanmaya hazır kullanmak iyi bir fikirdir. Ancak büyük olasılıkla bazı sorunlarla karşılaşırsınız.

    0.7 ve 0.2 + 0.7 = 0.8999999999999999 gibi iki değişken sayı ekleyeceğinizi hayal edin: 0.9.

    Beklediğiniz sonuç (0.2 + 0.7).tofixed(1)'du, bu durumda 1 basamaklı hassasiyetle bir sonuca ihtiyacınız var demektir. Yani

    `0.22 + 0.7 = 0.9199999999999999`
    
    kullanmalıydın ancak verilen sayıya bağlı olduğundan toFixed () işlevine belirli bir parametre veremezsiniz, örneğin  toFixed(2)

    Bu örnekte 2 basamak hassasiyetine ihtiyacınız vardır, bu yüzden

    (0.2 + 0.7).toFixed(10) => Result will be "0.9000000000"
    
    olmalıdır, bu nedenle verilen her bir şamandıra numarasına uyması gereken paragraf ne olmalıdır?

    Daha sonra her durumda 10 olmasına izin verebilirsiniz:

     
    parseFloat((0.2 + 0.7).toFixed(10)) => Result will be 0.9
    

    batsın 9'dan sonra bu istenmeyen sıfırlarla ne yapacaksın? İstediğiniz gibi yapmak için yüzmeye çevirme zamanı:

     
    function floatify(number){
               return parseFloat((number).toFixed(10));
            }
    

    Artık çözümü bulduğunuza göre, bunun gibi bir işlev olarak önermek daha iyidir:

     
    function floatify(number){
           return parseFloat((number).toFixed(10));
        }
     
    function addUp(){
      var number1 = +$("#number1").val();
      var number2 = +$("#number2").val();
      var unexpectedResult = number1 + number2;
      var expectedResult = floatify(number1 + number2);
      $("#unexpectedResult").text(unexpectedResult);
      $("#expectedResult").text(expectedResult);
    }
    addUp();
    input{
      width: 50px;
    }
    #expectedResult{
    color: green;
    }
    #unexpectedResult{
    color: red;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <input id="number1" value="0.2" onclick="addUp()" onkeyup="addUp()"/> +
    <input id="number2" value="0.7" onclick="addUp()" onkeyup="addUp()"/> =
    <p>Expected Result: <span id="expectedResult"></span></p>
    <p>Unexpected Result: <span id="unexpectedResult"></span></p>

    Kendin deneyelim:

     
    var x = 0.2 + 0.7;
    floatify(x);  => Result: 0.9
    

    Bunu şu şekilde kullanabilirsiniz:

     
    var x = (0.2 * 10 + 0.1 * 10) / 10;       // x will be 0.3
    

    W3SCHOOLS 'un önerdiği gibi, başka bir çözüm önerisi var; yukarıdaki sorun:

     (0.2 + 0.1) * 10 / 10

    decimal'un aynı görünse de hiç çalışmadığını unutmayın! İlk çözümü tercih ediyorum, çünkü girdi akışını doğru çıkış akışına dönüştüren bir fonksiyon olarak uygulayabiliyorum.

        
    13
    2018-10-13 08: 27: 16Z

    Bundan kimsenin bahsetmediği düşünülürse ...

    Python ve Java gibi bazı yüksek seviyeli diller, ikili kayan nokta sınırlamalarının üstesinden gelmek için araçlar ile birlikte gelir. Örneğin:

    Bu çözümlerin hiçbiri mükemmel değil (özellikle performanslara bakarsak veya çok yüksek bir hassasiyete ihtiyacımız varsa), ancak yine de ikili kayan nokta aritmetiğiyle ilgili çok sayıda sorunu çözüyorlar.

        
    12
    2015-08-21 15: 03: 35Z

    Dijital bir bilgisayarda uygulanabilecek kayan nokta matematiği, mutlaka üzerlerindeki gerçek sayıların ve işlemlerin bir yaklaşımını kullanır. ( standart sürüm, elli sayfanın üzerinde belgeye kadar uzanır ve hatalı bir şekilde ve daha fazla ayrıntılandırma ile ilgilenecek bir komitesi vardır.)

    Bu yaklaşım, her biri kesinliğinden sapma özelliğine bağlı olarak ya ihmal edilebilecek ya da dikkatle hesaplanabilecek farklı türde yaklaşımların bir karışımıdır. Aynı zamanda, çoğu insanın dikkatini çekmemiş gibi davranırken hem geçmiş hem de donanım düzeyinde hem de hem de farketmemiş gibi davranan bazı istisnai durumları içerir.

    Sonsuz hassasiyete ihtiyacınız varsa (örneğin, daha kısa stand-up'lardan biri yerine π sayısını kullanarak), sembolik bir matematik programı yazmalı veya kullanmalısınız.Öyleyim.

    Ancak bazen kayan noktalı matematiğin değer ve mantık açısından bulanık olduğu ve hataların hızlı bir şekilde birikebileceği ve bunun için izin vermek için gereksinimlerinizi ve testlerinizi yazabileceğiniz fikriniz varsa, kodunuz sıkça FPU’nuzda olanlarla.

        
    9
    2016-07-03 07: 45: 02Z

    Sadece eğlence için, C99 Standardındaki tanımları takip ederek float'lerin temsili ile oynadım ve aşağıdaki kodu yazdım.

    Kod, yüzen grupların ikili temsilini 3 ayrı grupta yazdırır

     float x = 999...

    ve bundan sonra, yeterince hassas bir şekilde toplandığında, gerçekten donanımda var olan değeri göstereceği bir toplamı yazdırır.

    Böylece, xx yazdığınızda, derleyici, bu sayıyı, işlev yy tarafından basılan bit gösteriminde, işlev

    #include <stdio.h>
    #include <limits.h>
    
    void
    xx(float *x)
    {
        unsigned char i = sizeof(*x)*CHAR_BIT-1;
        do {
            switch (i) {
            case 31:
                 printf("sign:");
                 break;
            case 30:
                 printf("exponent:");
                 break;
            case 23:
                 printf("fraction:");
                 break;
    
            }
            char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
            printf("%d ", b);
        } while (i--);
        printf("\n");
    }
    
    void
    yy(float a)
    {
        int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
        int fraction = ((1<<23)-1)&(*(int*)&a);
        int exponent = (255&((*(int*)&a)>>23))-127;
    
        printf(sign?"positive" " ( 1+":"negative" " ( 1+");
        unsigned int i = 1<<22;
        unsigned int j = 1;
        do {
            char b=(fraction&i)!=0;
            b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
        } while (j++, i>>=1);
    
        printf("*2^%d", exponent);
        printf("\n");
    }
    
    void
    main()
    {
        float x=-3.14;
        float y=999999999;
        printf("%lu\n", sizeof(x));
        xx(&x);
        xx(&y);
        yy(x);
        yy(y);
    }
    
    tarafından yazdırılan toplamın verilen sayıya eşit olacağı şekilde dönüştürür.

    Gerçekte, bu toplam sadece bir yaklaşımdır. 999,999,999 sayısı için derleyici, şamandıranın bit gösterimini 1.000.000.000 sayısını gösterecek.

    Koddan sonra, donanımda gerçekten var olan her iki sabit için (eksi PI ve 999999999) terimlerin toplamını hesapladığım bir konsol oturumu ekliyorum.

     bc

    Burada, şamandıranın donanımdaki gerçek değerini hesapladığım bir konsol oturumu var. Ana program tarafından çıkarılan terimlerin toplamını yazdırmak için repl kullandım. Biri bu toplamı python

    -- .../terra1/stub
    @ qemacs f.c
    -- .../terra1/stub
    @ gcc f.c
    -- .../terra1/stub
    @ ./a.out
    sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
    sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
    negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
    positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
    -- .../terra1/stub
    @ bc
    scale=15
    ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
    999999999.999999446351872
    
    'a veya benzer bir şeye ekleyebilir.  
    999999999.999999446351872
    

    İşte bu. 999999999’un değeri aslında

     bc

    Ayrıca scale ile -3.14'ün de bozulduğunu kontrol edebilirsiniz. bc’da scale faktörü ayarlamayı unutmayın.

    Görüntülenen toplam, donanımın içindekilerdir. Hesaplayarak elde ettiğiniz değer, ayarladığınız ölçeğe bağlıdır.

    1/3 + 2 / 3 == 1
    
    faktörünü 15 olarak belirledim. Matematiksel olarak, sonsuz hassasiyetle, 1.000.000.000 gibi görünüyor.     
    8
    2017-12-27 02: 00: 04Z

    Buna bakmanın başka bir yolu: Sayıları temsil etmek için kullanılan 64 bit. Sonuç olarak, 2 ** 64 = 18,446,744,073,709,551,616'dan daha fazla bir yol yoktur, farklı sayılar kesin olarak gösterilebilir.

    Ancak, Math zaten 0 ve 1 arasında sonsuz sayıda ondalık sayı olduğunu söylüyor. IEE 754, bu 64 bitin çok daha büyük bir sayı alanı ve NaN ve +/- Infinity için verimli bir şekilde kullanılması için bir kodlama tanımlıyor, bu nedenle tam olarak gösterilen boşluklar var sadece yaklaşık sayılarla dolu sayılar.

    Maalesef 0.3 bir boşlukta oturuyor.

        
    5
    2017-12-19 22: 48: 08Z

    Bu iş parçacığı, geçerli kayan nokta uygulamaları hakkında genel bir tartışmaya biraz dal attığından, sorunlarının giderilmesi için projeler olduğunu eklerdim.

    Örneğin, pozit adlı bir sayı türünü gösteren https://posithub.org/ bir göz atın (ve önceki sürüm) daha az bit ile daha iyi doğruluk sunmayı vaat ediyor. Anlayışım doğruysa, sorudaki problemleri de düzeltir. Oldukça ilginç bir proje, arkasındaki kişi bir matematikçi. Dr. John Gustafson . Her şey açık kaynaktır, C /C ++, Python, Julia ve C # ile birçok gerçek uygulama vardır ( https: //hastlayer). com /aritmetiği) .

        
    4
    2018-04-12 17: 26: 20Z

    Onuncu tabanda çalıştığını, yani, 8 basamak doğrulukla çalıştığınızı düşünün. Siz kontrol edin

     false

    ve bunun

    0.33333333 + 0.66666666 = 0.99999999
    
    döndürdüğünü öğrenin. Niye ya? Eh, gerçek sayılar olarak

    1/3 = 0.333 .... ve 2/3 =0.666 ....

    Sekiz ondalık basamakta kesiliyor, alıyoruz

     1.00000000

    elbette, 0.00000001’dan

    0.0001100 + 0.0011001 = 0.0100101
    
    ’a kadar farklı.

    Sabit sayıda bit içeren ikili sayıların durumu tamamen benzerdir. Gerçek sayılar olarak, biz

    1/10 = 0.0001100110011001100 ... (temel 2)

    ve

    1/5 = 0.0011001100110011001 ... (temel 2)

    Bunları yedi bit olarak kesersek, o zaman alırız

     0.0100110

    diğer yandan,

    3/10 = 0.01001100110011 ... (temel 2)

    yedi bitlik değere bölünür ve 0.0000001'dur ve bunlar tam olarak 0.0001100'dur.


    Kesin durum biraz daha belirsizdir, çünkü bu sayılar tipik olarak bilimsel gösterimde saklanır. Örneğin, 1/10'u 1.10011 * 2^-4 olarak depolamak yerine, üs ve mantis için kaç bit ayırdığımıza bağlı olarak, onu math.isclose() gibi bir şey olarak depolayabiliriz. Bu, hesaplamalarınız için kaç hassasiyet hanesini aldığınızı etkiler.

    Sonuç olarak, bu yuvarlama hataları nedeniyle, temelde hiçbir zaman == kayan nokta sayıları kullanmak istemezsiniz. Bunun yerine, farklarının mutlak değerinin bazı sabit küçük sayılardan daha küçük olup olmadığını kontrol edebilirsiniz.

        
    3
    2018-12-20 18: 27: 35Z

    Python 3.5'ten beri , yaklaşık eşitliği test etmek için

    >>> import math
    >>> math.isclose(0.1 + 0.2, 0.3)
    True
    >>> 0.1 + 0.2 == 0.3
    False
    
    işlevini kullanabilirsiniz :  
    .1 + .0001 + -.1 --> 0.00010000000000000286
    Math.sum(.1 , .0001, -.1) --> 0.0001
    
        
    3
    2019-02-26 22: 12: 40Z

    Math.sum (javascript) .... operatör değiştirme türü

     
    Object.defineProperties(Math, {
        sign: {
            value: function (x) {
                return x ? x < 0 ? -1 : 1 : 0;
                }
            },
        precision: {
            value: function (value, precision, type) {
                var v = parseFloat(value), 
                    p = Math.max(precision, 0) || 0, 
                    t = type || 'round';
                return (Math[t](v * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
            }
        },
        scientific_to_num: {  // this is from https://gist.github.com/jiggzson
            value: function (num) {
                //if the number is in scientific notation remove it
                if (/e/i.test(num)) {
                    var zero = '0',
                            parts = String(num).toLowerCase().split('e'), //split into coeff and exponent
                            e = parts.pop(), //store the exponential part
                            l = Math.abs(e), //get the number of zeros
                            sign = e / l,
                            coeff_array = parts[0].split('.');
                    if (sign === -1) {
                        num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');
                    } else {
                        var dec = coeff_array[1];
                        if (dec)
                            l = l - dec.length;
                        num = coeff_array.join('') + new Array(l + 1).join(zero);
                    }
                }
                return num;
             }
         }
        get_precision: {
            value: function (number) {
                var arr = Math.scientific_to_num((number + "")).split(".");
                return arr[1] ? arr[1].length : 0;
            }
        },
        diff:{
            value: function(A,B){
                var prec = this.max(this.get_precision(A),this.get_precision(B));
                return +this.precision(A-B,prec);
            }
        },
        sum: {
            value: function () {
                var prec = 0, sum = 0;
                for (var i = 0; i < arguments.length; i++) {
                    prec = this.max(prec, this.get_precision(arguments[i]));
                    sum += +arguments[i]; // force float to convert strings to number
                }
                return Math.precision(sum, prec);
            }
        }
    });
    

     
    Math.diff(0.2, 0.11) == 0.09 // true
    0.2 - 0.11 == 0.09 // false
    

    fikir, float hatalarını önlemek için operatör yerine Math kullanmaktır.

     cout << x

    ayrıca Math.diff ve Math.sum öğelerinin kullanım hassasiyetini otomatik olarak algıladığını unutmayın.

    Math.sum herhangi bir sayıda bağımsız değişkeni kabul eder

        
    2
    2018-04-21 12: 13: 46Z

    Farklı bir soru, bunun kopyası olarak adlandırıldı:

    C ++ 'da neden x'un sonucu bir hata ayıklayıcısının x için gösterdiği değerden farklı??

    Sorudaki float,

    float x = 9.9F;
    
    değişkenidir.

    Bir örnek olacaktır

     9.89999962

    Hata ayıklayıcı cout’u gösterir, 9.9 işleminin çıktısı cout’dur.

    Yanıt, float’un 10^-8/1000’un varsayılan kesinliği 6’dır, bu nedenle 6 ondalık basamağa yuvarlanır.

    başvuru için burayı inceleyin

        
    2
    2018-06-15 13: 26: 07Z
      

    Aslında oldukça basit. 10 taban sistemine sahipseniz (bizimki gibi), sadece bazın temel faktörünü kullanan kesirleri ifade edebilir. 10'luk ana faktörler 2 ve 5'tir. Yani 1/2, 1/4, 1/5, 1/8 ve 1/10 hepsi temiz bir şekilde ifade edilebilir, çünkü paydaların hepsi 10'un temel faktörlerini kullanır. Bunun aksine, 1 /3, 1/6 ve 1/7 hepsi tekrar eden değerlerdir, çünkü paydaları 3 ya da 7'lik bir asal çarpan kullanır. İkili (ya da baz 2) 'de, tek asal çarpan 2'dir. sadece ana faktör olarak 2 tane içerir. İkili olarak, 1/2, 1/4, 1/8, hepsi ondalık olarak temiz bir şekilde ifade edilir. 1/5 veya 1/10 ise ondalık sayıları tekrar ediyor olabilir. Yani 10 ve 0.2 (1/10 ve 1/5) taban 10 sistemindeki temiz ondalık sayıları kullanırken, taban 2 sistemindeki ondalık sayıları bilgisayar çalıştırır. Bilgisayarın çalıştığı taban 2 sistemindeki ondalık sayıları yineler. Bu, bilgisayarın 2 numaralı (ikili) sayısını, daha okunaklı bir 10 numaralı sayıya dönüştürdüğünüzde devam eder.

    https://0.30000000000000004.com/

    adresinden     
    2
    2019-05-07 20: 34: 37Z

    Bu, aslında bu sorunun yanıtı olarak tasarlandı. güçlü> bu soru, iken Bu cevabı bir araya getiriyordum, bu yüzden şimdi orada gönderemiyorum ... bu yüzden buraya göndereceğim!


      

    Soru özeti:

         

    10^-11 ve Number çalışma sayfasında, VBA'da yokken Eşit olarak değerlendirilir.

    Çalışma sayfasında, sayılar varsayılan olarak Scientific Notation (Bilimsel Notasyon) olarak ayarlanmıştır.

    Hücreleri, 15 ondalık sayı ile

    =10^-11 returns 0.000000000010000
    =10^(-8/1000) returns 0.981747943019984
    
    sayı biçiminde ( Ctrl + 1 ) değiştirirseniz, şunları elde edersiniz:  123.34

    Böylece, kesinlikle aynı değillerdir ... biri hemen hemen sıfır, diğeri de yaklaşık 1.

    Excel, son derece küçük sayılarla başa çıkmak için tasarlanmamıştır - en azından stok yüklemesiyle. Sayı hassasiyetini artırmaya yardımcı olacak eklentiler var.


      

    Excel, İkili Kayan Nokta Aritmetiği için IEEE Standardına uygun olarak tasarlanmıştır ( IEEE 754 ) . Standart, kayan nokta sayılarının nasıl saklandığını ve hesaplandığını tanımlar. Kayan nokta sayılarının makul bir miktarda depolanmasına izin verdiği için IEEE 754 standardı yaygın olarak kullanılmaktadır. boşluk ve hesaplamalar nispeten hızlı bir şekilde gerçekleşebilir.

         

    Sabit nokta sunumunda kayan avantaj, daha geniş bir değer aralığını destekleyebilmesidir. Örneğin, üçüncü basamaktan sonra konumlandırılan ondalık basamakla 5 ondalık basamağa sahip bir sabit nokta gösterimi, 12.23, 2.45, POWER, vb. Sayıları temsil ederken, 5 basamaklı kesinlikli kayan nokta gösterimi 1.2345, 12345, 0.00012345'i temsil edebilir. Benzer şekilde, kayan nokta gösterimi aynı zamanda hassasiyeti korurken geniş bir büyüklük aralığında hesaplamalara da izin verir. Örneğin,

    img


    Diğer Referanslar:

    1
    2018-10-02 03: 42: 06Z

    0.2, 0.3 ve 0.1 gibi ondalık kesirler, tam olarak ikili kodlanmış kayan nokta türlerinde gösterilmez. 0.2 ve 0.3 için yaklaşımların toplamı, 0.1 + 0.2 == 0.3 için kullanılan yaklaşımdan farklıdır; bu nedenle, burada daha net olarak görüldüğü gibi,

    #include <stdio.h>
    
    int main() {
        printf("0.1 + 0.2 == 0.3 is %s\n", 0.1 + 0.2 == 0.3 ? "true" : "false");
        printf("0.1 is %.23f\n", 0.1);
        printf("0.2 is %.23f\n", 0.2);
        printf("0.1 + 0.2 is %.23f\n", 0.1 + 0.2);
        printf("0.3 is %.23f\n", 0.3);
        printf("0.3 - (0.1 + 0.2) is %g\n", 0.3 - (0.1 + 0.2));
        return 0;
    }
    
    ’un yanlışlığı:  
    0.1 + 0.2 == 0.3 is false
    0.1 is 0.10000000000000000555112
    0.2 is 0.20000000000000001110223
    0.1 + 0.2 is 0.30000000000000004440892
    0.3 is 0.29999999999999998889777
    0.3 - (0.1 + 0.2) is -5.55112e-17
    

    Çıktı:

     _Decimal32

    Bu hesaplamaların daha güvenilir bir şekilde değerlendirilmesi için, kayan nokta değerleri için ondalık tabanlı bir gösterim kullanmanız gerekir. C Standardı varsayılan olarak bu türleri belirtmez, ancak

kaynak yerleştirildi İşte