Kayan nokta sayılarının çözünürlüğü neden başlangıç ​​noktasından daha fazla azalıyor?


19

OpenGL sahnemde, başlangıçtan gülünç derecede uzak mesafelere yerleştirilmiş nesneler var. Bu nesneleri gördüğümde ve etraflarında bir kamera kaydırdığımda / döndürdüğümde / yakınlaştırdığımda, 'titriyor'. Yani, nesneleri içeren köşeler, hayali bir 3B nokta ızgarasının etrafına yapışmış gibi görünmektedir. Bu kayan nokta hassasiyeti (hangi OpenGL ve hemen hemen her şey kullanır) kullanılarak saklanabilir bilgi miktarı nedeniyle bu yaygın bir sorun okudum. Bunun neden olduğunu anlamıyorum .

Bir çözüm ararken, çok basit 'kayan kökenli' düzeltmeye rastladım ve işe yarıyor gibi görünüyor. Her şeyi dönüştürüyorum, böylece nesnelerim aynı göreli konumlarda olacak, ancak kameranın baktığı her şey başlangıç ​​noktasına yakın. Burada bir açıklama buldum: http://floatingorigin.com/ , ancak takip edemedim.

Öyleyse ... Birisi sahnemi neden başlangıçtan çok uzakta konumlandırdığımı (10 milyon ünite) neden gözlemlediğim düzensiz davranışa neden olduğunu açıklayabilir mi? Ayrıca neden kaynağa yaklaşmak sorunu çözüyor?


4
Çünkü olmasaydı, sabit nokta sayıları olurdu . Tatolojik soru, bu.
MSalters

1
Doğru, ama sadece 'kayan nokta' nın gerçekten ne anlama geldiğini anladığınızda.
Kylotan

Yanıtlar:


26

Kayan noktaların bilgisayarlarda temsil edilme şekli nedeniyle bu TÜMÜdür.

Tamsayılar oldukça basit bir şekilde saklanır; her birim tıpkı sayılabilir sayılardan beklediğiniz gibi "önceki" nin tam olarak "bir" dir.

Kayan nokta sayıları ile durum tam olarak böyle değildir. Bunun yerine, birkaç bit EXPONENT'i, geri kalan kısım ise mantis veya fraksiyonel kısım olarak bilinen şeyi belirtir ve daha sonra nihai sonuç vermek için üs parçası tarafından (dolaylı olarak 2 ^ exp) ÇOKLU olur.

Bitlerin görsel bir açıklaması için buraya bakın .

Tam olarak bu üs bitlerin gerçek bir parçası olması nedeniyle sayılar büyüdükçe hassasiyet WANE'ye başlar.

Bunu çalışırken görmek için, nitrit-cesarete girmeden sahte bir kayan nokta temsili yapalım: 2 gibi küçük bir üs alın ve test etmek için bazı kesirli parçalar yapalım:

2 * 2 ^ 2 = 8

3 * 2 ^ 2 = 12

4 * 2 ^ 2 = 16

...vb.

Bu sayılar sadece üs 2'de çok fazla büyümez. Ama şimdi üs 38'i deneyelim:

2 * 2 ^ 38 = 549755813888

3 * 2 ^ 38 = 824633720832

4 * 2 ^ 38 = 1099511627776

Vay, şimdi çok büyük fark!

Örnek, özellikle ÇOK SONRAKİ SAYABİLİR'e (bunun kaç bit olduğuna bağlı olarak bir sonraki kesirli kısım olacaktır) gitmese de, sayılar büyüdükçe hassas kaybı göstermek için vardır. Şamandıralardaki "bir sonraki sayılabilir" birim, küçük üslerle çok küçük ve daha büyük üslerle ÇOK büyüktür, oysa tamsayılarda DAİMA 1'dir.

Şamandıra orijini yönteminin çalışmasının nedeni, bu "büyük sayılabilenler" (kesinlik) çok küçük ve mutlu olabilmesi için potansiyel olarak büyük üslü kayan nokta sayılarını küçük üsse doğru ölçeklendirmesidir.


Verdiğiniz örnekler gerçekten açıklayıcıydı, teşekkürler :)
Pris

3
Doğru yolda, ama keşke kayan noktanın gerçekten işleyişine daha yakın örnekler kullanmış olsaydınız. Mantisayı üsse yükseltmez; mantis * 2 ^ üs.
Nathan Reed

