正确使用Java System.currentTimeMillis()方法?

时间:2012-04-11 01:14:13

标签: java factorial language-concepts

我正在比较在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 %d\n", integer, fact1);
System.out.format("Algorithm took %d milliseconds\n\n", (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

显然,我必须在这里做错事,因为计算两种情况下的因子的预计时间不应该为零。

编辑:以下是我对factorial的解决方案,如果有人感兴趣(不是特别独特,但无论如何都是这样):

// 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

6 个答案:

答案 0 :(得分:4)

System.currentTimeMillis()的分辨率可能会有所不同,具体取决于您的系统;您的算法似乎太快,无法使用此计时器进行测量。

请改用System.nanoTime()。它的精度也取决于系统,但至少它能够进行高分辨率的时间测量。

即时编译会对性能产生很大影响,但大多数虚拟机需要在重新编译之前多次调用方法。这使得很难从这种微观基准中获得准确的结果。

答案 1 :(得分:3)

一个写得很好的因子函数应该在n = 25时非常快地执行,因此让它在大约0ms内运行并不是非常令人惊讶。您有三种选择:

  1. 使用更大的n。这将导致阶乘函数花费更长的时间,并为您提供一些衡量标准。
  2. 使用System.nanoTime
  3. 以大约纳秒而不是毫秒来测量时间
  4. 我建议同时执行1和2。
  5. 正如其他回答者所指出的那样,你确实从开始减去了结束,这是倒退。显然,你也应该解决这个问题。但是这种变化只会影响结果的符号,而不会影响绝对值。


    编辑:为了看看找到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微秒。没有机会在毫秒时钟精度的单次运行中测量迭代和递归解决方案之间的实质差异。

答案 2 :(得分:1)

你需要做(完成时间 - 开始时间),你需要向后。

试试这个:

System.out.format("Algorithm took %d milliseconds\n\n", (time2 - time1));

答案 3 :(得分:1)

非常常见的错误。你应该从time2中减去time1。

如果您明确命名变量会有所帮助 - 例如startTimeendTime,这样您就会知道或至少发现您必须endTime - startTime作为endTime &GT; startTime

答案 4 :(得分:1)

看起来你的快速递归可能不会做这么重的处理。

请改用System.nanoTime()。它返回纳秒秒

http://docs.oracle.com/javase/7/docs/api/java/lang/System.html

nanoTime() 返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。


另一种测试方法是迭代你的阶乘1000次。然后将时差除以1000.00(双倍)

答案 5 :(得分:0)

要获得有意义的定时结果,您需要重复它,并忽略,至少前一次调用方法10,000次(因此编译代码)并且您需要再运行2-10秒(重复)。