【问题标题】:Difference in time complexity in array addressing in JavaJava中数组寻址的时间复杂度差异
【发布时间】:2011-11-30 23:57:27
【问题描述】:

所以我在编码涉及时间复杂度的图像处理函数时有一个随机问题。以下是我原来的sn-p代码:

    long start = System.currentTimeMillis();

    for (int i = 0; i < newWidth; i++) {
        for (int j = 0; j < newHeight; j++) {

            double x = i * scaleX;
            double y = j * scaleY;

            double xdiff = x - (int) x;
            double ydiff = y - (int) y;

            int xf = (int) Math.floor(x);
            int xc = (int) Math.ceil(x);
            int yf = (int) Math.floor(y);
            int yc = (int) Math.ceil(y);

            double out = inputArray[xf][yf] * (1 - xdiff) * (1 - ydiff)
                    + inputArray[xc][yf] * xdiff * (1 - ydiff)
                    + inputArray[xf][yc] * (1 - xdiff) * ydiff
                    + inputArray[xc][yc] * xdiff * ydiff;

            outputArray[i][j] = (int) out;
        }
    }

    long elapsed = System.currentTimeMillis() - start;
    System.out.println("Time used: " + elapsed);

在编写完该代码后,我想知道不为下限和上限值创建 4 个临时变量是否会更快,而是直接在数组索引中计算它们。所以我这样修改:

    long start = System.currentTimeMillis();

    for (int i = 0; i < newWidth; i++) {
        for (int j = 0; j < newHeight; j++) {

            double x = i * scaleX;
            double y = j * scaleY;

            double xdiff = x - (int) x;
            double ydiff = y - (int) y;

            double out = inputArray[(int) Math.floor(x)][(int) Math.floor(y)] * (1 - xdiff) * (1 - ydiff)
                    + inputArray[(int) Math.ceil(x)][(int) Math.floor(y)] * xdiff * (1 - ydiff)
                    + inputArray[(int) Math.floor(x)][(int) Math.ceil(y)] * (1 - xdiff) * ydiff
                    + inputArray[(int) Math.ceil(x)][(int) Math.ceil(y)] * xdiff * ydiff;

            outputArray[i][j] = (int) out;
        }
    }

    long elapsed = System.currentTimeMillis() - start;
    System.out.println("Time used: " + elapsed);

我原以为后者会更快(因为您不必写入临时变量然后访问它),但事实证明后者至少比之前的代码慢 2.5 倍。使用的测试用例是 1024x768 图像的 3 倍缩放。

旧代码:使用时间:812 后来的代码:使用时间:2140

那么造成时差的原因是什么?

【问题讨论】:

    标签: java time complexity-theory


    【解决方案1】:

    您可以简单地将 double 转换为 int,而不是使用 Math.floor()。它会更快。

    代替:

    inputArray[(int) Math.floor(x)]
    

    只是:

    inputArray[(int) x]
    

    【讨论】:

      【解决方案2】:

      与 Math.floor 和 Math.ceil 相比,保存和查找局部变量的微小操作相形见绌。此外,您在第二个 sn-p 中更频繁地转换为 int。

      【讨论】:

        【解决方案3】:

        问:在第一种情况下,您调用了多少次“floor”和“ceil”?第二种情况? ;)

        问:我想知道这是否会比第一种情况运行得更快:

            long start = System.currentTimeMillis();
        
            for (int i = 0; i < newWidth; i++) {
                double x = i * scaleX;
                double xdiff = x - (int) x;
                int xf = (int) Math.floor(x);
                int xc = (int) Math.ceil(x);
                for (int j = 0; j < newHeight; j++) {
                    double y = j * scaleY;
                    double ydiff = y - (int) y;
        
                    int yf = (int) Math.floor(y);
                    int yc = (int) Math.ceil(y);
        
                    double out = inputArray[xf][yf] * (1 - xdiff) * (1 - ydiff)
                            + inputArray[xc][yf] * xdiff * (1 - ydiff)
                            + inputArray[xf][yc] * (1 - xdiff) * ydiff
                            + inputArray[xc][yc] * xdiff * ydiff;
        
                    outputArray[i][j] = (int) out;
                }
            }
        
            long elapsed = System.currentTimeMillis() - start;
            System.out.println("Time used: " + elapsed);
        

        【讨论】:

        • 一个更好的解决方案是在开始循环之前预先计算一个长度为 newHeight 的查找数组,其中包含所有 Y 下限和上限值。这将节省大量的ceilfloor 调用。
        • 该死!很显着的提高!!现在可以在 328 毫秒内完成!
        【解决方案4】:

        后者可能会更慢,因为它做更多的工作。设置一个临时变量很简单,但计算 floor 和 ceil 可能会非常昂贵。

        顺便说一句:当 x 为正时,(int) Math.floor(x)(int) x 相同,因此您无需计算两次。

        此外,您可以假设 xc = xf + 1 在这种情况下和 y 类似

        【讨论】:

        • 真,(int) Math.floor(x) 与 (int) x 相同
        • 所以你只需要为xy计算一次
        【解决方案5】:

        在第二个中,您正在重复计算。通过在第一个示例中将其捕获到变量中,您可以避免重复计算。

        【讨论】:

          【解决方案6】:

          后面的代码中有 8 个 Math.floor() / Math.ceil() 计算,而不是 4 个。这就是问题所在。

          计算比为局部变量分配空间要慢得多。

          【讨论】:

          • 正确。分配局部变量几乎是免费的,因为它们在堆栈上。分配基本上是将堆栈指针增加变量的大小。
          【解决方案7】:

          floorceil 有性能成本。

          您的第二个案例调用他们的频率是两倍。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-24
            • 1970-01-01
            • 1970-01-01
            • 2015-11-17
            • 2013-07-23
            • 2018-12-05
            相关资源
            最近更新 更多