3
Haklısın, biliyordum; Ne düşündüğümü bilmiyorum. Cevabımı düzenledi.

1
@ScottW Güzel düzenleme! +1
Nathan Reed

17

Kayan nokta sayıları kesir + üs + işareti olarak temsil edildiğinden ve kesir kısmı için yalnızca sabit miktarda bitiniz vardır.

http://en.wikipedia.org/wiki/Single_precision

Daha büyük ve daha büyük sayılar aldıkça, sadece daha küçük bölümleri temsil eden bitlere sahip değilsiniz.


8

Alandaki klasik yetiştirilmelidir: Her bilgisayar bilim insanının kayan nokta sayıları hakkında bilmesi gerekenler .

Ancak bunun özü, tek (çift) hassas kayan nokta sayısının sadece 32 bit (64 bit) ikili sayı olmasıyla ilgilidir, 1 bit işareti temsil eder, taban 2'nin 8 bit (11 bit) bir üssü ve 23 bit (52 bit) bir anlam ifade eder (parantezler çiftler için değerlerdir).

Araçlarla Yani tek hassasiyet içinde temsil edebilir en küçük pozitif sayı ,0000000000000000000001 x 2 ise -127 = 2 -22 x 2 -127 = 2 -149 ~ 1.40 x 10 -45 .

0,0000000000000000000010 x 2: Bir sonraki pozitif bir sayı olduğu çift -127 = 2 -148 ~ 2.80 x 10 -45 ve daha sonra bir sonraki numara, önceki iki ,0000000000000000000011 x 2 toplamıdır -127 = 3, x, 2 -149 ~ 4.2 - 45 .

0,1111111111111111111111 x 2: Bu kadar aynı sabit farkı ile artmaya devam -127 = 2 -126 - 2 149 ~ 1,17549435 x 10 -38 - 0,00000014 x 10 -38 = 1,17549421 x 10 -38

Şimdi normal sayılara ulaştınız (anlamlılığın ilk hanesi 1 olduğunda) özellikle: 1.0000000000000000000000 x 2 -126 = 2 -126 = 1.17549435 x 10 -38 ve sonraki sayı daha sonra 1.0000000000000000000001 x 2 -126 = 2 -126 (1 + 2 -22 ) x-1,00000023 1.17549435 =.


2

Kayan nokta sayılarının başlangıç ​​noktasından daha az hassas olmasının nedeni, kayan nokta sayısının büyük sayıları temsil edebilmesi gerektiğidir. Bunun nasıl yapıldığına "kayan nokta" terimi kazandırır. Her bir üs için yaklaşık aynı sayıda olması için alabileceği olası değerleri böler (bit uzunluğuyla belirlenir): 32 bitlik bir kayan nokta için, bitlerin 23'ü mantis veya anlamlıyı tanımlar. Böylece her üs aralığında 2 ^ 23 farklı değer alabilir. Bu üs aralıklarından biri 1-2 [2 ^ 0 ila 2 ^ 1] 'dir, bu nedenle 1 ila 2 aralığını 2 ^ 23 farklı değere bölmek çok fazla hassasiyet sağlar.

Ancak [2 ^ 10 ila 2 ^ 11] aralığını 2 ^ 23 farklı değere bölmek, her değer arasındaki boşluğun çok daha büyük olduğu anlamına gelir. Eğer olmasaydı, 23 bit yeterli olmazdı. Her şey bir uzlaşma: Herhangi bir gerçek sayıyı temsil etmek için sonsuz sayıda bite ihtiyacınız var. Uygulamanız daha büyük değerler için daha düşük hassasiyetle kurtulmanıza izin verecek şekilde çalışıyorsa ve büyük değerleri gerçekten temsil edebilmenizden faydalanıyorsanız, kayan nokta gösterimi kullanırsınız.


sadece 7 yıl sonra tekrar gözden geçirdiğimde bir not yazmak ... örneklerimdeki sayılar özellikle iyi seçilmiş değil. Ancak genel hususlar geçerlidir.
Steven Lu

1

Kayan nokta hassasiyetinin nasıl çalıştığına dair spesifik örnekler sunmak biraz zor olabilir. Diğer cevapları desteklemek için bir tane var. Diyelim ki üç basamaklı mantis ve bir üs basamağı ile ondalık kayan nokta numaramız var:

Mantissa × 10 üs

