使用Python进行实际值轨道仿真的数字太大了?

时间:2015-06-02 01:58:02

标签: python python-3.x

我尝试使用真实值进行重力模拟,但是当我尝试将真实值放入时,我会收到一条错误,上面写着" OverflowError:Python int太大而无法转换为C长"

这些数值与太阳质量(1.98e + 30 kg)一样大 - 我认为这并不是那么大(我希望今年晚些时候用Python进行黑洞模拟)。我试图在Python 2.7和Python 3.4上运行代码,但遗憾的是没有用。

我已经做了一些搜索我发现大多数人在使用大xrange的方法时都会遇到这个错误,事实并非如此(我使用的唯一xrange是最大荣耀0到1)和程序适用于少量质量。

我能做些什么吗?或者Python无法处理这些值(我觉得这不太可能)?

整个Traceback是这样的:

Traceback (most recent call last):
  File "Orbit2.py", line 166, in <module>
    main()
  File "Orbit2.py", line 155, in main
    pygame.draw.circle(win, (255, 255, 255), (int(WIDTHD2+zoom*WIDTHD2*(p._est._x-WIDTHD2)/WIDTHD2),int(HEIGHTD2+zoom*HEIGHTD2*(p._est._y-HEIGHTD2)/HEIGHTD2)),int(p._r*zoom), 0)
OverflowError: Python int too large to convert to C long

如果它有助于整个代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import pygame
import math
from collections import defaultdict

# Tamanho da janela
WIDTH, HEIGHT = 900, 600
WIDTHD2, HEIGHTD2 = WIDTH/2., HEIGHT/2.

# Número de planetas
PLANETAS=1

# Constante gravitacional
GRAVCONST = 6.67384e-11

# Densidade média dos planetas
DENSIDADE = 0.001

# Lista global de planetas
g_listaDePlanetas = []

class Estado:
    """ Classe que representa a posição e velocidade. """
    def __init__(self, x, y, vx, vy):
        self._x, self._y, self._vx, self._vy = x, y, vx, vy

    def __repr__(self):
        return 'x:{x} y:{y} vx:{vx} vy:{vy}'.format(x=self._x, y=self._y, vx=self._vx, vy=self._vy)

class Derivada:
    """ Classe que representa a velocidade e aceleração. """
    def __init__(self, dx, dy, dvx, dvy):
        self._dx, self._dy, self._dvx, self._dvy = dx, dy, dvx, dvy 

    def __repr__(self):
        return 'dx:{dx} dy:{dy} dvx:{dvx} dvy:{dvy}'.format(dx=self._dx, dy=self._dy, dvx=self._dvx, dvy=self._dvy) 

class Planeta:
    """ Classe que representa um planeta. A parte "_est" significa "Estado", que carrega
    a posição e a velocidade do planeta. Enquanto "_m" representa a massa."""
    def __init__(self):
        self._est = Estado (150, 300, 0, 2)
        self._r = 1.5
        self._m = 5.97e24

    def __repr__(self):
        return repr(self._est)

    def aceleracao(self, estado, un_t):
        """ Calcula a aceleração causada por outro planeta neste."""
        ax = 0.0
        ay = 0.0

        for p in g_listaDePlanetas:
            if p is self:
                continue
            dx = p._est._x - estado._x
            dy = p._est._y - estado._y
            dsq = dx*dx + dy*dy # distância quadratica
            dr = math.sqrt(dsq) # distância 
            forca = GRAVCONST*self._m*p._m/dsq

            ax += forca*dx/dr
            ay += forca*dy/dr
        return (ax, ay)

    def iniDerivada(self, estado, t):
        """ Parte do método de Runge-Kutta. """
        ax, ay = self.aceleracao(estado, t)
        return Derivada(estado._vx, estado._vy, ax, ay)

    def proxDerivada(self, iniEstado, derivada, t, dt):
        """ Parte do método de Runge-Kutta. """
        estado = Estado(0.0, 0.0, 0.0, 0.0)
        estado._x = iniEstado._x + derivada._dx*dt
        estado._y = iniEstado._y + derivada._dy*dt
        estado._vx = iniEstado._vx + derivada._dvx*dt
        estado._vy = iniEstado._vy + derivada._dvy*dt
        ax, ay = self.aceleracao(estado, t+dt)
        return Derivada(estado._vx, estado._vy, ax, ay)

    def atualizarPlaneta(self, t, dt):
        """ Solução de Runge-Kutta de quarta ordem para pos/vel do planeta. """
        k1 = self.iniDerivada(self._est, t)
        k2 = self.proxDerivada(self._est, k1, t, dt*0.5)
        k3 = self.proxDerivada(self._est, k2, t, dt*0.5)
        k4 = self.proxDerivada(self._est, k3, t, dt)
        dxdt = 1.0/6.0 * (k1._dx + 2.0*(k2._dx + k3._dx) + k4._dx)
        dydt = 1.0/6.0 * (k1._dy + 2.0*(k2._dy + k3._dy) + k4._dy)
        dvxdt = 1.0/6.0 * (k1._dvx + 2.0*(k2._dvx + k3._dvx) + k4._dvx)
        dvydt = 1.0/6.0 * (k1._dvy + 2.0*(k2._dvy + k3._dvy) + k4._dvy)
        self._est._x += dxdt*dt
        self._est._y += dydt*dt
        self._est._vx += dvxdt*dt
        self._est._vy += dvydt*dt

    def massaFromRaio(self):
        """ A partir de _r define _m. """
        self._m = DENSIDADE*4.*math.pi*(self._r**3.)/3.

    def raioFromMassa(self):
        """ A partir de _m define _r. """
        self._r = (3.*self._m/(DENSIDADE*4.*math.pi))**(0.3333)

