O informatyce, po swojemu, inaczej

[C++]Liczba PI

Witam,  kolejny rok szkolny, kolejny rocznik przystępuje do egzaminu maturalnego i być może w tym roku także trafi się ktoś, kto ma ochotę się spróbować z informatyką rozszerzoną. Przygotowałem dla was właśnie szczegółowe rozwiązanie jednego z zadań z matury z 2016 roku. To co tu jest przedstawione CKE zakłada, że należy zrobić to w arkuszu kalkulacyjnym – no cóż – ja postanowiłem zabrać się za to w C++ ( oczywiście nie całe zadanie, bo nie za specjalnie w chwili, gdy to piszę mam pomysł jak zrobić wykres w konsoli ). Oczywiście rozwiązanie w arkuszu kalkulacyjnym pojawi się także – tutaj przedstawię Ci kilka uproszczeń, do których dojdziesz, gdy pisząc rozwiązania takich zadań w C++ wejdziesz sobie na ambicję. Wtedy będziesz mógł wejść tutaj i sprawdzić, czy wszystko Ci działa.

Treść zadania brzmi następująco

W kartezjańskim układzie współrzędnych na płaszczyźnie narysowano kwadrat o boku długości 400 i środku symetrii w punkcie (200;200). Boki kwadratu są równoległe do osi układu współrzędnych. W kwadrat wpisano koło. Następnie wylosowano 10 000 punktów należących do kwadratu. Współrzędne (x,y) punktów zostały zapisane w pliku punkty.txt, każdy punkt w osobnym wierszu. Wiersz ma postać dwóch liczb całkowitych z zakresu <0;400>, rozdzielonych pojedynczym znakiem odstępu. (…)

4.1 Wypisz współrzędne tych punktów, które należą do brzegu koła (okręgu), oraz podaj liczbę punktów należących do wnętrza koła ( brzeg koła nie należy do wnętrza koła ).

Wskazówka:
Równanie okręgu o środku w punkcie S = (a,b) i promieniu r>0 ma postać:

(x-a)^2 + (y-b)^2 = r^2

Informacja:
W pliku wśród 100 pierwszych punktów 80 należy do wnętrza koła.

Pliki do zadania 4.1 punkty.txt

A więc teraz przechodząc krok po kroku zanim przejdę do pisania kodu

Dostaliśmy kwadrat o wymiarach 400×400 pkt/jednostek znajdujący się w układzie współrzędnych xy ( kartezjański ), w który wpisano okrąg ( sytuacja zobrazowana na poniższym rysunku ). Wylosowano 10 000 punktów, które należą do kwadratu.
Naszym zadaniem jest ustalenie, czy te punkty o podanych współrzędnych są wewnątrz koła, czy może leżą na okręgu.

Koło wpsane w kwadratSource: Owned by the author
Koło wpisane w kwadrat w układzie kartezjańskim

Rozwiązanie zadania 4.1

Do tej imprezy będą nam potrzebne następujące biblioteki:

#include <cstdlib>
#include <iostream>
#include <fstream> // biblioteka do wykonywania operacji na plikach
#include <math.h> // przyda się do obliczeń

Także rozbijmy to sobie na kilka prostszych zadań:
import, pobranie danych z pliku do programu
selekcja punktów na podstawie wzoru
wypisanie wyników do pliku

Wszystkie punkty musimy zestawić do wzoru, który mamy podany w zadaniu. Z tego wzoru i przy zamieszczonej sytuacji na rysunku wiemy, że:
– punkty znajdujące się na okręgu znajdują się w odległości 200 pkt/jednostek od środka
– boki kwadratu są równoległe do osi ( co znacznie ułatwia sprawę )

Naszym zadaniem jest po prostu zestawienie na podstawie podanego nam wzoru, czy dane losowe punkty z pliku zgadzają się z wartością promienia, która wynosi 200.

Drobny Myk

We wzorze mamy niejako kwadrat promienia, co nie jest dla nas przeszkodą, powiem więcej – nie ma sensu tego pierwiastkować, że się tak wyrażę, a z tego wynika, że to wszystko co jest po prawej stronie musi być równe 40 000 ( 200^2 ) dla określenia punktów okręgu, lub wynik mniejszy od 40 000 wskaże nam punkty, które są wewnątrz koła. Wszystkie punkty, które ze wzoru dają nam wynik większy od 40 000 nie należą do okręgu, ani koła. Tak więc zaczynajmy, bo nadal nie mamy nic kodu…

