我有两个函数,每个函数都计算两个不同向量的余弦相似度。一种是用 Java 编写的,一种是用 C 编写的。
在这两种情况下,我都声明了两个内联的 200 个元素数组,然后计算它们的余弦相似度 100 万次。我没有计算 jvm 启动的时间。Java 实现比 C 实现慢了近 15 倍。
我的问题是:
1.) 假设对于简单数学的紧密循环,c 仍然比 java 快一个数量级是否合理?
2.) java 代码中是否有一些错误,或者一些合理的优化会大大加快它的速度?
谢谢。
C:
#include <math.h>
int main()
{
int j;
for (j = 0; j < 1000000; j++) {
calc();
}
return 0;
}
int calc ()
{
double a [200] = {0.269852, -0.720015, 0.942508, ...};
double b [200] = {-1.566838, 0.813305, 1.780039, ...};
double p = 0.0;
double na = 0.0;
double nb = 0.0;
double ret = 0.0;
int i;
for (i = 0; i < 200; i++) {
p += a[i] * b[i];
na += a[i] * a[i];
nb += b[i] * b[i];
}
return p / (sqrt(na) * sqrt(nb));
}
$时间./余弦相似度
0m2.952s
爪哇:
public class CosineSimilarity {
public static void main(String[] args) {
long startTime = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
calc();
}
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.format("took %d%n seconds", duration / 1000000000);
}
public static double calc() {
double[] vectorA = new double[] {0.269852, -0.720015, 0.942508, ...};
double[] vectorB = new double[] {-1.566838, 0.813305, 1.780039, ...};
double dotProduct = 0.0;
double normA = 0.0;
double normB = 0.0;
for (int i = 0; i < vectorA.length; i++) {
dotProduct += vectorA[i] * vectorB[i];
normA += Math.pow(vectorA[i], 2);
normB += Math.pow(vectorB[i], 2);
}
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
}
}
$ java -cp 。-server -Xms2G -Xmx2G CosineSimilarity
耗时 44 秒
编辑:
Math.pow 确实是罪魁祸首。删除它使性能与 C 的性能相当。