У меня второй пример работает дольше примерно на 100 мсек.
100 миллисекунд это не показатель, вызов метода больше, на много, тратит. Запустите много раз.
Слышал, что в мехмате есть открытые семинары по программированию. Жаль только, что далеко от меня до Ростова.
Uses System;
begin
var DT := DateTime.Now;
var a: Double;
for Var i := 0 to 10000000 do
begin
for Var j := 0 to 19 do
begin
a := i * j;
end;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
DT := DateTime.Now;
for Var i := 0 to 10000000 do
begin
a := i;
a := i * 1;
a := i * 2;
a := i * 3;
a := i * 4;
a := i * 5;
a := i * 6;
a := i * 7;
a := i * 8;
a := i * 9;
a := i * 10;
a := i * 11;
a := i * 12;
a := i * 13;
a := i * 14;
a := i * 15;
a := i * 16;
a := i * 17;
a := i * 18;
a := i * 19;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
end.
Кстати циферки тут очень интересные. Примерно во столько раз программа на C# быстрее, чем на Паскале.
Не так уж и много. Но запускал несколько раз - разница доходила до секунды.
Давайте в процентах говорить лучше.
Вот у меня разница может колебаться (в обе стороны) на 10-15%, а если я атрибутом отключаю инлайнинг - вызов функции становится на 30-50% медленнее.
Как Вы его отключаете?
Uses System;
uses System.Runtime.CompilerServices;
[MethodImpl(MethodImplOptions.NoInlining)]
function BuildIndex(X: Int32; Y: Int32; Z: Int32; Width: Int32; Depth: Int32): Int32;
begin
Result := ((Width * Y) + X) * Depth + Z;
end;
[MethodImpl(MethodImplOptions.NoInlining)]
function mul(x: Int32; y: Int32; d: Int32): Int32;
begin
Result := x * y * d;
end;
begin
var arr: array of Int32 := new Int32[64 * 1000 * 1000];
for Var d := 0 to 63 do
for Var y := 0 to 999 do
for Var x := 0 to 999 do
begin
arr[((1000 * y) + x) * 64 + d] := x * y * d;
end;
var DT := DateTime.Now;
for Var d := 0 to 63 do
for Var y := 0 to 999 do
for Var x := 0 to 999 do
begin
arr[((1000 * y) + x) * 64 + d] := x * y * d;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
for Var d := 0 to 63 do
for Var y := 0 to 999 do
for Var x := 0 to 999 do
begin
arr[BuildIndex(x, y, d, 1000, 64)] := mul(x, y, d);
end;
DT := DateTime.Now;
for Var d := 0 to 63 do
for Var y := 0 to 999 do
for Var x := 0 to 999 do
begin
arr[BuildIndex(x, y, d, 1000, 64)] := mul(x, y, d);
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
Console.ReadLine();
end.
Хорошо. Вопрос с инлайном закрыт. Но вот что с раскруткой циклов?
А при чём тут они? И что с ними собственно, вы предлагаете?
И правильно. Компилятор не генерирует ассемблерный код. Этим занимается JIT. Ему лучше знать, какую функцию инлайнить.
Хорошо. Я уже проверил это. Но что делать с раскруткой? Код выше.
“ускорение” этой программы связано с тем, что 18 из 19ти тупо не выполняются…
А если так:
Uses System;
begin
var DT := DateTime.Now;
var a: Double;
for Var i := 1 to 10000000 do
begin
for Var j := 1 to 19 do
begin
a := i * j;
end;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
DT := DateTime.Now;
for Var i := 1 to 10000000 do
begin
a := i * 1;
a := i * 2;
a := i * 3;
a := i * 4;
a := i * 5;
a := i * 6;
a := i * 7;
a := i * 8;
a := i * 9;
a := i * 10;
a := i * 11;
a := i * 12;
a := i * 13;
a := i * 14;
a := i * 15;
a := i * 16;
a := i * 17;
a := i * 18;
a := i * 19;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
Console.ReadLine();
end.
Кхм, и правда, это уже не малая разница)) Но, по моему давать компилятору раскручивать циклы - не лучшая идея. Лучше, к примеру, директивой. К примеру я вот сейчас EXAPUNKS играю (очередная игра про програминг на ассемблере) - там, по моему, очень красивое решение.
@REP 3
ADDI X {3,2} X
@END
Развернётся в:
ADDI X 3 X
ADDI X 5 X
ADDI X 7 X
То есть скопирует строчки выделенные директивой и заменит {...}
на первое число, но в каждой копии строчки будет увеличивать его с шагом который записан вторым числом.
С языка сняли
Нет, проблема в том что у вас предыдущие значения не смысла присваивать, потому что их сразу перезаписывает. Так правильнее:
Uses System;
begin
var DT := DateTime.Now;
var a: Double;
for Var i := 1 to 10000000 do
begin
for Var j := 1 to 19 do
begin
a += i * j;
end;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
a := 0;
DT := DateTime.Now;
for Var i := 1 to 10000000 do
begin
a += i * 1;
a += i * 2;
a += i * 3;
a += i * 4;
a += i * 5;
a += i * 6;
a += i * 7;
a += i * 8;
a += i * 9;
a += i * 10;
a += i * 11;
a += i * 12;
a += i * 13;
a += i * 14;
a += i * 15;
a += i * 16;
a += i * 17;
a += i * 18;
a += i * 19;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
Console.ReadLine();
end.
Но разница всё равно в 2 раза, так что смысл в этом всём есть.
Привет, переполнение переменной! Но всё равно, к сожалению компилятор не увидел и не исправил этой чуши
Как считаете, может сделать опрос по директиве раскрутки цикла?
Ну хорошо:
Uses System;
begin
var DT := DateTime.Now;
var a: Double;
for Var i := 1 to 10000000 do
begin
a -= a*0.99;
for Var j := 1 to 19 do
begin
a += i * j;
end;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
a := 0;
DT := DateTime.Now;
for Var i := 1 to 10000000 do
begin
a -= a*0.99;
a += i * 1;
a += i * 2;
a += i * 3;
a += i * 4;
a += i * 5;
a += i * 6;
a += i * 7;
a += i * 8;
a += i * 9;
a += i * 10;
a += i * 11;
a += i * 12;
a += i * 13;
a += i * 14;
a += i * 15;
a += i * 16;
a += i * 17;
a += i * 18;
a += i * 19;
end;
Console.WriteLine((DateTime.Now - DT).TotalMilliseconds);
writeln(a);
Console.ReadLine();
end.
Всё равно, разница такая же, в 2 раза.