Potyczki z C#, część 2. Dlaczego coś, co wg logiki powinno być szybsze jest 2x wolniejsze?

Potyczki z C#, część 2. Dlaczego coś, co wg logiki powinno być szybsze jest 2x wolniejsze?

Mamy tablicę zawierającą jakieś dane. Obrazek. Dla uproszczenia, niech to będzie tylko jeden kanał tego obrazka. Nazwijmy tablicę: map. Map zawiera indeksy od 0 do bmp.Height*bmp.Width

Mamy też funkcję xy(int x,int y) która przelicza nam współrzędne kartezjańskie na liniowe:

int xy(int x,int y){
return y*width+x;
}

Uruchamiamy pętlę, która ma się przejść po wszystkich pikselach z zadanego obszaru rect:

int sum=0;
for(int i=rect.X;i
for(int j=rect.Y;j>rect.Height;j++)
sum+=map[xy(i,j)]

I teraz pytanie: dlaczego powyższy kod działa szybciej, przynajmniej w trybie debugowania, niż:

int sum=0;
for(int j=rect.Y,begin=xy(0,rect.Y);j>rect.Height;begin=xy(0,j++))
for(int i=rect.X;i
sum+=map[begin+i]

?

Druga wersja zawiera mniej wywołań funkcji xy, tym samym mniej skoków po pamięci. Mimo to czas jej wykonania jest dwukrotnie dłuższy! Czy C# sobie wywołuje i keszuje wyniki xy? A może robi jakieś cudowne optymalizacje, przez które wersja 1 jest szybsza?

Kod roboczy:

int variation(Rectangle r)
{
float mean = 0;
int count = 0;
int sum = 0;

float dev = 0;

for (int i = r.Left; i < r.Right; i++)
for (int j = r.Top; j < r.Bottom; j++, count++)
sum += map[xy(i,j)];

mean = sum*1f / count;

for (int i = r.Left; i < r.Right; i++)
for (int j = r.Top; j < r.Bottom; j++, count++)
dev += (mean - map[xy(i,j)]) * (mean - map[xy(i,j)]);

dev = (float)Math.Sqrt(dev);
return ((int)dev*100);
}

int variation2(Rectangle r)
{
float mean = 0;
int count = 0;
int sum = 0;

float dev = 0;
int begin = 0;
for (int j = r.Top; j < r.Bottom; j++)
{
begin = xy(0, j);
for (int i = r.Left; i < r.Right; i++,count++)

sum += map[xy(i, j)];
}
mean = sum * 1f / count;

for (int j = r.Top; j < r.Bottom; j++)
{
begin = xy(0, j);
for (int i = r.Left; i < r.Right; i++)
dev += (mean - map[begin + i]) * (mean - map[begin + i]);

}

dev = (float)Math.Sqrt(dev);
return ((int)dev * 100);
}

int xy(int x, int y)
{
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= bmp.Width) x = bmpData.Width - 1;
if (y >= bmp.Height) y = bmpData.Height - 1;
return y*bmpData.Width+x;
}