Como posso executar uma simulação de física determinística?


43

Estou criando um jogo de física envolvendo corpos rígidos nos quais os jogadores movem peças e peças para resolver um quebra-cabeça / mapa. Um aspecto extremamente importante do jogo é que, quando os jogadores iniciam uma simulação, ela é executada da mesma maneira em todos os lugares , independentemente do sistema operacional, processador, etc.

Há espaço para muita complexidade, e as simulações podem ser executadas por um longo tempo, por isso é importante que o mecanismo de física seja completamente determinístico em relação às operações de ponto flutuante; caso contrário, uma solução pode parecer "resolver" na máquina de um jogador e "falhar" em outro.

Como posso obter esse determinismo no meu jogo? Estou disposto a usar uma variedade de estruturas e linguagens, incluindo Javascript, C ++, Java, Python e C #.

Fui tentado pelo Box2D (C ++) e seus equivalentes em outras linguagens, pois parece atender às minhas necessidades, mas falta um determinismo de ponto flutuante, principalmente com funções trigonométricas.

A melhor opção que vi até agora foi o equivalente em Java do Box2D (JBox2D). Parece fazer uma tentativa de determinismo de ponto flutuante usando StrictMathmais do que Mathpara muitas operações, mas não está claro se esse mecanismo garantirá tudo o que preciso, pois ainda não construí o jogo.

É possível usar ou modificar um mecanismo existente para atender às minhas necessidades? Ou precisarei construir um mecanismo por conta própria?

EDIT: ignore o restante desta postagem se você não se importa com o motivo de alguém precisar de tanta precisão. Pessoas em comentários e respostas parecem acreditar que estou procurando algo que não deveria e, como tal, explicarei melhor como o jogo deve funcionar.

O jogador recebe um quebra-cabeça ou nível, que contém obstáculos e um objetivo. Inicialmente, uma simulação não está sendo executada. Eles podem usar peças ou ferramentas fornecidas para construir uma máquina. Depois que eles pressionam start, a simulação começa e eles não podem mais editar sua máquina. Se a máquina resolver o mapa, o jogador venceu o nível. Caso contrário, eles terão que pressionar parar, alterar sua máquina e tentar novamente.

A razão pela qual tudo precisa ser determinista é porque planejo produzir código que mapeie todas as máquinas (um conjunto de peças e ferramentas que tentam resolver um nível) para um arquivo xml ou json, registrando a posição, o tamanho e a rotação de cada peça. Será possível, então, que os jogadores compartilhem soluções (representadas por esses arquivos) para que possam verificar soluções, aprender uns com os outros, realizar competições, colaborar, etc ... É claro que a maioria das soluções, principalmente as simples ou rápidas os, não serão afetados pela falta de determinismo. Mas os projetos lentos ou complexos que resolvem níveis realmente difíceis podem, e esses são os que provavelmente serão os mais interessantes e que vale a pena compartilhar.


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo . Se você acha que tem uma solução para o problema, considere publicá-la como uma resposta, e não como um comentário - isso facilita a edição, a avaliação via votação / marcação aceita ou o comentário diretamente na sugestão em si para obter feedback, em vez de tecer respostas em um segmento de conversa mais longo.
DMGregory

Respostas:


45

Manipulando números de ponto flutuante de maneira determinística

O ponto flutuante é determinístico. Bem, deveria ser. É complicado.

Há muita literatura sobre números de ponto flutuante:

E como eles são problemáticos:

Para resumo. Pelo menos, em um único encadeamento, as mesmas operações, com os mesmos dados, ocorrendo na mesma ordem, devem ser determinísticas. Assim, podemos começar nos preocupando com insumos e reordenando.


Uma dessas entradas que causa problemas é o tempo.

Primeiro de tudo, você deve sempre calcular o mesmo timestep. Não estou dizendo para não medir o tempo, estou dizendo que você não passará o tempo para a simulação da física, porque variações no tempo são uma fonte de ruído na simulação.

Por que você mede o tempo se não está passando para a simulação de física? Você deseja medir o tempo decorrido para saber quando uma etapa de simulação deve ser chamada e - supondo que você esteja usando o sono - quanto tempo dormir.

