点集合之间的快速插值

时间:2014-04-30 10:17:29

标签: java performance

我用Java建立了太阳系的模型。为了确定行星的位置,它确实进行了大量的计算,这些计算给出了非常精确的值。但是我经常对大致的位置感到满意,如果这样可以让它变得更快。因为我以模拟速度使用它很重要,因为行星的位置将被要求数百万次。

目前我尝试在整个轨道上缓存行星的位置,然后一遍又一遍地使用这些坐标。如果请求两个值之间的位置,则执行线性插值。这就是我存储值的方式:

for(int t=0; t<tp; t++) {
    listCoordinates[t]=super.coordinates(ti+t);
}

interpolator = new PlanetOrbit(listCoordinates,tp);

PlanetOrbit有插值代码:

package cometsim;

import org.apache.commons.math3.util.FastMath;

public class PlanetOrbit {

    final double[][] coordinates;
    double tp;

    public PlanetOrbit(double[][] coordinates, double tp) {
        this.coordinates = coordinates;
        this.tp = tp;
    }

    public double[] coordinates(double julian) {
        double T = julian % FastMath.floor(tp);

        if(coordinates.length == 1 || coordinates.length == 0) return coordinates[0];

        if(FastMath.round(T) == T) return coordinates[(int) T];

        int floor = (int) FastMath.floor(T);

        if(floor>=coordinates.length) floor=coordinates.length-5;

        double[] f = coordinates[floor];
        double[] c = coordinates[floor+1];

        double[] retval = f;
        retval[0] += (T-FastMath.floor(T))*(c[0]-f[0]);
        retval[1] += (T-FastMath.floor(T))*(c[1]-f[1]);
        retval[2] += (T-FastMath.floor(T))*(c[2]-f[2]);

        return retval;
    }
}

您可以将FastMath视为Math但速度更快。但是,这个代码与每次计算精确值相比并没有太大的速度提升。您对如何加快速度有任何想法吗?

1 个答案:

答案 0 :(得分:1)

我可以看到一些问题,我能看到的主要问题如下

  • PlanetOrbit#coordinates似乎实际上更改了变量coordinates中的值。因为这个方法只能进行插值,所以我希望你的轨道每次运行时都会略微损坏(因为它是一个线性插值,轨道实际上会向它的中心降级)。
  • 你做了几次同样的事情,最清楚的是T-FastMath.floor(T)在代码中出现了3个单独的时间。
  • 不是效率或准确性的问题,但变量和方法名称非常不透明,使用真实的单词作为变量名称。

我建议的方法如下

public double[] getInterpolatedCoordinates(double julian){ //julian calendar? This variable name needs to be something else, like day, or time, or whatever it actually means
    int startIndex=(int)julian;
    int endIndex=(startIndex+1>=coordinates.length?1:startIndex+1); //wrap around

    double nonIntegerPortion=julian-startIndex;


    double[] start = coordinates[startIndex];
    double[] end = coordinates[endIndex];

    double[] returnPosition= new double[3];

    for(int i=0;i< start.length;i++){
        returnPosition[i]=start[i]*(1-nonIntegerPortion)+end[i]*nonIntegerPortion;
    }
    return returnPosition;
}

这可以避免破坏坐标数组并避免多次重复同一楼层(1-nonIntegerPortion仍然会进行多次,如果需要可以删除,但我希望分析会显示它并不重要)。但是,它确实每次创建一个新的double [],如果你只需要临时的数组,效率可能会很低。这可以使用商店对象(您以前使用但不再需要的对象,通常来自前一个循环)来纠正

public double[] getInterpolatedCoordinates(double julian, double[] store){
    int startIndex=(int)julian;
    int endIndex=(startIndex+1>=coordinates.length?1:startIndex+1); //wrap around

    double nonIntegerPortion=julian-startIndex;


    double[] start = coordinates[startIndex];
    double[] end = coordinates[endIndex];

    double[] returnPosition= store;

    for(int i=0;i< start.length;i++){
        returnPosition[i]=start[i]*(1-nonIntegerPortion)+end[i]*nonIntegerPortion;
    }
    return returnPosition; //store is returned
}