Apa level “relatif” terbesar yang bisa saya buat menggunakan float?


13

Sama seperti itu ditunjukkan dengan permainan seperti pengepungan penjara dan KSP, level yang cukup besar akan mulai mengalami gangguan karena cara kerja floating point. Anda tidak dapat menambahkan 1e-20 hingga 1e20 tanpa kehilangan keakuratan.

Jika saya memilih untuk membatasi ukuran level saya, bagaimana cara menghitung kecepatan minimum objek saya dapat bergerak sampai mulai berombak?

Jawaban:


26

Pelampung 32-bit memiliki mantra 23 bit .

Itu berarti setiap angka direpresentasikan sebagai 1.xxx xxx xxx xxx xxx xxx xx kali beberapa kekuatan 2, di mana setiap x adalah digit biner, baik 0 atau 1. (Dengan pengecualian dari angka denormalized sangat kecil kurang dari 2-126 - mereka mulai dengan 0. bukannya 1., tapi saya akan mengabaikannya untuk yang berikut)

Jadi dalam rentang dari 2saya dan 2(saya+1) , Anda dapat mewakili angka berapa pun dalam akurasi ±2(saya-24)

Sebagai contoh, untuk saya=0 , angka terkecil dalam kisaran ini adalah (20)1=1 . Angka terkecil berikutnya adalah (20)(1+2-23) . Jika Anda ingin mewakili 1+2-24 , Anda harus membulatkan ke atas atau ke bawah, untuk kesalahan 2-24 .

In this range:                You get accuracy within:
-----------------------------------------------
         0.25   -     0.5    2^-26 = 1.490 116 119 384 77 E-08
         0.5    -     1      2^-25 = 2.980 232 238 769 53 E-08
         1     -      2      2^-24 = 5.960 464 477 539 06 E-08
         2     -      4      2^-23 = 1.192 092 895 507 81 E-07
         4     -      8      2^-22 = 2.384 185 791 015 62 E-07
         8     -     16      2^-21 = 4.768 371 582 031 25 E-07
        16     -     32      2^-20 = 9.536 743 164 062 5  E-07
        32     -     64      2^-19 = 1.907 348 632 812 5  E-06
        64     -    128      2^-18 = 0.000 003 814 697 265 625
       128    -     256      2^-17 = 0.000 007 629 394 531 25
       256    -     512      2^-16 = 0.000 015 258 789 062 5
       512    -   1 024      2^-15 = 0.000 030 517 578 125
     1 024    -   2 048      2^-14 = 0.000 061 035 156 25
     2 048    -   4 096      2^-13 = 0.000 122 070 312 5
     4 096    -   8 192      2^-12 = 0.000 244 140 625
     8 192   -   16 384      2^-11 = 0.000 488 281 25
    16 384   -   32 768      2^-10 = 0.000 976 562 5
    32 768   -   65 536      2^-9  = 0.001 953 125
    65 536   -  131 072      2^-8  = 0.003 906 25
   131 072   -  262 144      2^-7  = 0.007 812 5
   262 144   -  524 288      2^-6  = 0.015 625
   524 288 -  1 048 576      2^-5  = 0.031 25
 1 048 576 -  2 097 152      2^-4  = 0.062 5
 2 097 152 -  4 194 304      2^-3  = 0.125
 4 194 304 -  8 388 608      2^-2  = 0.25
 8 388 608 - 16 777 216      2^-1  = 0.5
16 777 216 - 33 554 432      2^0   = 1

Jadi, jika unit Anda adalah meter, Anda akan kehilangan presisi milimeter di sekitar 16 484 - 32 768 band (sekitar 16-33 km dari asal).

Secara umum diyakini Anda dapat mengatasi ini dengan menggunakan unit dasar yang berbeda, tetapi itu tidak benar, karena presisi relatif yang penting.

  • Jika kita menggunakan sentimeter sebagai unit kita, kita kehilangan ketelitian milimeter pada pita 1 048 576-2 097 152 (10-21 km dari asalnya)

  • Jika kami menggunakan hektametres sebagai unit kami, kami kehilangan presisi milimeter pada pita 128-256 (13-26 km dari titik asalnya)

... jadi mengubah unit lebih dari empat kali lipat masih berakhir dengan kehilangan presisi milimeter di suatu tempat di kisaran puluhan kilometer. Yang kami bergeser adalah di mana tepatnya di band itu hits (karena ketidakcocokan antara basis-10 dan basis-2 penomoran) tidak secara drastis memperluas area bermain kami.

Tepatnya seberapa banyak ketidaktepatan yang bisa ditoleransi permainan Anda akan tergantung pada detail gameplay Anda, simulasi fisika, ukuran entitas / jarak gambar, resolusi render, dll. Jadi sulit untuk menetapkan cutoff yang tepat. Mungkin rendering Anda terlihat baik-baik saja 50 km dari asalnya, tetapi peluru Anda berpindah melalui dinding, atau skrip gameplay yang sensitif menjadi berantakan. Atau Anda mungkin menemukan permainan ini berjalan dengan baik, tetapi semuanya memiliki getaran yang nyaris tidak terlihat dari ketidakakuratan dalam transformasi kamera.

Jika Anda mengetahui tingkat akurasi yang Anda butuhkan (katakanlah, rentang 0,01 unit peta hingga sekitar 1 px pada jarak pandang / interaksi khas Anda, dan offset yang lebih kecil tidak terlihat), Anda dapat menggunakan tabel di atas untuk menemukan di mana Anda kehilangan itu. akurasi, dan mundur beberapa urutan besarnya untuk keselamatan jika terjadi operasi yang merugi.

