我知道Math.sin()
andMath.cos()
函数,但我想知道是否有一种方法可以创建(或使用已经存在的)更快的函数,因为我不关心精确度。我正在寻找执行基本的 sin 或 cos 计算,并让它尽可能快地执行。简单地迭代 sigma 几次会比 sigma 快Math.sin()
吗?
问问题
11104 次
4 回答
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;
}
}
我把循环和方法的优化留给你。
于 2013-06-05T02:35:30.573 回答
7
预先计算好的表格是要走的路。这是一个实现:
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
.
我只使用了一张表——将余弦转换为正弦的成本并不是很明显。
我使用浮点数,假设您可能会在计算中使用浮点数,因为您更喜欢性能而不是精度。这里没有太大区别,因为瓶颈实际上只是数组查找。
这是我的基准:
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
于 2013-06-05T07:46:54.083 回答
2
你可以试试 http://sourceforge.net/projects/jafama/
它使用查找表,因此它实际上可能比 Math 慢,特别是如果表经常从 CPU 缓存中逐出,但对于数千次连续调用,它可能会更快。
在类加载期间它似乎也更慢(也许 JIT 那时还没有启动),所以你可能希望在那个特定的用例中避免它。
于 2013-06-06T19:01:56.067 回答
-1
我知道这个问题很老,但我认为它是最快的 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
于 2017-08-27T17:47:24.943 回答