Üs 0 olduğunda, 0-999 aralığındaki her tamsayı tam olarak temsil edilebilir. 1 olduğunda, temelde o aralığın her öğesini 10 ile çarpıyorsunuz, böylece 0–9990 aralığını elde edersiniz; ancak şimdi, yalnızca 10'un katları doğru bir şekilde temsil edilebilir, çünkü hala yalnızca üç basamak hassasiyetiniz var. Üs en fazla 9 olduğunda, temsil edilebilir tamsayıların her çifti arasındaki fark bir milyardır . Kelimenin tam anlamıyla menzil için işlem hassasiyeti vardır.

İkili kayan noktalı sayılarla aynı şekilde çalışır: üs ne zaman bir yükselirse aralık iki katına çıkar , ancak bu aralıktaki temsil edilebilir değerlerin sayısı yarıya düşer . Bu, elbette probleminizin kaynağı olan kesirli sayılar için de geçerlidir.


0

Genel olarak, çözünürlük daha da kötüleşir, çünkü çözünürlük üs değeri ile çarpılır (2 ** üs parçası).

josh'un yorumunu kabul ederek: yukarıdakiler sadece cevabı kısa ve öz bir ifadeye koymaktı. Tabii ki, http://floatingorigin.com/ adresinde belirtmeye çalıştığım gibi , bu sadece genel bir çözüme doğru başlıyor ve programınız birçok yerden titremeye başlayabilir: hassas boru hattında veya kodun diğer kısımlarında .


Bu, diğer yanıtlarda bulunmayan hiçbir şey eklemez.

Doğru: Cevabı tek bir satırda tarif edebileceğimi fark ettim ve birinin kısa ve öz bir cevabı faydalı bulabileceğini düşündüm.
Chris Thorne

-1

OpenGL derinlik arabelleği doğrusal değildir . Ne kadar ileri giderseniz, o kadar kötü bir çözünürlüğe sahiptir. Okumayı tavsiye bu . Oradan alınan bir şey (12.070):

Özetle, perspektif bölünmesi, doğası gereği, görünüm hacminin önüne yakın arkaya göre daha fazla Z hassasiyetine neden olur.

Ve bir tane daha (12.040):

ZNear ve zFar kırpma düzlemlerinizi derinlik tamponu hassasiyetinizi ciddi şekilde sınırlayacak şekilde yapılandırmış olabilirsiniz. Genellikle bu, 0,0'a çok yakın bir zNear kırpma düzlemi değerinden kaynaklanır. ZNear kırpma düzlemi gittikçe daha fazla 0.0'a ayarlandığından, derinlik tamponunun etkili hassasiyeti önemli ölçüde azalır. ZFar kırpma düzlemini gözden daha uzağa taşımak, derinlik tamponu hassasiyeti üzerinde her zaman olumsuz bir etkiye sahiptir, ancak zNear kırpma düzlemini hareket ettirmek kadar dramatik değildir.

Bu nedenle, yakın kırpma uçağınızı mümkün olduğunca uzağa ve uzak uçağınızı olabildiğince yakın hareket ettirmelisiniz.


-1: soru, doğrusal olmayan derinlik arabellek gösterimi ile ilgili hassasiyet sorunları değil, kayan nokta hassasiyeti ile ilgilidir.
Nathan Reed

Gördüğüm şeyin derinlik tamponlama sorunları nedeniyle olması mümkündür. Sahnemi görüntülemek için OpenGL'nin üstünde bir lib kullanıyorum ve geometrinin boyutunu ve konumunu (izleyiciden beri) hesaba katmak için kamerayı, görünümü ve yakın ve uzak kırpma uçaklarını kurduğu varsayımını yapıyorum. araç, sahne içeriği için otomatik olarak en uygun görünümü ayarlıyor gibi görünüyor). Ama sanırım bu böyle olmayabilir - kırpma pozisyonları ile orijinal pozisyonunu değiştirmeden oynamaya çalışacağım ve ne olacağını göreceğim.
Pris

2Nathan Reed: Yazar, OpenGL sahnesine sahip olduğunu yazdı, bu yüzden bu sorun da olabileceğini düşündüm.
zacharmarz

Bu sorun benzer veya ilişkili görünebilir, ancak derinlik arabellek değerleri kesinlikle kayan nokta sayılarıyla uyumlu bir şekilde saklanmaz. Sabit nokta biçimidir. Bu nedenle cevap yanıltıcı olabilir.
Steven Lu
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.