Portanto:

  • Meça o tempo: Sim
  • Use o tempo na simulação: Não

Agora, reordenação de instruções.

O compilador pode decidir que f * a + bé o mesmo que b + f * a, no entanto, que pode ter um resultado diferente. Também pode ser compilado para o fmadd , ou pode-se decidir pegar várias linhas como essa que acontecem juntas e escrevê-las com o SIMD , ou alguma outra otimização em que não consigo pensar agora. E lembre-se de que queremos que as mesmas operações ocorram na mesma ordem, é lógico que queremos controlar quais operações acontecem.

E não, usar o dobro não o salvará.

Você precisa se preocupar com o compilador e sua configuração, em particular para sincronizar números de ponto flutuante na rede. Você precisa obter as compilações para concordar em fazer a mesma coisa.

Indiscutivelmente, escrever montagem seria o ideal. Dessa forma, você decide qual operação fazer. No entanto, isso pode ser um problema para suportar várias plataformas.

Portanto:


O caso dos números de pontos fixos

Devido à maneira como os carros alegóricos são representados na memória, valores grandes perdem a precisão. É lógico que manter seus valores pequenos (grampo) atenua o problema. Assim, não há velocidades enormes nem salas grandes. O que também significa que você pode usar física discreta porque tem menos risco de tunelamento.

Por outro lado, pequenos erros serão acumulados. Então, trunque. Quero dizer, dimensionar e converter para um tipo inteiro. Dessa forma, você sabe que nada está se acumulando. Haverá operações que você pode fazer permanecendo com o tipo inteiro. Quando você precisa voltar ao ponto flutuante, lança e desfaz a escala.

Nota eu digo escala. A ideia é que 1 unidade seja realmente representada como uma potência de duas (16384, por exemplo). Seja o que for, faça uma constante e use-a. Você está basicamente usando-o como número de ponto fixo. De fato, se você puder usar números de pontos fixos adequados de uma biblioteca confiável, é muito melhor.

Eu estou dizendo truncado. Sobre o problema do arredondamento, isso significa que você não pode confiar no último bit de qualquer valor que tenha após o lançamento. Portanto, antes da escala de elenco obter um pouco mais do que você precisa, e trunque depois.

Portanto:

  • Mantenha os valores pequenos: Sim
  • Arredondamento cuidadoso: Sim
  • Números de pontos fixos quando possível: Sim

Espere, por que você precisa de ponto flutuante? Você não poderia trabalhar apenas com um tipo inteiro? Oh, certo. Trigonometria e radicação. Você pode calcular tabelas para trigonometria e radicação e colocá-las em sua fonte. Ou você pode implementar os algoritmos usados ​​para computá-los com número de ponto flutuante, exceto usando números de ponto fixo. Sim, você precisa equilibrar memória, desempenho e precisão. No entanto, você pode ficar fora dos números de ponto flutuante e permanecer determinístico.

Você sabia que eles fizeram coisas assim para o PlayStation original? Por favor, encontre o meu cão, patches .

A propósito, não estou dizendo para não usar ponto flutuante para gráficos. Apenas para a física. Quero dizer, claro, as posições dependerão da física. No entanto, como você sabe, um colisor não precisa corresponder a um modelo. Não queremos ver os resultados do truncamento dos modelos.

Assim: USE NÚMEROS DE PONTO FIXO.


Para ficar claro, se você pode usar um compilador que permite especificar como os pontos flutuantes funcionam e isso é suficiente para você, você pode fazer isso. Isso nem sempre é uma opção. Além disso, estamos fazendo isso por determinismo. Os números de pontos fixos não significam que não há erros, afinal eles têm precisão limitada.

Eu não acho que "número de ponto fixo seja difícil" é uma boa razão para não usá-los. E se você deseja um bom motivo para usá-los, é determinismo, em particular determinismo entre plataformas.


Veja também:


