Tablicowanie wyników funkcji kwadratowej/rysowanie wykresu

0

Cześć Wszystkim :)
Potrzebuje pomocy w zadaniu na studia. Od dłuższego czasu próbuje je rozgryźć, ale za dużo na razie nie napisałem.
Za pomocą pól a,b oraz c obliczam delte i x1,x2 dla funkcji kwadratowej.
Następnie w pętli dodaje wyniki do tablicy, lecz nie jestem pewny czy robię to prawidłowe. Nie rozumiem tak w 100% jak dodawać wyniki do tablicy dwuwymiarowej.. Będę wdzięczny za przykład!
Kolejnym punktem jest narysowanie wykresu z danych pobranych do tablicy za pomocą PainBox.Canvas.
Zamieszczam cały amatorski kod jaki zrobiłem. Pewnie większość jest do poprawy, KAŻDA sensowna rada będzie dla mnie cenna - chce się tego na prawdę nauczyć dla siebie.

procedure TForm1.Button_rownanieClick(Sender: TObject);
var n : integer;
var x : longint ;
var y: longint;
var xi : double ;
var xmin : double ;
var delta : double;
var a : real;
var b: real ;
var yi : real;
var c: real;
var komunikat : string ;
var zero : string ;
var deltazero : string;
begin

    try
     a := Strtoint(Edit_a.text);
     b := Strtoint(Edit_b.text);
     c := Strtoint(Edit_c.text);
    Except
    komunikat :='Blad konwersji ciagu. Prosze podać cyfry!';
    Application.MessageBox(Pchar(komunikat),'Blad',0 );
    end;

    if (a = 0)  then
    begin
         zero := 'A nie może być rowne zero! Podaj inna liczbe!';
         Application.MessageBox(Pchar(zero),'Blad',0 );
    end
    else
      begin
      delta :=  b*b - 4 * a *c;
      end  ;

    if (delta > 0) then
      begin
          x1 := (-b - Sqrt(delta))/(2 * a);
          x2 := (-b + Sqrt(delta))/(2 * a);
          xmin := -b / (2 +a);

          xi:= xmin;

          for i:=1 to 500 do
          begin
          yi:=a*xi*xi+b*xi+c;
          TabWar[1,1]:=xi;
          TabWar[1,2]:=yi;
          x := round(TabWar[1,1]);
          y := round(TabWar[1,2]);

          PaintBox_wykres.canvas.Pixels[x,y]:= clRed;
          end;
;

          ListBox_tablica.Items.Clear;
          ListBox_tablica.Items.Add(FloatToStr(TabWar[1,1])+ ' '+FloatToStr(TabWar[1,2]));
          Memo_wyniki.Lines.Clear;
          Memo_wyniki.Append('x1 : '+ FloatToStr(x1) + '   x2 :' + FloatToStr(x2));

      end;

      if (delta = 0) then

        begin
           x3 := -b / (2+ a);
          Memo_wyniki.Lines.Clear;
          Memo_wyniki.Append('x : '+ FloatToStr(x3));
        end;

      if (delta < 0) then
      begin
          deltazero := 'Delta rowna zero - brak rozwiazan!';
          Application.MessageBox(Pchar(deltazero),'Blad',0 );
      end;

end;                      

Wklejam poniżej treść zadania, które muszę rozwiązać.
screenshot-20201207075604.png
screenshot-20201207075524.png
Wykres:
screenshot-20201207075629.png

  1. Jak użyć funkcji Canvas by narysować wykres jak wyżej z danych dodanych wcześniej do tablicy?
  2. W sumie, jak prawidłowo dodać wyniki do tablicy?

Pozdrawiam Was wszystkich i proszę o rady :)

7

@Nibek:

  1. wydziel funkcje, wszystko w Button_rownanieClick to antypattern
  • oddziel czytanie danych z UI i wyświetlanie wyniku od funkcji obliczających
  1. if (a = 0) then
    tu są dwa błędy:
    2.1) porównywanie wartości real do 0 (tego się nie robi w ten sposób) - https://edn.embarcadero.com/article/22507
    Najlepiej po prostu ten przypadek umieścić w else
    2.2) zbędne nawiasy (to nie C)

  2. Strtoint - funkcja nazywa się StrToInt m.in. po to żeby można ją było łatwo identyfikować

0

@vpiotr: Ok postaram się to poprawić :)

5

Skoro zadanie to robisz nie tylko na zaliczenie a chcesz się też nauczyć to mały tip:
zamiast bombardować użytkownika komunikatami o błędnie podanych wartościach zrób sprawdzanie wartości od razu w polu edit w stylu:

procedure TForm1.Edit_aKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in [#8, #9, '0'..'9', '-', ',']) then // akceptowane znaki
  begin
    // jak już chcesz bardzo, to możesz zrobić jakiegoś labelka który wyświetli komunikat o błędnym znaku
    // np, jakimś timerem który pokaże taki komunikat na 1-2 sekundy. Rozwiązań może być dużo
    Key := #0; // zabezpiecza przed dźwiękiem systemowym przy znaku spoza zakresu
  end;
end;

następny tip:
jak widać deltę porównujesz do jakiejś wartości kilka razy, czy nie wydaje ci się że kod używający

case wyrażenie of
  wybór 1: (kod);
  ...
  wybór n: (kod);
  else
  (kod)
end;

będzie wyglądał dużo lepiej?

i ostatnia uwaga:
w deklaracji zmiennych wystarczy raz wpisać var. Dodatkowo aby nie robić kilometra deklaracji można zmienne podawać po przecinku:
Czyli zamiast:

var n : integer;
var x : longint ;
var y: longint;
var xi : double ;
var xmin : double ;
var delta : double;
var a : real;
var b: real ;
var yi : real;
var c: real;
var komunikat : string ;
var zero : string ;
var deltazero : string;

Może być:

var 
  n: integer;
  x, y: longint;
  xi, xmin, delta: double;
  a, b, yi, c: real;
  komunikat, zero, deltazero: string;

Ale to już kwestia gustu.
Zresztą, połowa zmiennych powiedzmy że jest i tak niepotrzebna.

0

Super popracuje nad kodem i zobaczę co uda mi się osiągnąć Wskazówki są bardzo cenne :) Wrzucę zadanie jakie dostałem w całości (załącznik PDF). Może ktoś jeszcze coś doda żebym wykonał to poprawnie. Chodzi głównie o zadanie 3.
Jesteście wielcy jeszcze raz dzięki :)