def main():
    pygame.init()
    win=pygame.display.set_mode((WIDTH, HEIGHT))

    keysPressed = defaultdict(bool)

    def ScanKeyboard():
        while True:
            evt = pygame.event.poll()
            if evt.type == pygame.NOEVENT:
                break
            elif evt.type in [pygame.KEYDOWN, pygame.KEYUP]:
                keysPressed[evt.key] = evt.type == pygame.KEYDOWN

    global g_listaDePlanetas, PLANETAS

    g_listaDePlanetas = []

    for i in xrange(0, PLANETAS):
        g_listaDePlanetas.append(Planeta())

    sol = Planeta()
    # Centraliza o sol na tela
    sol._est._x, sol._est._y = WIDTHD2, HEIGHTD2
    sol._est._vx = sol._est._vy = 0.0
    sol._m = 1.989e30 # Massa do sol
    sol._r = 3.5
    #sol.raioFromMassa()

    g_listaDePlanetas.append(sol)

    t, dt = 0.0, 1.0

    zoom = 1.0

    bClearScreen = True

    pygame.display.set_caption("Simulador de órbitas RK-4")

    while True:
        t += dt
        pygame.display.flip()
        if bClearScreen:  # Mostrar orbitas ou não
            win.fill((0, 0, 0))
        win.lock()
        for p in g_listaDePlanetas:
             pygame.draw.circle(win, (255, 255, 255), (int(WIDTHD2+zoom*WIDTHD2*(p._est._x-WIDTHD2)/WIDTHD2),int(HEIGHTD2+zoom*HEIGHTD2*(p._est._y-HEIGHTD2)/HEIGHTD2)),int(p._r*zoom), 0)
        win.unlock()
        ScanKeyboard()

        for p in g_listaDePlanetas:
            p.atualizarPlaneta(t, dt)

        if keysPressed[pygame.K_ESCAPE]:
            break

if __name__ == "__main__":
    main()

1 个答案:

答案 0 :(得分:0)

首先,您需要了解不同类型的合法值范围。 largest int on most system is 9.2e186.2.6.2p2。在大多数代码中,您使用的是浮点数,因此这不是问题。但是,你可以在你发布的堆栈跟踪中看到你遇到了麻烦:

pygame.draw.circle(win, (255, 255, 255), (int(WIDTHD2+zoom*WIDTHD2*(p._est._x-WIDTHD2)/WIDTHD2),int(HEIGHTD2+zoom*HEIGHTD2*(p._est._y-HEIGHTD2)/HEIGHTD2)),int(p._r*zoom), 0)

我没有跟踪你发布的所有代码,以确定在那里计算的是什么或为什么,但是可以说,对int()的两个调用中的一个是计算一些非常大的值并且试图将它转换为int,这是行不通的。我猜测如果你画圈子,这不是你代码的核心部分(但是我再没有跟踪代码或试着将评论翻译成英文) - 我猜这只是为了可视化。如果是这样,我建议将这些缩小到更小,更小。如果你缩放所有内容,它在屏幕上应该看起来一样,但你可以在你需要的地方使用整数数学。