Suuret luvut - Matematiikka JavaScriptissä


Kehitän 3D-avaruuspeliä, joka käyttää paljon matemaattisia kaavoja, navigointia, pehmenemistehosteita, rotaatioita, suuria etäisyyksiä planeettojen välillä, objektien massaa ja niin edelleen...

Kysymykseni on, mikä olisi paras tapa tehdä tämä matematiikan avulla. Pitäisikö minun laskea kaikki kokonaislukuina ja saada todella suuria kokonaislukuja (yli 20 numeroa), vai käyttää pieniä desimaalilukuja.

Kokemukseni mukaan matematiikka desimaaliluvuilla ei ole tarkkaa, mikä aiheuttaa outoa käyttäytymistä suuria desimaalilukuja käytettäessä.

Vastaus #1

Vältäisin desimaalien käyttöä. Niillä on tunnettuja tarkkuusongelmia: http://floating-point-gui.de/

Suosittelisin käyttämään kokonaislukuja, mutta jos sinun täytyy käsitellä hyvin suuria kokonaislukuja, suosittelisin käyttämään suurten numeroiden tai suurten kokonaislukujen kirjastoa, kuten jotakin näistä:

  • http://jsfromhell.com/classes/bignumber
  • https://silentmatt.com/biginteger/

Haittapuolena on, että sinun täytyy käyttää näitä numero-olioita ja niiden metodeja sen sijaan, että käyttäisit primitiivistä Number-tyyppiä ja tavallisia JS-operaattoreita, mutta sinulla on paljon enemmän joustavuutta suurten lukujen käsittelyssä.

Muokkaus:
Kuten le_m huomautti, toinen haittapuoli on nopeus. Kirjaston menetelmät eivät toimi yhtä nopeasti kuin alkuperäiset operaattorit. Sinun täytyy testata itse nähdäksesi, onko suorituskyky hyväksyttävä.

Vastaus #2

Etäisyys meidän Auringostamme Alpha Centauriin on 4.153×1018 cm. Voit esittää tämän arvon hyvin Number-tietotyypillä, joka tallentaa arvoja jopa 1.7977×10308 saakka noin 17 merkitsevän numeron tarkkuudella.

Mutta entä jos haluat mallintaa avaruusalusta, joka on asemassa Alpha Centaurilla?

Koska Number-tyypillä on rajoitettu tarkkuus, voit tallentaa joko arvon 4153000000000000000 tai 4153000000000000500, mutta ei mitään näiden välissä. Tämä tarkoittaa, että sinulla olisi maksimaalinen spatiaalinen resoluutio 500 cm Alphassa Kentaurilla. Avaruusaluksesi näyttäisi todella kömpelöltä.

Voisimmeko käyttää toista tietotyyppiä kuin Number? Tietenkin voit käyttää kirjastoa, kuten BigNumber.js, joka tarjoaa tuen lähes rajattomalle tarkkuudelle. Voit pysäköidä avaruusaluksesi yhden millimetrin päähän Alpha Centaurin kuumasta ytimestä ilman (numeerisia) ongelmia:

pos_acentauri = new BigNumber(4153000000000000000);

pos_spaceship = pos_acentauri.add(0.1); // one milimeter from Alpha Centauri

console.log(pos_spaceship); // 4153000000000000000.1
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/2.3.0/bignumber.min.js"></script>

Kuitenkin ei ainoastaan tuon aluksen kapteeni palaisi kuoliaaksi, vaan myös 3D-moottorisi olisi hirvittävän hidas. Tämä johtuu siitä, että Number sallii todella nopeat aritmeettiset laskelmat vakioajassa, kun taas esimerkiksi BigNumber-yhteenlaskun laskenta-aika kasvaa tallennetun arvon koon mukaan.

Ratkaisu: Käytä Number 3D-moottorissasi. Voit käyttää erilaisia paikallisia koordinaattijärjestelmiä, esimerkiksi yhtä Alfa Centaurille ja yhtä aurinkokunnallemme. Käytä BigNumber vain asioihin, kuten HUD, pelitilastot ja niin edelleen.