2

Oj, podziwiam wykładowcę że mu się chciało. Dawno nie widziałem tak dobrze przygotowanego zadania. Aż miło się zrobiło. — robertz68 35 minut temu

przygotował już 20 lat temu, wiec ma

1

Hej :)
Starałem się zastosować wszystkie Wasze rady. Nie wszystko jest jeszcze dla mnie jasne.
@robertz68 Dzięki Twoim radą oraz @vpiotr udało mi się na pewno wyszczuplić trochę kod :D

procedure TForm1.Button_rownanieClick(Sender: TObject);
var
  i, n  : integer;
  x, y : longint ;
  xi, xmin, delta, yi : double ;
begin


       delta :=  b*b - 4 * a * c;

    if (delta > 0) then
      begin
          x1 := (-b - Sqrt(delta))/(2 * a);
          x2 := (-b + Sqrt(delta))/(2 * a);
          xmin := -b / (2 +a);
      end
      else ShowMessage('Delta rowna zero');

          xi:= xmin;

      for i:=1 to 500 do
      begin
      yi:=a*xi*xi+b*xi+c;
      TabWar[1,i]:=xi;          // Na prawdę nie wiem jak to powunno być dodane do tabeli..
      TabWar[2,i]:=yi;
      end;

      ListBox_tablica.Items.Clear;
      ListBox_tablica.Items.Add(FloatToStr(TabWar[1,i])+ ' '+FloatToStr(TabWar[2,i]));

      Memo_wyniki.Lines.Clear;
      Memo_wyniki.Append('x1 : '+ FloatToStr(x1) + '   x2 :' + FloatToStr(x2));


end;

Sprawdzam teraz wprowadzone wartości bezpośrednio w polu edycyjnym, pozbyłem się nadmiernej ilości ifów.
Będę próbował wprowadzić opcje z wyborem Case Of.
Nadal jednak nie potrafię sobie poukładać w głowie jak dodać prawidłowo kolejne wyniki do tabeli tak by później narysować wykres.

Będę wdzięczny za kolejne wskazówki.

0

Wykończy mnie ta młodzież :). Wiesz ile lat temu ja obliczałem równania kwadratowe? Wydaje mi się że jeszcze komuna rządziła w Polsce :).

No dobra:
na formatce masz dwa buttony, jeden ma obliczać równanie i wynik wpisać do memo i na tym kończy się "Zadanie 1". Skoro tak to po co w tym przycisku od razu próbujesz obliczyć funkcje? Wykładowca zapewne oczekuje abyś wykonał zadanie zgodnie z jego poleceniem.

Czyli, obliczasz deltę - to już umiesz,
następnie:

  if delta < 0 then
  begin
    Memo_wyniki.Lines.Add('a=' + FloatToStr(a) + ' b=' + FloatToStr(b) + ' c=' + FloatToStr(c) + ' delta=' + FloatToStr(delta) + ' brak rozwiązania');
  end;
  if delta = 0 then
  begin
    x1 := -b / 2 * a;
    Memo_wyniki.Lines.Add('a=' + FloatToStr(a) + ' b=' + FloatToStr(b) + ' c=' + FloatToStr(c) + ' delta=' + FloatToStr(delta) + ' x1,x2=' + FloatToStr(x1));
  end;
  if delta > 0 then
  begin
    x1 := (-b - Sqrt(delta)) / (2 * a);
    x2 := (-b + Sqrt(delta)) / (2 * a);

    Memo_wyniki.Lines.Add('a=' + FloatToStr(a) + ' b=' + FloatToStr(b) + ' c=' + FloatToStr(c) + ' delta=' + FloatToStr(delta) + ' x1=' + FloatToStr(x1) +
      ' x2=' + FloatToStr(x2));
  end;

To chyba taki najprostszy sposób, myślę że tak początkujący by to napisał.
Mógłbyś w memo jakoś ładnie sformatować tekst aby wyglądało to jakby miało kolumny - ale to już sam możesz poszukać.

Najważniejsze, co robiłeś źle to przy każdym użyciu buttona czyściłeś zawartość pola memo

Memo_wyniki.Lines.Clear;

a przecież ono służy właśnie do tego abyś widział historię swoich obliczeń. Tak naprawdę to można by generować wyniki z danych w memo ustawiając się na odpowiednią linię - ale to może później.

I teraz możesz przystąpić do Zadania 2, czyli musisz utworzyć listę współrzędnych aby po pierwsze wpisać je do tablicy, następnie tablicę przepisać do ListBox-a a na koniec wyrysować z tych danych wykres. Pamiętaj tylko że nie zawsze można to zrobić - patrz na deltę!

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