Adendo : Estou sugerindo que o tamanho do mundo seja pequeno. Com isso dito, o OP e o Jibb Smart levantam o ponto de que se afastar dos carros alegóricos de origem tem menos precisão. Isso terá um efeito sobre a física, algo que será visto muito mais cedo do que o limite do mundo. Números de pontos fixos, bem, têm precisão fixa, serão igualmente bons (ou ruins, se você preferir) em todos os lugares. O que é bom se queremos determinismo. Também quero mencionar que a maneira como costumamos fazer física tem a propriedade de amplificar pequenas variações. Veja O Efeito Borboleta - Física Determinística no Incredible Machine and Contraption Maker .


Outra maneira de fazer física

Eu estive pensando, a razão pela qual o pequeno erro de precisão nos números de ponto flutuante se amplifica é porque estamos fazendo iterações nesses números. A cada etapa da simulação, pegamos os resultados da última etapa da simulação e fazemos coisas neles. Acumular erros em cima de erros. Esse é o seu efeito borboleta.

Eu não acho que veremos uma única compilação usando um único thread na mesma máquina produzir uma saída diferente pela mesma entrada. No entanto, em outra máquina poderia, ou uma construção diferente poderia.

Há um argumento para testar lá. Se decidirmos exatamente como as coisas devem funcionar e pudermos testar no hardware de destino, não devemos criar builds que tenham um comportamento diferente.


No entanto, há também um argumento para não trabalhar longe que acumula tantos erros. Talvez seja uma oportunidade de fazer física de uma maneira diferente.

Como você deve saber, existe uma física contínua e discreta, ambas trabalham em quanto cada objeto avançaria no passo temporal. No entanto, a física contínua tem os meios para descobrir o instante de colisão em vez de investigar diferentes instantes possíveis para ver se ocorreu uma colisão.

Assim, proponho o seguinte: use as técnicas da física contínua para descobrir quando ocorrerá a próxima colisão de cada objeto, com um grande intervalo de tempo, muito maior que o de uma única etapa de simulação. Então você pega o instante de colisão mais próximo e descobre onde tudo estará naquele instante.

Sim, isso é muito trabalho de uma única etapa de simulação. Isso significa que a simulação não será iniciada instantaneamente ...

... No entanto, você pode simular as próximas etapas da simulação sem verificar a colisão a cada vez, porque você já sabe quando a próxima colisão ocorrerá (ou que nenhuma colisão ocorrerá no grande espaço de tempo). Além disso, os erros acumulados nessa simulação são irrelevantes porque, uma vez que a simulação atinge um grande passo no tempo, colocamos as posições que computamos anteriormente.

Agora, podemos usar o orçamento de tempo que teríamos usado para verificar colisões em cada etapa da simulação para calcular a próxima colisão após a que encontramos. Ou seja, podemos simular com antecedência usando o timestep grande. Supondo um mundo de escopo limitado (isso não funcionará para jogos enormes), deve haver uma fila de estados futuros para a simulação e, em seguida, cada quadro que você interpola do último estado para o próximo.


Eu argumentaria por interpolação. No entanto, como existem acelerações, não podemos simplesmente interpolar tudo da mesma maneira. Em vez disso, precisamos interpolar levando em consideração a aceleração de cada objeto. Por esse motivo, poderíamos apenas atualizar a posição da mesma maneira que fazemos para o timestep grande (o que também significa que é menos propenso a erros, porque não estaríamos usando duas implementações diferentes para o mesmo movimento).


Nota : Se estivermos fazendo esses números de ponto flutuante, essa abordagem não resolverá o problema de os objetos se comportarem de maneira diferente quanto mais distantes da origem. No entanto, embora seja verdade que a precisão é perdida quanto mais longe você for da origem, isso ainda é determinístico. De fato, é por isso que nem trouxe isso à tona originalmente.


Termo aditivo

Do OP no comentário :

A idéia é que os jogadores possam salvar suas máquinas em algum formato (como xml ou json), para que a posição e a rotação de cada peça sejam registradas. Esse arquivo xml ou json será usado para reproduzir a máquina no computador de outro jogador.

Então, nenhum formato binário, certo? Isso significa que também precisamos nos preocupar com os números de ponto flutuante recuperados, correspondentes ou não ao original. Consulte: Precisão do flutuador revisitada: portabilidade de flutuador de nove dígitos


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Vaillancourt

