簡體   English   中英

為什么 Java 對於矩陣乘法比 C 快?

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

我在 Java 和 C 中編寫了用於乘以巨大尺寸(例如 2000x2000)的矩陣的代碼,以將它們作為一項活動進行基准測試。 我不明白為什么 Java 代碼比 C 代碼執行得更快......

以下是結果:

矩陣 1 尺寸: 1000 x 500; 矩陣 2 尺寸: 500 x 1000

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

矩陣 1 尺寸: 1000 x 1000; 矩陣 2 尺寸: 1000 x 1500

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

下面是我寫的代碼:

在 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;
}

在 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);
            }
        }
    }
}

我在 Windows 10 上運行這些,使用最新版本的 MinGW 和 JDK。

您正在將橙子與一籃子蘋果進行比較。 您是否考慮過long可能是64位,而 Java int是 32 位。

另一個原因可能是您沒有要求 C 編譯器優化代碼。 Java JIT編譯器及時優化代碼,而默認情況下GCC 進行快速編譯產生慢代碼以便於調試 沒有 JIT 優化。 從來沒有人對未優化的代碼進行基准測試,就好像在 20 英里/小時的限速下測試法拉利一樣。

在沒有任何優化的情況下,對於 Java,我得到 3216 毫秒,對於 1000x1000 矩陣,我得到 C 的 7670 毫秒。 使用 -O3 C 運行時間下降到 2225 毫秒。

但它仍然是橙子與一籃子蘋果的比較。 在我將 Java 更改為使用long[][]之后,它需要 8300 毫秒。

如果你只想找出矩陣乘法時間,你應該只比較乘法部分......而不是它的創建,生成,乘法和刪除。 將您的代碼更改為

對於 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;
}

對於 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);
            }
        }
    }
}

我已經為矩陣乘法設置了開始和停止時間

據我所知, Java 中沒有free (或delete )-當不再引用 object 時,它留給垃圾收集器“清理”。 具體什么時候發生,我們無從得知。 因此,您的 Java 代碼與您的 C 代碼並不完全相同,因為 C 代碼具有明確的free調用。 如果 C 代碼在計時器運行時沒有調用free ,那么比較可能會“更公平”。

其他一些注意事項:

  • mat3使用calloc並刪除初始化mat3的循環

  • 刪除您用於時間測量的代碼中的所有打印件(在 C 和 Java 中)

至少對於 C 代碼,您還應該在停止計時器添加一些結果打印。 這是為了防止真正聰明的編譯器將所有矩陣內容優化為“無”。 但請注意,如果您先撥打free電話,則無法這樣做。

順便說一句:我理所當然地認為您在打開優化(例如-O3)的情況下編譯 C 代碼 - 如果沒有,那就是時候了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM