简体   繁体   English

为什么 Java 对于矩阵乘法比 C 快?

[英]Why is Java faster than C for matrix multiplication?

I wrote codes for multiplying matrices of huge sizes (such as 2000x2000) in Java and C to benchmark them as an activity.我在 Java 和 C 中编写了用于乘以巨大尺寸(例如 2000x2000)的矩阵的代码,以将它们作为一项活动进行基准测试。 I cannot understand why Java code executes faster than C code...我不明白为什么 Java 代码比 C 代码执行得更快......

Here are the results:以下是结果:

Matrix 1 size: 1000 x 500;矩阵 1 尺寸: 1000 x 500; Matrix 2 size: 500 x 1000矩阵 2 尺寸: 500 x 1000

Time Taken by Java : 13787 ms
Time Taken by C: 20565 ms

Matrix 1 size: 1000 x 1000;矩阵 1 尺寸: 1000 x 1000; Matrix 2 size: 1000 x 1500矩阵 2 尺寸: 1000 x 1500

Time Taken by Java : 64636 ms
Time Taken by C: 65155 ms

Here are the codes I wrote:下面是我写的代码:

In C:在 C:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 10

int main()
{
    // Declaring the variables
    long i, j, k, m1, n1, m2, n2;

    // Reading the dimensions of the matrices
    printf("Enter the row dimension of the matrix 1:\t "); scanf("%ld", &m1);
    printf("Enter the column dimension of the matrix 1:\t "); scanf("%ld", &n1);
    printf("\nEnter the row dimension of the matrix 2:\t "); scanf("%ld", &m2);
    printf("Enter the column dimension of the matrix 2:\t "); scanf("%ld", &n2);

    // Variables used by the clock
    clock_t start, end;
    double cpu_time_used;

    // Necessary condition for matrix multiplication
    if (n1 != m2)
    {
        printf("\nMuliplication is not possible!\n");
        printf("Please check the dimensions of the matrices!\n\n");
    }

    else
    {
        char choice;
        start = clock();                                    // Starts the clock

        long (*mat1)[n1] = malloc(m1 * sizeof *mat1);       // Storing the matrix in heap memory
        if (mat1 == NULL) exit(1);                          // Freeing up space once matrix is NULL
            
        long (*mat2)[n2] = malloc(m2 * sizeof *mat2);
        if (mat2 == NULL) exit(1);
            
        long (*mat3)[n2] = malloc(m1 * sizeof *mat3);
        if (mat3 == NULL) exit(1);

        // Generating matrix with random elements
        for(i=0; i<m1; i++)
            for(j=0; j<n1; j++)
                mat1[i][j] = (long)rand()%MAX;

        // Generating matrix with random elements
        for(i=0; i<m2; i++)
            for(j=0; j<n2; j++)
                mat2[i][j] = (long)rand()%MAX;

    printf("\nMatrices Generated!\n");

        // Initializing the result matrix with zeroes        
        for(i=0; i<m1; i++)
            for(j=0; j<n2; j++)        
                mat3[i][j] = 0;

        // Performing mat1[m1][n1] x mat2[m2][n2] = mat3[m1][n2]
        for (i = 0; i < m1; i++)
            for (j = 0; j < n2; j++)
                for (k = 0; k < m2; k++)
                    mat3[i][j] += mat1[i][k] * mat2[k][j];
        
        // Freeing up space occupied by the matrices after process completion
        free(mat1); free(mat2); free(mat3);

        end = clock();                                                  // Stop the clock timer
        cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;      // Time taken by the program
        printf("\nMultiplication took %f milliseconds to execute.\n\n", cpu_time_used*1000);
    }

    return 0;
}

In Java:在 Java 中:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Matrix {
    private static String s;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Reading the dimensions of matrix 1
        System.out.print("Enter the row dimension of the matrix 1:\t ");
        int m1 = Integer.parseInt(br.readLine());
        System.out.print("Enter the column dimension of the matrix 1:\t ");
        int n1 = Integer.parseInt(br.readLine());

        // Reading the dimensions of matrix 2
        System.out.print("\nEnter the row dimension of the matrix 2:\t ");
        int m2 = Integer.parseInt(br.readLine());
        System.out.print("Enter the column dimension of the matrix 2:\t ");
        int n2 = Integer.parseInt(br.readLine());

        // Print error message if condition not satisfied
        if(n1 != m2) {
            System.out.println("\nMuliplication is not possible!");
            System.out.println("Please check the dimensions of the matrices!\n");
        }

        else {
            long start = System.currentTimeMillis();
            
            // Declaring matrices
            int[][] matrix1 = new int[m1][n1];
            int[][] matrix2 = new int[m2][n2];

            // Generate random matrices
            generateRandom(matrix1);
            generateRandom(matrix2);

            System.out.println("\nMatrices Generated!\n");

            // Performs matrix1 x matrix2 = result
            int[][] result = new int[m1][n2];
            for (int i = 0; i < m1; i++) {
                for (int j = 0; j < n2; j++) {
                    for (int k = 0; k < n1; k++) {
                        result[i][j] += matrix1[i][k] * matrix2[k][j];
                    }
                }
            }
            
            long end = System.currentTimeMillis();
            s = "Execution time is " + (end - start);
            System.out.print(s + " milliseconds.\n\n");
        }
    }

    private static void displayMatrix(int[][] matrix) {
        int r = matrix.length;
        int c = matrix[0].length;

        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    // Generates Random Matrices
    private static void generateRandom(int[][] matrix) {
        int r = matrix.length;
        int c = matrix[0].length;
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                // Gives numbers in range (0,10)
                matrix[i][j] = (int) (Math.random() * 10);
            }
        }
    }
}

I'm running these on Windows 10, with Latest Versions of MinGW and JDK.我在 Windows 10 上运行这些,使用最新版本的 MinGW 和 JDK。

You're comparing oranges to baskets of apples.您正在将橙子与一篮子苹果进行比较。 Did you even take into account that long could be 64 bits whereas Java int is 32 bits.您是否考虑过long可能是64位,而 Java int是 32 位。

Another reason could be that you didn't ask your C compiler to optimize the code.另一个原因可能是您没有要求 C 编译器优化代码。 Java JIT compiler optimizes the code in time, whereas by default GCC does fast compilation producing slow code for easy debugging . Java JIT编译器及时优化代码,而默认情况下GCC 进行快速编译产生慢代码以便于调试 There is no JIT optimization.没有 JIT 优化。 No one ever benchmarks unoptimized code, it is as if testing a Ferrari at 20 mph speed limit.从来没有人对未优化的代码进行基准测试,就好像在 20 英里/小时的限速下测试法拉利一样。

Without any optimizations, I get 3216 milliseconds for Java, 7670 for C for 1000x1000 matrices.在没有任何优化的情况下,对于 Java,我得到 3216 毫秒,对于 1000x1000 矩阵,我得到 C 的 7670 毫秒。 With -O3 C running time drops to 2225 ms.使用 -O3 C 运行时间下降到 2225 毫秒。

But it is still oranges to baskets of apples comparison.但它仍然是橙子与一篮子苹果的比较。 After I change Java to use long[][] then it takes 8300 milliseconds.在我将 Java 更改为使用long[][]之后,它需要 8300 毫秒。

You should compare only multiplication part if you want to find out the matrix multiplication time only... not its creation, generation, multiplication and deletion.如果你只想找出矩阵乘法时间,你应该只比较乘法部分......而不是它的创建,生成,乘法和删除。 Change your code as将您的代码更改为

For C对于 C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 10

int main()
{
    // Declaring the variables
    long i, j, k, m1, n1, m2, n2;

    // Reading the dimensions of the matrices
    printf("Enter the row dimension of the matrix 1:\t "); scanf("%ld", &m1);
    printf("Enter the column dimension of the matrix 1:\t "); scanf("%ld", &n1);
    printf("\nEnter the row dimension of the matrix 2:\t "); scanf("%ld", &m2);
    printf("Enter the column dimension of the matrix 2:\t "); scanf("%ld", &n2);

    // Variables used by the clock
    clock_t start, end;
    double cpu_time_used;

    // Necessary condition for matrix multiplication
    if (n1 != m2)
    {
        printf("\nMuliplication is not possible!\n");
        printf("Please check the dimensions of the matrices!\n\n");
    }

    else
    {
        char choice;
        

        long (*mat1)[n1] = malloc(m1 * sizeof *mat1);       // Storing the matrix in heap memory
        if (mat1 == NULL) exit(1);                          // Freeing up space once matrix is NULL
            
        long (*mat2)[n2] = malloc(m2 * sizeof *mat2);
        if (mat2 == NULL) exit(1);
            
        long (*mat3)[n2] = malloc(m1 * sizeof *mat3);
        if (mat3 == NULL) exit(1);

        // Generating matrix with random elements
        for(i=0; i<m1; i++)
            for(j=0; j<n1; j++)
                mat1[i][j] = (long)rand()%MAX;

        // Generating matrix with random elements
        for(i=0; i<m2; i++)
            for(j=0; j<n2; j++)
                mat2[i][j] = (long)rand()%MAX;

    printf("\nMatrices Generated!\n");

        // Initializing the result matrix with zeroes        
        for(i=0; i<m1; i++)
            for(j=0; j<n2; j++)        
                mat3[i][j] = 0;
       start = clock();                                    // Starts the clock
        // Performing mat1[m1][n1] x mat2[m2][n2] = mat3[m1][n2]
        for (i = 0; i < m1; i++)
            for (j = 0; j < n2; j++)
                for (k = 0; k < m2; k++)
                    mat3[i][j] += mat1[i][k] * mat2[k][j];
        end = clock();                                                  // Stop the clock timer
        cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;      // Time taken by the program
        printf("\nMultiplication took %f milliseconds to execute.\n\n", cpu_time_used*1000);
        // Freeing up space occupied by the matrices after process completion
        free(mat1); free(mat2); free(mat3);

        
    }

    return 0;
}