Zaczynamy standardowo od wczytania potrzebnych nam bibliotek oraz formułki poprawiającej czytelność kodu:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <math.h>

using namespace std;  // formuła poprawiająca czytelność kodu oraz ułatwiająca pisanie, nie musimy pisać od teraz długiego żmudnego „std::” przy strumieniach z bibliotek standardowych

Teraz definiujemy zmienne, na których będziemy pracować

fstream plik, odp;
long int punktyx[10000], punktyy[10000], wk;

zmienne fstream służą do pracy z plikami, my będziemy pracować na dwóch plikach, więc przydadzą nam się dwie zmienne, chociaż jakbyśmy chcieli poradzimy sobie na jednej – na chwilę obecną skupmy się na wykonaniu zadania, potem pokażę Ci jeszcze jeden kod, który sprawi, że program będzie bardziej uniwersalny i mniej podatny na błędy użytkownika
wszystkie tablice, które zostały zdefiniowane posłużą nam do przechowywania współrzędnych punktów z pliku punkty.txt, natomiast zmienna 'wk’ policzy nam punkty, które należą do wnętrza okręgu. Wielkość tablic ustawiona rzecz jasna na potrzeby zadania.

Dla przejrzystości kodu wszystkie operacje w zasadzie zrobimy w dwóch funkcjach, które musimy przed int main() zadeklarować. Spójrz w ten kod:

import współrzędnych punktów do tablic,

void import()
{
plik.open( "punkty.txt", ios::in );  // niech zmienna plik otworzy plik z na prawach do odczytu, plik punkty.txt musi być w tym samym katalogu co plik exe naszego programu
for( int i = 0; i <10000; i++)
{
plik >> punktyx[i];
plik >> punktyy[i];
} // wczytujemy wszystkie współrzędne do tablic x i y

}

wyjaśnienie pętli

W bibliotece fstream mamy możliwość przechwytywania informacji strumieniami jak w cin i cout odpowiednio cout zapisuje do pliku, natomiast cin importuje. Importowane są wszystkie znaki do pierwszego napotkanego białego znaku, kwestia tego ile zmieścimy zależy już od pojemności zmiennej ( co zobaczysz już w drugiej funkcji, gdzie będziemy wypisywać współrzędne punktów do plików )
Struktura pliku źródłowego wygląda tak:

x y
x1 y2
... ....

Stąd też to jest dla nas wygodne i najlepsze rozwiązanie. Używamy pętli for, aby nic nie zgubić, natomiast dwóch tablic, aby nie pomylić par współrzędnych x,y punktów.

void okrag_czy_kolo()
{
odp.open( "odpowiedz.txt", ios::app );  // otwieramy plik, w przypadku jego braku zostanie utworzony tam, gdzie znajduje się plik exe naszego programu

long int wynik;  // definiujemy trochę dłuższą zmienną, taką która pomieści nam wyniki potęgowania
for(int i = 0; i<5; i++)
{

wynik= punktyx[i]*punktyx[i] – 400*punktyx[i] + punktyy[i]*punktyy[i] – 400*punktyy[i] + 80000; // tutaj wykonujemy obliczenia 'prawej strony równiania’ *
if(wynik<40000)   // jeżeli wynik 'prawej strony jest mniejszy niż kwadrat naszego promienia
{
wk=++wk;  // to dodaj 1 do licznika punktów wewnątrz koła
}
else if(wynik==40000)
{
odp << punktyx[i] << ” ” << punktyy[i] << endl; // jeżeli natomiast jest równe kwadratowi promienia wypisz do pliku współrzędne

}
}
}

Natomiast nasz int wyglądać będzie tak…

int main()
{
import(); // importujemy dane
okrag_czy_kolo(); // wykonujemy zadanie

cout<< ” Punktow wewnatrz kola: ” << wk << endl << „Punkty nalezace do okregu mozesz sprawdzic w pliku odpowiedz.txt ” << endl; // informujemy, gdzie szukać odpowiedzi

plik.close();
odp.close();  // zamykamy pliki, bo już ich nie używamy

system(„PAUSE”);
return 0;
}

Cały kod tutaj. Oczywiście ten kod można, a nawet wypada trochę podrasować ale na potrzeby zadania absolutnie wystarczy.
* w tej linijce możecie oczywiście użyć funkcji na potęgowanie pow – u mnie niestety coś wykrzaczał i 400^2 podawał jako 15 999 dlatego napisałem w tak rozbudowany i długi sposób