11

Come posso garantire che i calcoli in virgola mobile in un'applicazione .NET (ad esempio in C#) producano sempre lo stesso risultato bit-esatto? Soprattutto quando si utilizzano versioni diverse di .NET e in esecuzione su piattaforme diverse (x86 vs x86_64). Le inesattezze delle operazioni in virgola mobile non contano.Punto mobile deterministico e .NET

In Java userei strictfp. In C/C++ e in altri linguaggi di basso livello questo problema viene essenzialmente risolto accedendo ai registri di controllo FPU/SSE ma probabilmente non è possibile in .NET.

Anche con il controllo del registro di controllo della FPU, il JIT di .NET genera codice diverso su piattaforme diverse. Qualcosa come HotSpot sarebbe anche peggio in questo caso ...

Perché ne ho bisogno? Sto pensando di scrivere un gioco di strategia in tempo reale (RTS) che dipende in larga misura dalla matematica in virgola mobile e da una simulazione a blocchi. Essenzialmente trasmetterò solo l'input dell'utente attraverso la rete. Questo vale anche per altri giochi che implementano replay memorizzando l'input dell'utente.

Non è un'opzione sono:

  • decimali (troppo lento)
  • valori virgola fissa (troppo lente e ingombranti quando si utilizza sqrt, sin, cos, tan, atan ...)
  • aggiornamento stato attraverso la rete come un FPS: L'invio di informazioni sulla posizione per centinaia o poche migliaia di unità non è un'opzione

Qualche idea?

risposta

2

Non sono sicuro della risposta esatta per la tua domanda ma potresti usare C++ e fare tutto il tuo float in una dll C++ e poi restituire il risultato a .Net attraverso un interopt.

+0

Se scrivessi la parte critica (simulazione) del gioco in C/C++, allora posso semplicemente scrivere l'intero gioco senza .Net. Forse è il modo "giusto" qui. – user285934

+0

Esaminare la funzionalità C/C++ IJW (It-Just-Works) del compilatore MSVC. Ti consentirà di scrivere ciò che devi scrivere come codice non gestito, e fare il resto come codice gestito per interfacciarsi agevolmente con il resto delle parti gestite del tuo gioco. – Ants

1

I risultati di Bitexact per diverse piattaforme sono un dolore nella a **. Se si utilizza solo x86, non dovrebbe essere importante poiché la FPU non cambia da da 32 a 64 bit. Ma il problema è che le funzioni trascendentali potrebbero essere più accurate sui nuovi processori.

Le quattro operazioni di base non dovrebbero dare risultati diversi, ma la vostra macchina virtuale potrebbe ottimizzare le espressioni e questo potrebbe dare risultati diversi. Quindi, come proposto da Ants, scrivi le tue routine add/mul/div/sub come codice non gestito per essere sicuri.

Per le funzioni trascendentali temo che sia necessario utilizzare una tabella di ricerca su per garantire l'esattezza del bit. Calcola il risultato di ad es. 4096 valori, memorizzarli come costanti e se è necessario un valore tra loro, interpolare. Questo non ti dà grande precisione, ma sarà bitexact.

+0

Le quattro operazioni di base producono risultati diversi anche su un singolo processore quando l'unità SSE e l'FPU non sono configurate correttamente (disabilita i numeri subnormali per entrambi, usa valori a 32 bit o 64 bit su fpu anziché la massima precisione). Le funzioni trascendentali possono essere implementate in software utilizzando questo ambiente controllato in C/C++. – user285934

0

Se si desidera il determinismo in virgola mobile è necessario eliminare tutte le variabili. Questo è possibile se si limita un po 'il proprio ambito.

  1. Effettuare l'applicazione solo a 64 bit. In questo modo non si ha a che fare con x87 vs SSE (x86 JIT emette ancora codice x87 fp, altri JIT emettono SSE).
  2. Utilizzare .NET Core e bundle the runtime with your application. In questo modo garantisci lo stesso codice per qualsiasi versione della tua applicazione. Questo è fondamentale, le più piccole differenze di codegen possono causare calcoli fp per dare risultati diversi.
  3. Attaccare con un sistema operativo. Seriamente, quanti RTS cross-platform sono disponibili? Sì, c'è Starcraft 2; questo è tutto AFAIK. Blizzard ha padroneggiato questa arte per molto tempo e pochissimi potrebbero replicare questa impresa. Se vuoi veramente supportare il multiplayer per Mac-PC, dovrai verificare scrupolosamente che il tuo runtime .NET generi lo stesso codice fp su entrambe le piattaforme. E se non lo fai, sei sfortunato.

Un punto di cui non sono ancora sicuro è se è possibile fidarsi della classe Math per ottenere risultati coerenti, date le restrizioni di cui sopra; ma suppongo che dovrebbe

Problemi correlati