[英]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.