我正在比较在Java中计算迭代和递归阶乘过程的时间。我正在尝试使用 System.currentTimeMillis
方法来比较每种算法计算所需的时间,但我似乎无法计算差异。我不确定使用此方法的正确方法是什么,但是这里的任何事件都是我试图在代码中实现的:
// ... more code above
System.out.print("Please enter an integer: ");
int integer = readInt();
System.out.println();
// demonstrate recursive factorial and calculate
// how long it took to complete the algorithm
long time1 = System.currentTimeMillis();
int fact1 = factRecursive(integer);
long time2 = System.currentTimeMillis();
System.out.format("Result of recursive factorial %s is %dn", integer, fact1);
System.out.format("Algorithm took %d millisecondsnn", (time2 - time1));
// ... more code below
这是输出:
Please enter an integer: 25
Result of recursive factorial 25 is 2076180480
Algorithm took 0 milliseconds
Result of iterative factorial 25 is 2076180480
Algorithm took 0 milliseconds
显然,我在这里一定做错了什么,因为两种情况下计算阶乘的预期时间不应为零。
编辑:这是我对阶乘的解决方案,如果有人感兴趣(不是特别独特,但无论如何它们都在这里):
// factRecursive uses a recursive algorithm for
// caluclating factorials.
public static long factRecursive(long n)
{
return n = (n == 1)? 1 : n * factRecursive(n - 1);
}
// factIterative uses an iterative algorithm for
// calculating factorials.
public static long factIterative(long n)
{
long product = 1;
if(n == 1) return n;
for(int i = 1; i <= n; ++i)
product *= i;
return product;
}
并且是一些输出。令人惊讶的是,递归版本保持良好。直到39岁左右!迭代版本开始表现明显更好。
Please enter an integer: 39
Result of recursive factorial 39 is 2304077777655037952
Algorithm took 5828 nanoseconds
Result of iterative factorial 39 is 2304077777655037952
Algorithm took 5504 nanoseconds
System.currentTimeMillis()
的分辨率可能会有所不同,具体取决于您的系统;您的算法似乎太快而无法使用此计时器进行测量。
请改用System.nanoTime()
。它的精度也取决于系统,但至少它能够进行高分辨率的时间测量。
实时编译可能会对性能产生很大影响,但大多数虚拟机都需要在重新编译之前多次调用该方法。这使得很难从这种微观基准中获得准确的结果。
一个写得很好的阶乘函数应该在 n = 25 时执行得非常快,所以让它在大约 0 毫秒内运行并不奇怪。 您有三种选择:
- 使用较大的 n。 这将导致阶乘函数花费更长的时间,并为您提供一些要测量的东西。
- 使用 System.nanoTime 以近似纳秒而不是毫秒为单位测量时间。
- 我建议同时做 1 和 2。
正如其他回答者所指出的,你确实在从开始减去结束,这是倒退的。 显然,您也应该解决这个问题。 但这种变化只影响结果的符号,而不影响绝对值。
编辑:只是为了看看找到 25 的阶乘有多快,我写了这个 Python 实现
>>> def fact(n):
... def _fact(n, acc):
... if n == 1:
... return acc
... return _fact(n - 1, n * acc)
... if n < 0:
... return 0 # Or raise an exception
... if n < 2:
... return 1
... return _fact(n, 1)
...
>>> fact(25)
15511210043330985984000000L
>>> import timeit
>>> t = timeit.Timer("fact(25)", "from __main__ import fact")
>>> print t.timeit()
6.2074379921
尽管 Python 是一种没有尾部调用优化的解释型动态类型语言,但带有累加器的简单递归解决方案可以在我的机器上在 6.2 秒内找到fact(25)
一百万次。 因此,平均执行时间为 6.2 微秒。 没有机会以毫秒级时钟精度在单次运行中测量迭代和递归解决方案之间的实质性差异。
你需要做(完成时间 - 开始时间),你把它倒过来。
试试这个:
System.out.format("Algorithm took %d millisecondsnn", (time2 - time1));
非常常见的错误。您应该从时间 2 中减去时间 1。
如果您明智地命名变量(例如startTime
和endTime
,这将有所帮助,这样您就会知道或至少发现您必须endTime - startTime
做endTime
> startTime
看起来您的快速递归可能毕竟没有进行如此繁重的处理。
请改用System.nanoTime()
。它返回纳秒
http://docs.oracle.com/javase/7/docs/api/java/lang/System.html
纳时间()返回正在运行的 Java 虚拟机的高分辨率时间源的当前值(以纳秒为单位)。
另一种测试方法是迭代阶乘,例如 1000 次。 然后将时差除以 1000.00(双精度)
为了获得有意义的定时结果,您需要重复它,并忽略至少前 10,000 次调用方法(因此代码被编译),您需要再运行它 2-10 秒(重复)。