Dwa kody teoretycznie takie same, a w praktyce liczą inaczej. (W dwóch miejscach się różnią te kody)

0

Cały pierwszy kod (chciałem dodać w załączniku, ale nie da się):

#include <iostream>
#include <time.h>
#include <fstream>
#include <iomanip>

using namespace std;

void MA(int **s, int x, int y, float reduced_temperature, float random_number, int L);
void ones(int **s, int L); // Wypełnia tablicę jedynkami
void print(int **s, int L); // Wyświetla elementy tablicy
void print_percent(int i, int number_of_mcs); // Wyświetla jaki procent symulacji został wykonany
float magnetisation(int **s, int L); // Liczy magnetyzację układu

int main()
{
	srand(time(NULL)); // Linijka zapewniająca losowość wylosowanych liczb
	int number_of_mcs = 1000000, L = 10, counter = 1;
	float reduced_temperature = 0, random_number, m = 0, average_m = 0;
	int **s;
	fstream file;

	file.open("data.txt", ios::out);
	
	// Tworzenie tablicy wymiaru LxL
	s = new int*[L];
	for (int i = 0; i < L; i++)
	{
		s[i] = new int[L];
	}
	// -----------------------------
	ones(s, L);
	print(s, L);

	for (int i = 1; i <= number_of_mcs; i++)
	{
		for (int j = 0; j < L; j++)
		{
			for (int k = 0; k < L; k++)
			{
				random_number = (float) (rand() % 1000000) / 1000000; // Wylosowanie liczby z przedziału (0,1)
				MA(s, j, k, reduced_temperature, random_number, L);
			}
		}
		if (i >= 30000)
		{
			if(i % 100 == 0)
			{
				m = magnetisation(s, L);
				average_m += abs(m);
				// Zapisywanie danych do pliku
				file << setw(8) << left << i;
				file << setw(6) << left << m;
				file << setw(8) << left << reduced_temperature;
				file << setw(10) << left << average_m / counter << endl;
				// -----------------------------------------------------
				reduced_temperature += 0.0005f;
				counter++;
			}
		}
		print_percent(i, number_of_mcs);			
	}	
	print(s, L);
	file.close();

    return 0;
}

void MA(int **s, int x, int y, float reduced_temperature, float random_number, int L)
{
	int deltaU;

	deltaU = 2 * s[x][y] * (s[(x + 1 + L) % L][y] + s[(x - 1 + L) % L][y] + s[x][(y + 1 + L) % L] + s[x][(y - 1 + L) % L]);
	
	if (deltaU < 0) s[x][y] = -s[x][y];
	else if (random_number <= exp(-deltaU / reduced_temperature)) s[x][y] = -s[x][y];	
}

float magnetisation(int **s, int L)
{
	int m = 0;

	for (int i = 0; i < L; i++)
	{
		for (int j = 0; j < L; j++)
		{
			m += s[i][j];
		}
	}
	return (float)m / (L*L);
}

void print(int **s, int L)
{
	for (int i = 0; i < L; i++)
	{
		for (int j = 0; j < L; j++)
		{
			if (s[i][j] == 1) cout << "*" << " ";
			else cout << "M" << " ";			
		}
		cout << endl;
	}
	cout << endl;
}

void ones(int **s, int L)
{
	for (int i = 0; i < L; i++)
	{
		for (int j = 0; j < L; j++)
		{
			s[i][j] = 1;
		}
	}
}

void print_percent(int i, int number_of_mcs)
{
	if (i % (number_of_mcs / 100) == 0)	cout << i * 100 / number_of_mcs << "%" << endl;
}

Różnice pomiędzy kodami są takie:

Pierwszy kod:

file << setw(10) << left << average_m / counter << endl;

Drugi kod:

average_m /= counter; // Dodatkowa linia, której nie ma w pierwszym kodzie
file << setw(10) << left << average_m << endl; // Zamiast average_m / counter jest samo average_m

I wartości average_m są znacząco różne. Gdzie jest błąd lub różnica pomiędzy tymi kodami? .

0

Co znaczy "znacząco różne"? Możesz podać przykładowy input i output obu wersji?

0

Inputu tu nie ma. :D
Outputy w załączniku (4 kolumna). Najlepiej to widać na wykresie. Chodzi o to, że w drugim kodzie average_m spada bardzo szybko do 0.

1

To teraz zrób eksperyment.
float reduced_temperature = 0, random_number, m = 0, average_m = 0; to zamień na double. Generalnie double to jest typ jakiego domyślnie powinieneś używać chcąc mieć zmienną zmiennoprzecinkową.
Co więcej, przy takim porównywaniu wyników nie powinieneś mieć żadnej randomizacji:
srand(time(NULL)); to możesz zamienić na srand(0); na czas testów.

2
file << setw(10) << left << average_m / counter << endl;

Jeśli to zmienisz na to

average_m /= counter; // Dodatkowa linia, której nie ma w pierwszym kodzie
file << setw(10) << left << average_m << endl; // Zamiast average_m / counter jest samo average_m

to wyniki są znacząco różne? Człowieku, przecież pierwsze nie modyfikuje average_m, a drugie tak!

Dla porównania, sprawdź co się stanie:

double a = 4, b = 4;
a /= 2;
cout << a << ",  " << b/2 << '\n';
a /= 2;
cout << a << ",  " << b/2 << '\n';

Ponadto bardzo zalecam lekturę:
https://dsp.krzaq.cc/post/98/prosty-widok-na-macierz-2d-w-cpp/
https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/
https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/

1
double a = 4, b = 4;
a /= 2;
cout << a << ",  " << b/2 << '\n';

Porównując to do mojego kodu. W obu kodach mam te same wartości average_m. W pierwszym kodzie zapisuje do pliku "average_m / counter" (czyli tak jakby wyświetlam b/2), w drugim kodzie najpierw dzielę average_m przez counter i wyświetlam SAMO average_m (czyli tak jakby dzielę a przez 2 i wyświetlam SAMO a). W moim przypadku do pliku są zapisywane inne liczby, natomiast liniacout << a << ", " << b/2 << '\n'; wyświetla te same liczby.

EDIT: Rozumiem już różnicę. :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1