java code
public class Test {
public static void main(String[] args) {
final int n=1000;
final int m=1000;
final int p=1000;
final long startDate = System.currentTimeMillis();
final double[] A = new double[n*m];
final double[] B = new double[m*p];
final double[] C = new double[n*p];
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
A[i*m+j]=Math.random();
for (int i=0;i<m;i++)
for (int j=0;j<p;j++)
B[i*p+j]=Math.random();
for (int i=0;i<n;i++)
for (int j=0;j<p;j++) {
for (int k=0;k<m;k++)
C[i*p+j]+=A[i*m+k]*B[k*p+j];
}
System.out.println("Calculation time: " + (System.currentTimeMillis() - startDate));
}
}
Ты не представляешь, сколько таких упсов я уже видел в matlab7sp1. Регулярно падает. Особенно не любит нечёткий даблклик мышью в current directory window. Периодически виснет при обработке больших объёмов данных. В клинических случаях приходится ручками удалять toolbox cache, иначе сразу после старта выдаёт весь свой java-report прямо в основное окно, после чего валится окончательно. Пробовали разные дистрибутивы, разные машины. Всегда одно и то же. Рядом, как скала, стоит 5.3.1. Хоть бы раз упал. В нём java ещё далеко не везде, наверно :)
Ничего личного против java, но как-то неприятно. Непонятно, почему даже при использовании такого продвинутого языка девелоперы умудряются наделать столько косяков.
Там заведомо C/C++ должен быть быстрее, поскольку JVM скорее всего (??) будет многократно проверять индексы на соотвествие границам массивов. Поэтому нужно брать другую задачу, где не должны активно использоваться эти самые массивы. А, вообще, глупости это все! :)
2dea загляни в функцию Calendar.getInstance() и посмотри как он там гуляет по различным функциям.
C[i*p+j]=0; в джаве всё в начале инициалицируется, так что этого не надо. А ещё полезно применять модификатор final, помогает =)
public class Test {
public static void main(String[] args) {
final int n=1000;
final int m=1000;
final int p=1000;
final long startDate = System.currentTimeMillis();
final double[] A = new double[n*m];
final double[] B = new double[m*p];
final double[] C = new double[n*p];
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
A[i*m+j]=Math.random();
for (int i=0;i<m;i++)
for (int j=0;j<p;j++)
B[i*p+j]=Math.random();
for (int i=0;i<n;i++)
for (int j=0;j<p;j++) {
for (int k=0;k<m;k++)
C[i*p+j]+=A[i*m+k]*B[k*p+j];
}
System.out.println("Calculation time: " + (System.currentTimeMillis() - startDate));
}
}
Мега оптимизация (см. код) привела к выигрышу 6 (51760)(!!!) секунд. Вумная Java такую оптимизация и сама могла бы сделать (java оптимизации фууу)
public class Test {
public static void main(String[] args) {
final int n=1000;
final int m=1000;
final int p=1000;
final long startDate = System.currentTimeMillis();
final double[] A = new double[n*m];
final double[] B = new double[m*p];
final double[] C = new double[n*p];
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
A[i*m+j]=Math.random();
for (int i=0;i<m;i++)
for (int j=0;j<p;j++)
B[i*p+j]=Math.random();
for (int i=0;i<n;i++) {
final int k1 = i*m;
for (int j=0;j<p;j++) {
final int k2 = i*p+j;
for (int k=0;k<m;k++) {
C[k2] += A[k1+k]*B[k*p+j];
}
}
}
System.out.println("Calculation time: " + (System.currentTimeMillis() - startDate));
}
}
одно добавление. замена
final int k2 = i*p+j;
for (int k=0;k<m;k++) {
C[k2] += A[k1+k]*B[k*p+j];
}
на
final int k2 = i*p+j;
int _C = 0;
for (int k=0;k<m;k++) {
_C += A[k1+k]*B[k*p+j];
}
C[k2] = _C;
_увеливала_ время до 100 секунд. (ещё одно фууу - преведение стандартных типов на 2).
если там использовать double то время сокращается до 35165 и становится сравнимо с С.
В обшем давовский оптимизатор заработал два.
re:Ничего личного против java, но как-то неприятно. Непонятно, почему даже при использовании такого продвинутого языка девелоперы умудряются наделать столько косяков.
По тому, что людям свойственно ошибаться ;-)
Чем сложнее и больше задача, тем больше вероятность сделать ошибку(причем зависимость наверное экспоненциальная).
Именно по этому делают высокоуровневые языки.
Тебе будет легче понять, если ты хоть раз поучаствуешь в большом проекте. (И это не важно на каком языке проект, чем больше проект - тем больше ошибок, KDE, GNOME (кстати в последнем думают использовать mono или java именно для того, что бы сократить количество ошибок, а вовсе не для того что бы сделать Gnome быстрее (sun уже встроил JAVA в свой "GNOME", Novel давит на GNOME разработчиков, что бы они использовали Novelовский mono).
Timing Trials, or, the Trials of Timing:
Experiments with Scripting and User-Interface Languages
....
Needless to say, we advise all who want to know which version of a program will run faster to construct test programs and find out the truth for their language processor and machine.
....
Despite the preceding disclaimer, we essay the following summary of our observations:
Awk and Perl are similar in performance. Awk ran faster in about half the tests, contrary to the conventional wisdom that Perl is faster than Awk.
Tcl is significantly slower than Awk and Perl, typically by a factor of five or ten, but the latest bytecode version narrows that gap significantly. Scheme appears to be very roughly comparable with Tcl (aside from volume I/O, where interpreted Scheme's performance is hopeless); again, various compilation techniques speed improve this behavior.
Our experiments do not support the folklore that Java interpreters are 10 times slower than C, except when the excruciatingly slow I/O libraries are involved; otherwise the ratio is much smaller. Using buffered I/O functions improves runtimes, but by no more than a factor of two. Just-in-time compilation can have a significant effect, usually beneficial.
А так? :)
for (int i = 0; i < n; i++) {
for (int j = 0; j < p; j++) {
final int ipj = i * p + j;
final int im = i * m;
C[ipj] = 0;
int kpj = j;
for (int k = 0; k < m; k++) {
C[ipj] += A[im + k] * B[kpj];
kpj += p;
}
}
}
Сорри, умножение в 1-й цикл:
for (int i = 0; i < n; i++) {
final int im = i * m;
final int ip = i * p;
for (int j = 0; j < p; j++) {
final int ipj = ip + j;
C[ipj] = 0;
int kpj = j;
for (int k = 0; k < m; k++) {
C[ipj] += A[im + k] * B[kpj];
kpj += p;
}
}
}
s n,m,p = 1000 programma na C pokazala na 30% luchshe rezultat'. Pri uvelichenii n,m,p do 2000, C prodolzhal ostavatsya liderom, no uzhe s 10% operezheniem. GCJ pokazal sebya s otvratitelnoy storoni, ustupiv C 18%, java 7%.
Na toy zhe mashine pod solaris 10 rezultati java oboshli C pod linuxom na 25%, resultati C pod solarisom hotya i oboshli linux na 8%, vse ravno otstayut ot javi na 17%.
re:Ничего личного против java, но как-то неприятно. Непонятно, почему даже при использовании такого продвинутого языка девелоперы умудряются наделать столько косяков.
а
потом
Обратите внимание, что в варианте с clock я забыл после своих экспериментов обратно вернуть значения n, p и m на 1000!!!!! Каюсь, в общем :)
Теперь понимаешь почему девелоперы "умудряются делать ошибки"?
;-)
> Теперь понимаешь почему девелоперы "умудряются делать ошибки"?
Ну, я же не продаю свой код за бешеные бабки, как это делает MathWorks :)
Теперь ещё осталось:
1) отыскать и допросить счастливого обладателя icc;
2) попробовать на зуб Python, о коем тут также заикнулись :-D
P.S. От java я ожидал заметного торможения, но она меня порядком удивила.
>2) попробовать на зуб Python, о коем тут также заикнулись :-D
Кстати, да! C & JAVA пободались! С с некоторым перевесом победил. Помоему, ни кто другого и не ожидал. Но!!! Отсиделись в тени ценители Python и С приплюснутого!
Не совсем понятно почему производительность тестируется на примитивных типах. Было бы удивительно, если бы после стольких лет после создания, ява на этих "машинно-приближенных" типах сильно отставала от С/С++. Давайте уж на каких-нибудь комплексных числах померяемся...
> Не совсем понятно почему производительность тестируется на примитивных
> типах. Было бы удивительно, если бы после стольких лет после создания,
> ява на этих "машинно-приближенных" типах сильно отставала от С/С++.
> Давайте уж на каких-нибудь комплексных числах померяемся...
Так ты предложи примерчик-то :)
Ради смеха протестировал под виндой на Delphi 5 аналогичный код:
program mmult;
uses windows,sysutils;
const
n=1000;
m=1000;
p=1000;
var
A:array[0..n-1,0..m-1] of double;
B:array[0..m-1,0..p-1] of double;
C:array[0..n-1,0..p-1] of double;
i,j,k:smallint;
t0,tn:DWORD;
begin
t0:=GetTickCount;
for i:=0 to n-1 do
for j:=0 to m-1 do
A[i,j]:=random(1);
for i:=0 to m-1 do
for j:=0 to p-1 do
B[i,j]:=random(1);
for i:=0 to n-1 do
for j:=0 to p-1 do begin
C[i,j]:=0;
for k:=0 to m-1 do
C[i,j]:=C[i,j]+A[i,k]*B[k,j];
end;
tn:=GetTickCount;
MessageBoxEx(0,PChar('Calculation time, ms: '+IntToStr(tn-t0)+#13#10),'mmult',MB_OK+MB_ICONINFORMATION,0);
end.
C под линуксом считает 21.73 секунды, delphi - 22.61.
Ну так создайте эквивалентные классы в С++ и Java, реализующие простейшее представление комплексного числа с операциями сложения и умножения. Будет любопытно сравнить вариант хранения массивов С++ в стеке и в динамической памяти с только одним (по моим сведениям) возможным вариантом в Java, которая размещает значения непримитивных типов только в куче.
Может это толькл в Visual работает но по-моему двумерные массивы удобней так выделять на С/С++:
double (*f)[10]=(double(*)[10])malloc(sizeof(double)*10*10);
double (*k)[10]= new double[10][10];
можно нормально ссылаться f[5][5]=10;
К примеру на моем ноуте ява под виндой выдает 20-21 секунда против 17-18 на линухе и десктопе на 1000 размерности и 166 против 140 на 2000 размерности. А ПМ1.5 и П4 2.8ХТ всё-таки разные камни.
В этом нет ничего необычного. Вы тут конечно неплохо померялись у кого жаба круче, но почему то забыли о том что умножение матриц стоит делать поблочно, так чтобы соблюдалась локальность по кешу. Ускорение в 5-10 раз гарантировано(а то и больше).
> Может быть я не прав, но сравнивать производительность арифметики на Java и C++ неприлично.
Неприлично, конечно. Потому что Фортран забыли :)
Однако, уже на таких задачках Java показывает себя с хорошей стороны. Для того, чтобы найти пример, где Java будет шустрее C/C++ можно взять, например, обработку каких-нибудь сложных и взаимосвязных структур типа графов. Особенно хорошо, если на одни и те же объкты будет ссылаться множество других объектов (ассоциации 1..* x 1..*), а также будет обилие циклических ссылок (вроде такой: obj1 -> obj2 -> obj3 -> obj1).
Вот, тогда программирование таких вещей на низкоуровневых C/C++ может превратиться в настоящий геморрой (т.е., будут тормоза), тогда как явовский сборщик мусора заточен на решение таких задач. Другое дело, что придумать такую небольшую задачу для тестов не так просто.
На P3-800 Python 2.4 при использовании Psyco, при n = m = p = 500 расчёт занял 122 секунды :) Ессно я не использова функции Numeric для работы с массивами.
import psyco
from Numeric import *
from random import *
from time import *
psyco.full()
def calc():
n = 500
m = 500
p = 500
a = array(zeros(n * m), Float)
b = array(zeros(m * p), Float)
c = array(zeros(n * p), Float)
start_time = time()
for i in xrange(n):
for j in xrange(m):
a[i*m+j] = random()
for i in xrange(m):
for j in xrange(p):
b[i*p+j] = random()
for i in xrange(n):
for j in xrange(p):
for k in xrange(m):
c[i*p+j]+=a[i*m+k] * b[k*p+j]
print "Calculation time:%f" % (time() - start_time)
calc()
А вы говорите - проценты... Тут такой разброс может быть, что мало не покажется :) Надо производить расчёт в цикле для ряда значений, а потом строить на графике и только тогда делать выводы :) Например, брать среднее значение разности за весь интервал.
> На P3-800 Python 2.4 при использовании Psyco, при n = m = p = 500 расчёт занял 122 секунды :) Ессно я не использова функции Numeric для работы с массивами.
А что на этой машине при этих же размерах массивов говорит C?
mult(*C,*A,*B); - это из какой библиотеки? Я и к C могу подключить какую-нибудь либу, она того быстрее посчитает. А за матлабом вообще никто не угонится. И?