[英]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 mat3
对
mat3
使用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.