2
Ótima resposta! Mais 2 pontos a favor do ponto fixo: 1. o ponto flutuante se comportará de maneira diferente mais próximo ou mais distante da origem (se você tiver o mesmo quebra-cabeça em um lugar diferente), mas o ponto fixo não; 2. ponto fixo realmente tem mais precisão do que ponto flutuante na maior parte de sua faixa - você pode obter precisão usando bem o ponto fixo
Jibb Smart

É possível codificar dados binários em XML e JSON usando base64elementos. Não é uma maneira eficiente de representar grandes quantidades desses dados, mas é incorreto sugerir que eles impedem o uso de representações binárias.
Pikalek

1
@Pikalek eu sei, o OP me perguntou sobre isso nos comentários, mencionei o base64 como uma opção, entre outras, incluindo hex, reinterpretar o elenco como int e usar o formato protobuf, já que ninguém entenderá esses arquivos de qualquer maneira, eles não são (sem treinamento) ) legível por humanos. Então - eu assumo - um mod removeu os comentários (não, não está no chat vinculado acima). Isso vai acontecer de novo? Devo remover isso da resposta? Devo prolongar?
Theraot

@ Theraot Ah, eu posso ver como eu poderia ter interpretado isso de maneira diferente no contexto de comentários excluídos. (FWIW, eu li as conversas sobre esta resposta e a pergunta). E mesmo que houvesse uma maneira nativa e eficiente de codificar os dados, ainda há a questão maior de garantir que isso signifique a mesma coisa nas plataformas. Dada a rotatividade, talvez seja melhor deixar como está. Obrigado por esclarecer!
Pikalek

6

Eu trabalho para uma empresa que faz um certo jogo de estratégia em tempo real bem conhecido e posso dizer que o determinismo de ponto flutuante é possível.

O uso de compiladores diferentes, ou o mesmo compilador com configurações diferentes, ou mesmo versões diferentes do mesmo compilador, pode quebrar o determinismo.

Se você precisar de crossplay entre plataformas ou versões de jogos, acho que precisará ir com um ponto fixo - a única crossplay possível que eu conheço com ponto flutuante é entre PC e XBox1, mas isso é muito louco.

Você precisará encontrar um mecanismo de física que seja totalmente determinístico, ou usar um mecanismo de código aberto e torná-lo determinístico ou executar seu próprio mecanismo. No topo da minha cabeça, tenho a sensação de que a Unity de todas as coisas adicionou um mecanismo determinístico de física, mas não tenho certeza se é apenas determinístico na mesma máquina ou determinístico em todas as máquinas.

Se você tentar criar suas próprias coisas, algumas coisas que podem ajudar:

  • Os flutuadores IEE754 são determinísticos se você não estiver fazendo nada muito frutado (google "determinismo IEE754" para obter mais informações sobre o que é ou não coberto)
  • Você precisa garantir que cada cliente tenha seu modo de arredondamento e precisão definidos de forma idêntica (use controlfp para defini-lo)
  • o modo de arredondamento e a precisão podem ser alterados por determinadas bibliotecas de matemática; portanto, se você estiver usando alguma biblioteca fechada, é recomendável checá-las após fazer chamadas (novamente usando controlfp para verificar)
  • algumas instruções SIMD são determinísticas, muitas não são, tenha cuidado
  • como mencionado acima, para garantir o determinismo, você também precisa da mesma plataforma, da mesma versão exata do mesmo compilador, da mesma configuração e das mesmas configurações do compilador
  • construa algumas ferramentas para detectar dessincronização de estado e ajude a diagnosticá-las - por exemplo, faça a CRC do estado do jogo a cada quadro a ser detectado quando ocorre uma dessincronização e, em seguida, tenha um modo de registro detalhado, onde você pode ativar onde modificações no estado do jogo são laboriosamente registradas em um arquivo, então pegue 2 arquivos de simulações dessincronizados um do outro e compare em uma ferramenta diff para ver onde está errado
  • inicialize todas as suas variáveis ​​no estado do jogo, principal fonte de dessincronização
  • toda a simulação do jogo precisa acontecer exatamente na mesma ordem todas as vezes para evitar dessincronizações, é incrivelmente fácil entender errado, é aconselhável estruturar a simulação do jogo de maneira a minimizar isso. Eu realmente não sou um cara de padrão de design de software, mas para este caso provavelmente é uma boa idéia - você pode considerar algum tipo de padrão em que a simulação do jogo é como uma caixa segura, e a única maneira de alterar o estado do jogo é inserir "messages" ou "comandos", com apenas acesso const fornecido a qualquer coisa fora do estado do jogo (por exemplo, renderização, rede, etc). Portanto, colocar a simulação em rede para um jogo multiplayer é o caso de enviar esses comandos pela rede ou repetir a mesma simulação é o caso de gravar o fluxo de comandos na primeira vez,

1
O Unity está realmente trabalhando em direção a uma meta de determinismo entre plataformas com seu novo sistema Unity Physics para sua pilha de tecnologia orientada a dados, mas, pelo que entendi, ainda é um trabalho em andamento e ainda não está completo / pronto para uso.
DMGregory

O que é um exemplo de uma instrução SIMD não determinística? Você está pensando em aproximados uns como rsqrtps?
Ruslan

O @DMGregory deve estar em pré-visualização, como você já pode usá-lo - mas, como você diz, ainda não pode ter terminado.
Joe

@Ruslan sim rsqrtps / rcpps os resultados dependem da implementação
Joe

5

Não tenho certeza se esse é o tipo de resposta que você está procurando, mas uma alternativa pode ser executar os cálculos em um servidor central. Faça com que os clientes enviem a configuração ao seu servidor, permitam que ele execute a simulação (ou recupere uma em cache) e envie os resultados, que são então interpretados pelo cliente e processados ​​em gráficos.

Obviamente, isso interrompe todos os planos que você possa ter para executar o cliente no modo off-line e, dependendo de quão intensamente computacional sejam as simulações, pode ser necessário um servidor muito poderoso. Ou vários, mas pelo menos você tem a opção de garantir que eles tenham a mesma configuração de hardware e software. Uma simulação em tempo real pode ser difícil, mas não impossível (pense em transmissões de vídeo ao vivo - elas funcionam, mas com um pequeno atraso).


1
Eu concordo completamente. É assim que você garante uma experiência compartilhada com todos os usuários. gamedev.stackexchange.com/questions/6645/… discute um tópico semelhante, comparando a diferença entre a física do lado do cliente e a do servidor.
Tim Holt

1

Vou dar uma sugestão contra-intuitiva de que, embora não seja 100% confiável, funcione bem na maior parte do tempo e é muito fácil de implementar.

Reduza a precisão.

Use um tamanho de etapa de tempo constante pré-determinado, execute a física em cada etapa no flutuador padrão de precisão dupla, mas depois quantize a resolução de todas as variáveis ​​em precisão única (ou algo ainda pior) após cada etapa. Em seguida, a maioria dos desvios possíveis que a reordenação de ponto flutuante poderia introduzir (em comparação com uma execução de referência do mesmo programa) será cortada porque esses desvios ocorrem em dígitos que nem existem na precisão reduzida. Assim, o desvio não tem a chance de um acúmulo de Lyapunov (efeito borboleta) que acabaria se tornando notável.

Obviamente, a simulação será um pouco menos precisa do que poderia ser (em comparação com a física real), mas isso não é realmente notável desde que todas as execuções de seu programa sejam imprecisas da mesma maneira .

Agora, tecnicamente falando, é claro que é possível que uma reordenação cause um desvio que chegue a um dígito de maior significado, mas se os desvios são realmente apenas causados ​​por flutuação e seus valores representam quantidades físicas contínuas, isso é extremamente improvável. Observe que existem meio bilhão de doublevalores entre dois single, portanto, pode-se esperar que a grande maioria dos intervalos de tempo na maioria das simulações seja exatamente a mesma entre as execuções da simulação. Os poucos casos em que um desvio passa pela quantização serão esperados em simulações que não duram tanto (pelo menos não com dinâmica caótica).


Também recomendo que você considere a abordagem completamente oposta ao que está perguntando: aceite a incerteza ! Se o comportamento é levemente não determinístico, então isso é realmente mais próximo dos experimentos físicos reais. Então, por que não aleatoriamente deliberadamente os parâmetros de partida para cada execução de simulação e exige que a simulação seja bem - sucedida de maneira consistente em várias tentativas? Isso ensinará muito mais sobre física e sobre como projetar as máquinas para serem robustas / lineares o suficiente, em vez de super-frágeis que são apenas realistas em uma simulação.


Arredondar para baixo não ajudará, porque se o resultado de alta precisão não for determinístico, eventualmente um resultado será arredondado em uma direção em um sistema e na outra em outro sistema. Por exemplo, você sempre pode arredondar para o número inteiro mais próximo, mas um sistema computa 1.0 e o outro calcula 0.9999999999999999999999999999999999999999 e eles arredondam de maneira diferente.
yoyo

Sim, isso é possível, como eu já disse na resposta. Mas isso acontece muito raramente , assim como outras falhas na física dos jogos. Então arredondamento faz ajuda. (Eu não arredondaria para baixo ; arredondar para o mais próximo para evitar
distorções

0

Crie sua própria classe para armazenar números!

Você pode forçar um comportamento determinístico se souber exatamente como os cálculos serão executados. Por exemplo, se as únicas operações com as quais você lida são multiplicação, divisão, adição e subtração, seria suficiente representar todos os números como apenas um número racional. Para fazer isso, uma simples classe Rational funcionaria perfeitamente.

Mas se você quiser lidar com cálculos mais complicados (possivelmente funções trigonométricas, por exemplo), terá que escrever essas funções sozinho. Se você quisesse obter o seno de um número, seria necessário escrever uma função que se aproxima do seno de um número enquanto usa apenas as operações mencionadas acima. Tudo isso é possível e, na minha opinião, contorna muitos dos detalhes cabeludos de outras respostas. A desvantagem é que você terá que lidar com algumas contas.


3
A aritmética racional é totalmente impraticável para qualquer tipo de integração numérica. Mesmo que cada passo no tempo ocorra apenas * / + -, os denominadores se tornarão cada vez maiores ao longo do tempo.
leftaroundabout

Eu esperaria que, mesmo sem considerar a integração, isso não seria uma boa solução, porque, após apenas algumas multiplicações ou divisões, os números que representam seu numerador e denominador estourariam um número inteiro de 64 bits.
jvn91173

0

Há alguma confusão de terminologia aqui. Um sistema físico pode ser completamente determinístico, mas impossível de modelar por um período útil, porque seu comportamento é extremamente sensível às condições iniciais e uma mudança infinitesimalmente pequena nas condições iniciais produzirá comportamentos completamente diferentes.

Aqui está um vídeo de um dispositivo real cujo comportamento é intencionalmente imprevisível, exceto no sentido estatístico:

https://www.youtube.com/watch?v=EvHiee7gs9Y

É fácil construir sistemas matemáticos simples (usando apenas adição e multiplicação) em que o resultado após N etapas depende da n-ésima casa decimal das condições iniciais. Escrever um software para modelar esse sistema de forma consistente, em qualquer hardware e software que o usuário possa ter, é quase impossível - mesmo se você tiver um orçamento grande o suficiente para testar o aplicativo em todas as combinações prováveis ​​de hardware e software.

A melhor maneira de corrigir isso é atacar o problema na sua origem: torne a física do seu jogo o mais determinista possível para obter resultados reproduzíveis.

A alternativa é tentar torná-lo determinístico, aprimorando o software do computador para modelar algo que não é o que a física especificou. O problema é que você introduziu várias camadas de complexidade no sistema, em comparação com a alteração explícita da física.

Como um exemplo específico, suponha que seu jogo envolva colisões de corpos rígidos. Mesmo se você ignorar o atrito, a modelagem exata de colisões entre objetos de formato arbitrário que podem estar girando enquanto se movem é na prática impossível. Mas se você mudar a situação para que os únicos objetos sejam tijolos retangulares não rotativos, a vida se tornará muito mais simples. Se os objetos no seu jogo não parecerem tijolos, oculte esse fato com alguns gráficos "não físicos" - por exemplo, oculte literalmente o instante de colisão atrás de fumaça ou chamas, ou um balão de texto de desenho animado "Ai" como queiras.

O jogador tem que descobrir a física do jogo jogando o jogo. Não importa se não é "totalmente realista" desde que seja autoconsistente e semelhante o suficiente à experiência do senso comum para ser plausível.

Se você faz a própria física se comportar de maneira estável, um modelo de computador dela também pode produzir resultados estáveis, pelo menos no sentido de que erros de arredondamento serão irrelevantes.


1
Não estou vendo nenhuma confusão na terminologia. O OP quer um comportamento determinístico de um sistema potencialmente caótico. Isso é totalmente factível.
Mark

O uso de formas mais simples (como círculos e retângulos) não altera o problema. Você ainda precisa de muitas funções trigonométricas, sqrt, etc ...
jvn91173

-1

Use precisão de ponto flutuante duplo , em vez de precisão de ponto flutuante único . Embora não seja perfeito, é preciso o suficiente para ser considerado determinístico em sua física. Você pode enviar um foguete para a lua com precisão de ponto flutuante duplo, mas não precisão de ponto flutuante único.

Se você realmente precisa de um determinismo perfeito, use a matemática do ponto fixo . Isso fornecerá menos precisão (supondo que você use o mesmo número de bits), mas resultados determinísticos. Não tenho conhecimento de nenhum mecanismo de física que use matemática de ponto fixo; portanto, você pode precisar escrever o seu próprio se quiser seguir esse caminho. (Algo que eu desaconselharia.)


11
A abordagem de precisão dupla colide com o efeito borboleta . Em um sistema dinâmico (como um simulador de física), mesmo um pequeno desvio nas condições iniciais pode amplificar através do feedback, aumentando a neve até um erro perceptível. Tudo o que os dígitos extras fazem é adiar um pouco mais - forçando a bola de neve a rolar um pouco mais antes que ela fique grande o suficiente para causar problemas.
DMGregory

2
Dois erros de uma só vez: 1) Os pontos flutuantes duplos sofrem os mesmos problemas e geralmente adiam o problema para um futuro cada vez mais difícil de depurar. 2) Não existe uma regra que determine que o ponto fixo deve ser menos preciso que o ponto flutuante. Dependendo da escala e do problema em questão, ou da memória que você está pronto para usar por número de ponto fixo, eles podem ser menos precisos, igualmente precisos ou mais precisos. Não faz sentido dizer "eles são menos precisos".
phresnel