Tetapi jika Anda berpikir tentang jarak yang sangat jauh, mungkin lebih baik untuk menghindari semua ini dengan memasukkan kembali dunia Anda saat pemain bergerak. Anda memilih daerah berbentuk persegi atau kubus yang konservatif kecil di sekitar titik asal. Setiap kali pemain bergerak di luar wilayah ini, menerjemahkannya, dan semua yang ada di dunia, kembali setengah lebar dari wilayah ini, menjaga pemain tetap di dalam. Karena semuanya bergerak bersama, pemain Anda tidak akan melihat perubahan. Ketidakakuratan masih dapat terjadi di belahan dunia yang jauh, tetapi umumnya tidak terlalu terlihat di sana daripada terjadi tepat di bawah kaki Anda, dan Anda dijamin selalu memiliki ketepatan tinggi yang tersedia di dekat pemain.


1
Recentering jelas merupakan cara untuk pergi!
Floris

2
Bagaimana dengan menggunakan koordinat titik tetap? Mungkin dengan integer 64 bit jika perlu?
API-Beast

pertanyaannya adalah, seberapa besar wilayah yang bisa dipusatkan itu? jika misalnya dalam permainan saya ingin memotret pada jarak jauh dengan zoom yang kuat, apakah saya benar-benar perlu menggunakan ganda atau cukup mengambang? bukankah lebih baik untuk masuk kembali sesuai dengan quad tree atau algoritma ubin?
jokoon

Ini akan tergantung pada stabilitas numerik dari algoritma yang digunakan oleh rendering dan sistem fisika Anda - jadi untuk basis kode / mesin yang diberikan, satu-satunya cara untuk mengetahui pasti adalah mencoba adegan pengujian. Kita dapat menggunakan tabel untuk memperkirakan akurasi maksimum (mis. Sebuah kamera yang berjarak 16 km dari suatu objek akan cenderung melihat setidaknya kesalahan ukuran milimeter, sehingga zoom Anda harus cukup lebar untuk menjaga yang lebih kecil dari satu piksel - jika kebutuhan zoom diperlukan. untuk menjadi lebih ketat untuk gim Anda kemudian berlipat ganda atau matematika pintar mungkin diperlukan), tetapi rantai operasi yang merugi dapat mengalami masalah jauh sebelum batas hipotetis ini.
DMGregory

Saya masih bertanya-tanya apa artinya memasukkan kembali dunia ke API grafis. Jika saya memiliki sebagian besar geometri yang dipasang (atau tidak dipasang), apakah masih aman untuk melakukannya? Saya kira itu berarti menerjemahkan SEMUA transformasi, tetapi jika saya melakukan ini beberapa kali, bukankah ada risiko kehilangan presisi floating point?
jokoon

3

Sulit untuk menjawab karena itu tergantung pada skala fisika Anda: Berapa kecepatan gerakan minimum yang dapat diterima yang TIDAK perlu dibulatkan menjadi nol?

Jika Anda membutuhkan dunia yang besar dan fisika yang konsisten, lebih baik menggunakan kelas poin tetap.

Misalnya, menembakkan bola meriam dari mana saja di dunia akan memberi Anda hasil yang sama dan titik tetap 64bit (32,32) memberi Anda ketepatan yang sangat besar dan lebih dari apa pun yang dapat dilihat di sebagian besar permainan. Jika unit Anda 1 meter Anda masih berada di 232 pikometer presisi 2147483km dari tempat asalnya.

Anda masih dapat melakukan fisika lokal dalam floating point dalam sel lokal untuk menghemat pekerjaan pemrograman dan menggunakan mesin fisika off-the-shelf. Ini akan tetap konsisten untuk semua tujuan praktis.

Sebagai fase bonus luas dan AABB cenderung lebih cepat di titik tetap karena latensi FPU. Ini juga lebih cepat untuk mengonversi titik tetap menjadi indeks octree (atau quadtree) karena Anda dapat melakukan masking bit sederhana.

Operasi-operasi itu tidak mendapatkan banyak manfaat dari instruksi SIMD dan pemipaan yang biasanya menyembunyikan latensi FPU.

Anda dapat mengubah posisi menjadi titik mengambang SETELAH mengurangi posisi kamera pada titik tetap untuk membuat semuanya, menghindari masalah titik mengambang di dunia besar dan masih menggunakan penyaji reguler menggunakan titik mengambang.


-3

Anda dapat menghindarinya sekaligus dengan multiplikasi.
Alih-alih bekerja dengan float, cukup kalikan dengan 10 ^ (x), simpan, dan bila dibutuhkan, kalikan lagi dengan 10 ^ (- x).
Dari situ tergantung jenis int yang ingin Anda gunakan.


2
Ini tidak menghindari masalah. Format titik tetap masih memiliki ketelitian dan jangkauan terbatas - semakin besar kisaran, semakin rendah presisi (berdasarkan di mana Anda meletakkan titik desimal tetap) - sehingga keputusan "seberapa besar saya dapat membuat level tanpa kesalahan pembulatan yang terlihat" masih berlaku.
DMGregory

3
Selain itu, basis-10 tidak terlalu praktis. Angka titik tetap bekerja jauh lebih baik ketika Anda membagi bilangan bulat dalam hal bit (pertimbangkan unsigned 26,6 - komponen fraksional adalah 6-bit yang lebih rendah ( 1,0 / 64,0 * x & 63) dan bagian integralnya hanya x >> 6) . Itu jauh lebih sederhana untuk diterapkan daripada meningkatkan sesuatu menjadi kekuatan sepuluh.
Andon M. Coleman
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.