我知道Math.sin()
和Math.cos()
函数,但我想知道是否有一种方法可以创建(或使用已经存在的)更快的函数,因为我没有关心准确的准确性。我正在寻求执行基本的sin或cos计算,并使其基本上尽可能快地执行。简单地迭代西格玛几次会比Math.sin()
快?
答案 0 :(得分:7)
由于您不太关心准确性将其存储在预先计算或仅计算一次的表中,因此当我想避免调用Math
时,这就是我所做的事情。
粗略
public class CosSineTable {
double[] cos = new double[361];
double[] sin = new double[361];
private static CosSineTable table = new CosSineTable();
private CosSineTable() {
for (int i = 0; i <= 360; i++) {
cos[i] = Math.cos(Math.toRadians(i));
sin[i] = Math.sin(Math.toRadians(i));
}
}
public double getSine(int angle) {
int angleCircle = angle % 360;
return sin[angleCircle];
}
public double getCos(int angle) {
int angleCircle = angle % 360;
return cos[angleCircle];
}
public static CosSineTable getTable() {
return table;
}
}
我将循环和方法的优化留给你。
答案 1 :(得分:6)
预先计算的表格是要走的路。这是一个实现:
static final int precision = 100; // gradations per degree, adjust to suit
static final int modulus = 360*precision;
static final float[] sin = new float[modulus]; // lookup table
static {
// a static initializer fills the table
// in this implementation, units are in degrees
for (int i = 0; i<sin.length; i++) {
sin[i]=(float)Math.sin((i*Math.PI)/(precision*180));
}
}
// Private function for table lookup
private static float sinLookup(int a) {
return a>=0 ? sin[a%(modulus)] : -sin[-a%(modulus)];
}
// These are your working functions:
public static float sin(float a) {
return sinLookup((int)(a * precision + 0.5f));
}
public static float cos(float a) {
return sinLookup((int)((a+90f) * precision + 0.5f));
}
在我的笔记本电脑上,这些速度比Math.sin
快约6倍。
我只使用了一张表 - 将余弦变成正弦的成本并不明显。
我使用了浮点数,假设你在计算中可能会使用浮点数,因为你对性能的偏好超过了精度。这里没有太大区别,因为瓶颈实际上只是数组查找。
以下是我的基准:
public static void main(String[] args) {
int reps = 1<<23;
int sets = 4;
Q.pl(" Trial sinTab cosTab sinLib");
for(int i = 0; i<sets; i++) {
Q.pf("%7d\t%7.2f\t%7.2f\t%7.2f\n", i, testSinTab(reps), testCosTab(reps), testSinLib(reps));
}
}
private static float[] sample(int n) {
Random rand = new Random();
float[] values = new float[n];
for (int i=0; i<n; i++) {
values[i] = 400*(rand.nextFloat()*2-1);
}
return values;
}
private static float testSinTab(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = sin(sample[i]);
}
time += System.nanoTime();
return (time/1e6f);
}
private static float testCosTab(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = cos(sample[i]);
}
time += System.nanoTime();
return time/1e6f;
}
private static float testSinLib(int n) {
float[] sample = sample(n);
long time = -System.nanoTime();
for (int i=0; i<n; i++) {
sample[i] = (float) Math.sin(sample[i]);
}
time += System.nanoTime();
return time/1e6f;
}
输出:
Trial sinTab cosTab sinLib
0 102.51 111.19 596.57
1 93.72 92.20 578.22
2 100.06 107.20 600.68
3 103.65 102.67 629.86
答案 2 :(得分:3)
你可以试试 http://sourceforge.net/projects/jafama/
它使用查找表,因此它可能实际上更慢 比数学,特别是如果表经常从CPU缓存中逐出, 但对于数以千计的连续呼叫,它可能会更快。
在课堂加载期间它似乎也慢了(也许JIT还没有开始), 所以你可能想在那个特定的用例中避免使用它。
答案 3 :(得分:0)
我知道这个问题很老,但我认为这是最快的java实现,可以精确到65536个元素。
public class MathHelper {
private static double[] a = new double[65536];
public static final double sin(float f) {
return a[(int) (f * 10430.378F) & '\uffff'];
}
public static final double cos(float f) {
return a[(int) (f * 10430.378F + 16384.0F) & '\uffff'];
}
static {
for (int i = 0; i < 65536; ++i) {
a[i] = Math.sin((double) i * 3.141592653589793D * 2.0D / 65536.0D);
}
}
}
来源:https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/MathHelper.java