@phresnel, como um exemplo de precisão de ponto fixo, o IBM 1400 series usou matemática decimal de ponto fixo de precisão arbitrária. Dedique 624 dígitos a cada número e você excedeu o intervalo e a precisão do ponto flutuante de precisão dupla.
Mark

@phresnel (2) Bom ponto. Atualizei minha resposta para assumir o mesmo número de bits.
Evorlor

-2

Use o padrão Memento .

Na sua execução inicial, salve os dados posicionais de cada quadro ou quaisquer benchmarks necessários. Se isso for muito ruim, faça-o apenas a cada n quadros.

Então, quando você reproduzir a simulação, siga a física arbitrária, mas atualize os dados posicionais a cada n quadros.

Pseudo-código excessivamente simplificado:

function Update():
    if(firstRun) then (SaveData(frame, position));
    else if(reproducedRun) then (this.position = GetData(frame));

9
Eu não acho que isso funcione no caso da OP. Digamos que você e eu estamos jogando o jogo em sistemas diferentes. Cada um de nós coloca as peças do quebra-cabeça da mesma maneira - uma solução que não foi prevista com antecedência pelo desenvolvedor. Quando você clica em "Iniciar", seu PC simula a física, de forma que a solução seja bem-sucedida. Quando faço o mesmo, uma pequena diferença na simulação faz com que minha solução (idêntica) não seja classificada como bem-sucedida. Aqui, não tenho a oportunidade de consultar a lembrança da sua execução bem-sucedida, porque aconteceu na sua máquina, não no tempo de desenvolvimento.
DMGregory

@DMGregory Isso está correto. Obrigado.
jvn91173
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.