For Java对于 Java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Matrix {
    private static String s;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Reading the dimensions of matrix 1
        System.out.print("Enter the row dimension of the matrix 1:\t ");
        int m1 = Integer.parseInt(br.readLine());
        System.out.print("Enter the column dimension of the matrix 1:\t ");
        int n1 = Integer.parseInt(br.readLine());

        // Reading the dimensions of matrix 2
        System.out.print("\nEnter the row dimension of the matrix 2:\t ");
        int m2 = Integer.parseInt(br.readLine());
        System.out.print("Enter the column dimension of the matrix 2:\t ");
        int n2 = Integer.parseInt(br.readLine());

        // Print error message if condition not satisfied
        if(n1 != m2) {
            System.out.println("\nMuliplication is not possible!");
            System.out.println("Please check the dimensions of the matrices!\n");
        }

        else {
            
            
            // Declaring matrices
            int[][] matrix1 = new int[m1][n1];
            int[][] matrix2 = new int[m2][n2];

            // Generate random matrices
            generateRandom(matrix1);
            generateRandom(matrix2);

            System.out.println("\nMatrices Generated!\n");
            long start = System.currentTimeMillis();
            // Performs matrix1 x matrix2 = result
            int[][] result = new int[m1][n2];
            for (int i = 0; i < m1; i++) {
                for (int j = 0; j < n2; j++) {
                    for (int k = 0; k < n1; k++) {
                        result[i][j] += matrix1[i][k] * matrix2[k][j];
                    }
                }
            }
            
            long end = System.currentTimeMillis();
            s = "Execution time is " + (end - start);
            System.out.print(s + " milliseconds.\n\n");
        }
    }

    private static void displayMatrix(int[][] matrix) {
        int r = matrix.length;
        int c = matrix[0].length;

        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    // Generates Random Matrices
    private static void generateRandom(int[][] matrix) {
        int r = matrix.length;
        int c = matrix[0].length;
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                // Gives numbers in range (0,10)
                matrix[i][j] = (int) (Math.random() * 10);
            }
        }
    }
}

I have put start and stop time just for matrix multiplication我已经为矩阵乘法设置了开始和停止时间

As far as I know there is no free (or delete ) in Java - it's left to a garbage collector to "clean up" when an object is no longer referenced.据我所知, Java 中没有free (或delete )-当不再引用 object 时,它留给垃圾收集器“清理”。 Exactly when that happens, we can't tell.具体什么时候发生,我们无从得知。 Consequently, your Java code isn't doing exactly the same as your C code as the C code has an explicit free call.因此,您的 Java 代码与您的 C 代码并不完全相同,因为 C 代码具有明确的free调用。 Maybe the compare would be "more fair" if the C code didn't call free while the timer is running.如果 C 代码在计时器运行时没有调用free ,那么比较可能会“更公平”。

Some other notes:其他一些注意事项:

  • Use calloc for mat3 and remove the loop that initializes mat3mat3使用calloc并删除初始化mat3的循环

  • Remove all prints in the code that you are using for time measurement (in both C and Java)删除您用于时间测量的代码中的所有打印件(在 C 和 Java 中)

At least for the C code, you should also add some prints of the result after stopping the timer.至少对于 C 代码,您还应该在停止计时器添加一些结果打印。 This is to prevent a real clever compiler from optimizing all the matrix stuff to "nothing".这是为了防止真正聪明的编译器将所有矩阵内容优化为“无”。 But notice that you can't do that if you call free first.但请注意,如果您先拨打free电话,则无法这样做。

BTW: I take it for granted that you compile the C code with optimization turned on (eg -O3) - if not, it's about time.顺便说一句:我理所当然地认为您在打开优化(例如-O3)的情况下编译 C 代码 - 如果没有,那就是时候了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM