我有一个C ++应用程序,我需要比较两个值并确定哪个更大。唯一的复杂因素是一个数字在日志空间中表示,另一个不在。例如:
double log_num_1 = log(1.23);
double num_2 = 1.24;
如果我想比较num_1
和num_2
,我必须使用log()
或exp()
,我想知道一个人是否比其他(即通常在较短的时间内运行)。您可以假设我正在使用标准cmath
库。
换句话说,以下是语义上等效的,因此速度更快:
if(exp(log_num_1) > num_2)) cout << "num_1 is greater";
或
if(log_num_1 > log(num_2)) cout << "num_1 is greater";
答案 0 :(得分:23)
AFAIK的算法,复杂性是相同的,差异应该只是一个(希望可以忽略不计)的常数。
因此,我会使用exp(a) > b
,因为它不会因无效输入而中断。
答案 1 :(得分:8)
编辑:修改代码以避免exp()溢出。这导致两个功能之间的差距大大缩小。谢谢,fredrikj。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char **argv)
{
if (argc != 3) {
return 0;
}
int type = atoi(argv[1]);
int count = atoi(argv[2]);
double (*func)(double) = type == 1 ? exp : log;
int i;
for (i = 0; i < count; i++) {
func(i%100);
}
return 0;
}
(使用:编译)
emil@lanfear /home/emil/dev $ gcc -o test_log test_log.c -lm
结果似乎很有说服力:
emil@lanfear /home/emil/dev $ time ./test_log 0 10000000
real 0m2.307s
user 0m2.040s
sys 0m0.000s
emil@lanfear /home/emil/dev $ time ./test_log 1 10000000
real 0m2.639s
user 0m2.632s
sys 0m0.004s
令人惊讶的是,日志似乎更快。
纯粹猜测:
或许基础数学taylor series会更快地收敛日志或什么?在我看来,natural logarithm比exponential function更容易计算:
ln(1+x) = x - x^2/2 + x^3/3 ...
e^x = 1 + x + x^2/2! + x^3/3! + x^4/4! ...
不确定c库的功能是否也是这样。但这似乎不太可能。
答案 2 :(得分:7)
你真的需要知道吗?这会占用你运行时间的很大一部分吗?你怎么知道的?
更糟糕的是,它可能取决于平台。什么?
当然,如果你关心的话,测试它,但是花费大量时间在微优化上苦苦挣扎通常是一个坏主意。
答案 3 :(得分:5)
因为您正在处理值&lt;&lt; 1,注意x-1>对于x <1,log(x), 这意味着x-1&lt; log(y)表示log(x)&lt; log(y),已经 无需使用log或exp即可处理1 / e~37%的案例。
答案 4 :(得分:3)
python中的一些快速测试(使用c进行数学运算):
$ time python -c "from math import log, exp;[exp(100) for i in xrange(1000000)]"
real 0m0.590s
user 0m0.520s
sys 0m0.042s
$ time python -c "from math import log, exp;[log(100) for i in xrange(1000000)]"
real 0m0.685s
user 0m0.558s
sys 0m0.044s
表示日志稍慢
编辑:C函数正在被编译器优化,所以循环占用了时间
有趣的是,在C语言中,它们的速度似乎相同(可能出于Mark在评论中提到的原因)
#include <math.h>
void runExp(int n) {
int i;
for (i=0; i<n; i++) {
exp(100);
}
}
void runLog(int n) {
int i;
for (i=0; i<n; i++) {
log(100);
}
}
int main(int argc, char **argv) {
if (argc <= 1) {
return 0;
}
if (argv[1][0] == 'e') {
runExp(1000000000);
} else if (argv[1][0] == 'l') {
runLog(1000000000);
}
return 0;
}
给出时间:
$ time ./exp l
real 0m2.987s
user 0m2.940s
sys 0m0.015s
$ time ./exp e
real 0m2.988s
user 0m2.942s
sys 0m0.012s
答案 5 :(得分:1)
它可能取决于您的libm,平台和处理器。您最好编写一些代码,这些代码会多次调用exp
/ log
,并使用time
调用它几次以查看是否存在明显差异。
两者在我的计算机上基本上都是同一时间(Windows),所以我使用exp
,因为它是为所有值定义的(假设你检查ERANGE
)。但是如果使用log
更自然,那么你应该使用它而不是在没有充分理由的情况下进行优化。
答案 6 :(得分:1)
日志更快是有意义的...... Exp必须执行几次乘法才能得到答案,而log只需将尾数和指数从base-2转换为base-e。
如果您正在使用日志,请务必进行边界检查(正如许多其他人所说)。
答案 7 :(得分:0)
如果您确定这是热点 - 编译器instrinsics是您的朋友。虽然它依赖于平台(如果你在这样的地方寻求性能 - 你不能与平台无关) 所以。问题实际上是 - 哪一个是对目标架构的asm指令 - 以及延迟+周期。如果没有这个,那就是纯粹的猜测。