Расчеты Java / Processing, возвращающие "NaN" и "Infinity" - PullRequest
1 голос
/ 12 июля 2020

Я пытаюсь симулировать задачу трех тел в Processing / Java. Я создал объект Pl anet и определил несколько функций для расчета притяжения, сил и скорости планет. Программа работает без ошибок. Загвоздка в том, что вычисления возвращают выходные данные Infinity и NaN. Я не нашел ни одной ошибки деления на ноль. Почему он это делает?

float simulationTime = 0.01;
float earthMass = pow(10,24)*5.972;

Planet[] bodies = {new Planet(100,200, 0, 0,earthMass/2),
                   new Planet(400,500, 0, 0,earthMass/2),
                   new Planet(800,200, 0, 0,earthMass/2)};
int size = 500;
float G = 6.674*pow(10, -11);
float gravAttract(float mass1, float mass2, float x1, float y1, float x2, float y2) {
  float force = G*mass1*mass2/pow(dist1(x1, y1, x2, y2), 2);
  //println(pow(dist1(x1, y1, x2, y2), 2));
  //println(force);
  return force;
}
float attract(Planet one,Planet two){
  float force = G*one.mass*two.mass/pow(dist1(one.xpos,one.ypos,two.xpos,two.ypos),2);
  println(one.xpos,two.xpos,one.xspeed,two.xspeed);
  return force;
}
float[] forceXY(int body){
  float[] xy = {0,0};
  for (int ii = 0; ii<bodies.length; ii = ii+1){
    if (ii == body){
      continue;
    }
    else{
      xy[0] = xy[0]+attract(bodies[body],bodies[ii])*
      (bodies[ii].xpos-bodies[body].xpos)/dist1(bodies[body].xpos,bodies[body].ypos,bodies[ii].xpos,bodies[ii].ypos);
      xy[1] = xy[1]+attract(bodies[body],bodies[ii])*
      (bodies[ii].ypos-bodies[body].ypos)/dist1(bodies[body].xpos,bodies[body].ypos,bodies[ii].xpos,bodies[ii].ypos);
      println(xy);
    }
  }
  return xy;
}
float dist1(float x1,float y1,float x2,float y2){
  float x = dist(x1,y1,x2,y2);
  x = x*149.6*pow(10,7);
  //println(x1,y1,x2,y2);
  return x;
}
class Planet {
  float xpos;
  float ypos;
  float xspeed;
  float yspeed;
  float mass;

  Planet(float a, float b, float c, float d, float e) {
    xpos = a;
    ypos = b;
    xspeed = c;
    yspeed = d;
    mass = e;
  }
  void update(float xforce, float yforce) {
    //println("xy",xpos,ypos);
    float xa = xforce/mass;
    float ya = yforce/mass;
    xspeed = xspeed + xa*simulationTime;
    yspeed = yspeed + ya*simulationTime;
    xpos = xpos + xspeed*simulationTime;
    ypos = ypos + yspeed*simulationTime;
  }
}
void setup() {
  size(1000, 1000);
  frameRate(1);
}
void draw() {
  background(0);
  
  for (int ii = 0; ii < bodies.length; ii = ii+1){
    float[] asdf = new float[2];
    asdf = forceXY(ii);
    circle(bodies[ii].xpos,bodies[ii].ypos,10);
    bodies[ii].update(asdf[0],asdf[1]);
  }
}

1 Ответ

1 голос
/ 12 июля 2020

Я вижу, вы пытаетесь делать расчеты, используя реальные физические значения. Проблема в том, что астрономические массы, расстояния и силы астрономические не только буквально, но и образно. Числа настолько велики, что результаты промежуточных вычислений не могут быть представлены с использованием ограниченного диапазона типа данных float.

Решение состоит в том, чтобы изменить единицы измерения. Например, вместо метров, килограммов и секунд измеряйте расстояние в «астрономических единицах» (расстояние между Землей и Солнцем), массу в кратных массах Земли и время в годах. Или воспользуйтесь стандартной «астрономической системой единиц» . Что наиболее важно, это изменяет значение гравитационной постоянной G.

Если вы не слишком привязаны к созданию симуляции, которая позволяет вам предсказывать реальное положение планет, гораздо проще просто «управлять им». и установите G = 1, установите массы на малые числа и поиграйте со скоростями. Вы увидите, что очень легко создать реалистичную c симуляцию.

...