pytania do programu obliczeniowego

0

Witam, postanowiłem założyć nowy temat, ponieważ będę miał trochę pytań do programu który chcę napisać. To będzie prosty program realizujący liniowe wcięcie przestrzenne na 6 punktów. Wszystko rozpisałem na kartce. Chodzi o to, aby na podstawie wprowadzonych danych oraz odpowiednich rachunków macierzowych dojść do macierzy (wektora) dx (3x1), a następnie wykonać dwie kontrole obliczeń oraz wyświetlić wyniki. Fajnie by było jak by wynikiem były (mogą być wygenerowane do pliku txt): macierze A (6x3), L (6x1), P (6x6), dx (3x1) oraz w okienku MessageBox po kliknięciu oblicz wartości: XAw, YAw, ZAw (wyrównane współrzędne).
W załączniku rozpisane wszystkie obliczenia, ale jak ktoś nie chce w to wnikać to nie trzeba, bo mam pare gotowych pytań na tym etapie na którym jestem.

To co napisałem do tej pory:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    TX1: TEdit;
    Label4: TLabel;
    Label5: TLabel;
    TY1: TEdit;
    Label6: TLabel;
    TZ1: TEdit;
    Label7: TLabel;
    TX2: TEdit;
    Label8: TLabel;
    Label9: TLabel;
    TY2: TEdit;
    Label10: TLabel;
    TZ2: TEdit;
    Label11: TLabel;
    TX3: TEdit;
    Label12: TLabel;
    Label13: TLabel;
    TY3: TEdit;
    Label14: TLabel;
    TZ3: TEdit;
    Label15: TLabel;
    TX4: TEdit;
    Label16: TLabel;
    Label17: TLabel;
    TY4: TEdit;
    Label18: TLabel;
    TZ4: TEdit;
    Label19: TLabel;
    TX5: TEdit;
    Label20: TLabel;
    Label21: TLabel;
    TY5: TEdit;
    Label22: TLabel;
    TZ5: TEdit;
    Label23: TLabel;
    TX6: TEdit;
    Label24: TLabel;
    Label25: TLabel;
    TY6: TEdit;
    Label26: TLabel;
    TZ6: TEdit;
    Label27: TLabel;
    Label28: TLabel;
    Label29: TLabel;
    Label30: TLabel;
    Label31: TLabel;
    Label32: TLabel;
    TXAp: TEdit;
    TYAp: TEdit;
    TZAp: TEdit;
    Label33: TLabel;
    Label35: TLabel;
    Label37: TLabel;
    Label39: TLabel;
    Label41: TLabel;
    Label43: TLabel;
    Label45: TLabel;
    TdA1: TEdit;
    TdA2: TEdit;
    TdA3: TEdit;
    TdA4: TEdit;
    TdA5: TEdit;
    TdA6: TEdit;
    Label46: TLabel;
    Label47: TLabel;
    Label48: TLabel;
    Tmd: TEdit;
    Oblicz: TButton;
    procedure ObliczClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
// deklaracja zmiennych użytych w obliczeniach
  Form1: TForm1;
  X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, X4, Y4, Z4, X5, Y5, Z5, X6, Y6, Z6, XAp, YAp, ZAp, dA1, dA2, dA3, dA4, dA5, dA6, dA1p, dA2p, dA3p, dA4p, dA5p, dA6p: Double;
  L: array [1..6] of Real;
  P: array [1..6,1..6] of Real;
implementation

{$R *.dfm}

procedure TForm1.ObliczClick(Sender: TObject);
begin
// sprawdzenie czy współrzędne są liczbami
if TryStrToFloat(TX1.Text, X1) = True
and TryStrToFloat(TY1.Text, Y1) = True
and TryStrToFloat(TZ1.Text, Z1) = True
and TryStrToFloat(TX2.Text, X2) = True
and TryStrToFloat(TY2.Text, Y2) = True
and TryStrToFloat(TZ2.Text, Z2) = True
and TryStrToFloat(TX3.Text, X3) = True
and TryStrToFloat(TY3.Text, Y3) = True
and TryStrToFloat(TZ3.Text, Z3) = True
and TryStrToFloat(TX4.Text, X4) = True
and TryStrToFloat(TY4.Text, Y4) = True
and TryStrToFloat(TZ4.Text, Z4) = True
and TryStrToFloat(TX5.Text, X5) = True
and TryStrToFloat(TY5.Text, Y5) = True
and TryStrToFloat(TZ5.Text, Z5) = True
and TryStrToFloat(TX6.Text, X6) = True
and TryStrToFloat(TY6.Text, Y6) = True
and TryStrToFloat(TZ6.Text, Z6) = True
// sprawdzenie czy współrzędne są liczbami
and TryStrToFloat(TXAp.Text, XAp) = True
and TryStrToFloat(TYAp.Text, YAp) = True
and TryStrToFloat(TZAp.Text, ZAp) = True
// sprawdzenie czy pseudoodległości są liczbami
and TryStrToFloat(TdA1.Text, dA1) = True
and TryStrToFloat(TdA2.Text, dA2) = True
and TryStrToFloat(TdA3.Text, dA3) = True
and TryStrToFloat(TdA4.Text, dA4) = True
and TryStrToFloat(TdA5.Text, dA5) = True
and TryStrToFloat(TdA6.Text, dA6) = True
// sprawdzenie czy błąd pomiaru jest liczbą
then
//obliczenie przybliżonych pseudoodległości
dA1p:=SQRT(SQR(XAp-X1)+SQR(YAp-Y1)+SQR(ZAp-Z1));
dA2p:=SQRT(SQR(XAp-X2)+SQR(YAp-Y2)+SQR(ZAp-Z2));
dA3p:=SQRT(SQR(XAp-X3)+SQR(YAp-Y3)+SQR(ZAp-Z3));
dA4p:=SQRT(SQR(XAp-X4)+SQR(YAp-Y4)+SQR(ZAp-Z4));
dA5p:=SQRT(SQR(XAp-X5)+SQR(YAp-Y5)+SQR(ZAp-Z5));
dA6p:=SQRT(SQR(XAp-X6)+SQR(YAp-Y6)+SQR(ZAp-Z6));
//wyznaczenie macierzy L
L[1]:=dA1-dA1p;
L[2]:=dA2-dA2p;
L[3]:=dA3-dA3p;
L[4]:=dA4-dA4p;
L[5]:=dA5-dA5p;
L[6]:=dA6-dA6p;
//wyznaczenie macierzy P

end;

end.

Teraz pierwszy problem na tym etapie: Jak zadeklarować macierz P (diagonalna), aby nie wypisywać wszystkich 36 elementów? Tylko na przekątnej są wartości 1/podany wcześniej błąd pomiaru do kwadratu.
I drugie pytanie: Czy aby wykonać transpozycję macierzy A (AT), muszę pisać dla każdego elementu:

AT[1,1]:=A[1,1];
AT[1,2]:=A[2,1];
AT[1,3]:=A[3,1];
AT[1,4]:=A[4,1];
itp.

Czy da się to zrobić jakoś inaczej (szybciej)?

Z góry dzięki za zainteresowanie i podpowiedzi ;)

0
  1. Wszystkie obliczenia które należy wykonać w przyp. prawidłowych danych należy umieścić pomiędzy begin...end.

  2. Zastosowałbym więcej tablic a następnie pętle for, np

  var
    dA,dAp,x,y:array[1..6] of Real;
    i:Integer;
//obliczenia w pętli
  for i:=1 to 6 do dAp[i]:=SQRT(SQR(XAp-X[i])+SQR(YAp-Y[i])+SQR(ZAp-Z[i]));
  for i:=1 to 6 do L[i]:=dA[i]-dAp[i];
//zamiast tego:
dA1p:=SQRT(SQR(XAp-X1)+SQR(YAp-Y1)+SQR(ZAp-Z1));
dA2p:=SQRT(SQR(XAp-X2)+SQR(YAp-Y2)+SQR(ZAp-Z2));
dA3p:=SQRT(SQR(XAp-X3)+SQR(YAp-Y3)+SQR(ZAp-Z3));
dA4p:=SQRT(SQR(XAp-X4)+SQR(YAp-Y4)+SQR(ZAp-Z4));
dA5p:=SQRT(SQR(XAp-X5)+SQR(YAp-Y5)+SQR(ZAp-Z5));
dA6p:=SQRT(SQR(XAp-X6)+SQR(YAp-Y6)+SQR(ZAp-Z6));
//i tego:
//wyznaczenie macierzy L
L[1]:=dA1-dA1p;
L[2]:=dA2-dA2p;
L[3]:=dA3-dA3p;
L[4]:=dA4-dA4p;
L[5]:=dA5-dA5p;
L[6]:=dA6-dA6p;
//macierz P też może być zwykłą tablicą
var p:array[1..6] of Real;
for i:=1 to 6 do p[i]:=1/Sqr(md);
  1. Podobnie w pętli możesz sprawdzać zawartości TEditów przy pomocy FindComponent
var DaneOK:Boolean;
//...
  DaneOK:=True;//wstępne założenie
for i:=1 to 6 do DaneOK:=DaneOK and TryStrToFloat(TEdit(FindComponent('TX'+IntToStr(i))).Text, X[i]);
//i dalej
for i:=1 to 6 do DaneOK:=DaneOK and TryStrToFloat(TEdit(FindComponent('TY'+IntToStr(i))).Text, Y[i]);
//i tak dalej, a następnie
  if DaneOK then
  begin
    Twoje obliczenia
  end
  else
  begin
    Jakiś komunikat o błędach
  end;
  1. Odwracanie macierzy
  for i:=1 to 4 do AT[1,i]:=AT[i,1];
0

O pętlach, tablicach i dynamicznym tworzeniu komponentów to kolega kiedyś słyszał?

0

@pelsta

Zrobiłem tak jak napisałeś, jednak jest problem, przy próbie kompilacji wyskakuje błąd, że zmienna X[i] w pętli for powinna być zmienną lokalną. Wstawiam fragment kodu od deklaracji zmiennych do początku obliczeń:

var
// deklaracja zmiennych użytych w obliczeniach
  Form1: TForm1;
  DaneOK: Boolean;
  dA: array[1..6] of Real;
  dAp: array[1..6] of Real;
  X: array [1..6] of Real;
  Y: array [1..6] of Real;
  Z: array [1..6] of Real;
  L: array [1..6] of Real;
  P: array [1..6,1..6] of Real;
  A: array [1..6,1..3] of Real;
  AT: array [1..3,1..6] of Real;
  ATPA: array [1..3,1..3] of Real;
  detATPA: Real;
  ATP: array [1..3,1..6] of Real;
  ATPAD: array [1..3,1..3] of Real;
  i: integer;
implementation

{$R *.dfm}

procedure TForm1.ObliczClick(Sender: TObject);

begin

DaneOK:= True; //wstępne założenie

// sprawdzenie czy współrzędne są liczbami

for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TX'+InttoStr(i))).Text, X[i]);
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TY'+InttoStr(i))).Text, Y[i]);
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TZ'+InttoStr(i))).Text, Z[i]);

// sprawdzenie czy pseudoodległości są liczbami
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('dA'+InttoStr(i))).Text, dA[i]);

// sprawdzenie czy współrzędne są liczbami
and if
TryStrToFloat(TXAp.Text, XAp) = True
and TryStrToFloat(TYAp.Text, YAp) = True
and TryStrToFloat(TZAp.Text, ZAp) = True

// sprawdzenie czy błąd pomiaru jest liczbą
and TryStrToFloat(Tmd.Text, md) = True
then

if DaneOK then

begin //początek obliczeń
//obliczenie przybliżonych pseudoodległości
for i:=1 to 6 do
dAp[i]:=SQRT(SQR(XAp-X[i])+SQR(YAp-Y[i])+SQR(ZAp-Z[i]));

//wyznaczenie macierzy L
for i:=1 to 6 do
L[i]:=dA[i]-dAp[i];

Jeszcze co do macierzy P, to ona jest 6x6, poza przekątną ma wartości 0, a na przekątnej 1/md^2, czy takie coś będzie dobre (ewentualnie gdzie stawiać begin, end):

//wyznaczenie macierzy P

for i:=1 to 6 do
for j:=1 to 6 do
if i:=j then
P[i,j]:=1/(SQR(md));
else
P[i,j]:=0;

@winerfresh
słyszałem, ale dawno temu :) dlatego na przykładzie tego zadania chcę sobie wszystko przypomnieć :)

0
  1. Stosuj wcięcia, a kod wstaw na stronę pomiędzy znaczniki kodu źródłowego Delphi.

  2. Wyznaczenie macierzy P prawie dobre a dokładnie powinno być tak (kompilator nie czepiał się?):

//wyznaczenie macierzy P
  for i:=1 to 6 do
    for j:=1 to 6 do
      if i=j then
        P[i,j]:=1/(SQR(md))
      else
        P[i,j]:=0;

Wcześniej musisz sprawdzić, czy md<>0.
Ewentualnie podstawiłbym zmienną pomocniczą md2:=1/(SQR(md)) i później P[i,j]:=md2

  1. Licznik w pętli musi być zmienną lokalną (zadeklarowaną w procedurze) - każdy o tym wie - a Ty deklarujesz jako zmienną globalną.

  2. Dalsze sprawdzanie powinno odbywać się w postaci

  DaneOK:=DaneOK and TryStrToFloat(TXAp.Text, XAp) and TryStrToFloat(TYAp.Text, YAp);
//itd
  DaneOK:=DaneOK and (md<>0);
0

Zadeklarowałem zmienne pod procedurą klikania w przycisk i jest dobrze. Niestety problem jest z tym sprawdzaniem danych, które zaproponowałeś.

DaneOK:= True; //wstępne założenie
begin // Czy po wstępnym założeniu trzeba dać wszystkie sprawdzenia w begin-end???

// sprawdzenie czy współrzędne satelit są liczbami
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TX'+InttoStr(i))).Text, X[i]);
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TY'+InttoStr(i))).Text, Y[i]);
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('TZ'+InttoStr(i))).Text, Z[i]);

// sprawdzenie czy pseudoodległości są liczbami
for i:=1 to 6 do DaneOK:=DaneOK and TryStrtoFloat(TEdit(FindComponent('dA'+InttoStr(i))).Text, dA[i]);

// sprawdzenie czy współrzędne punktu są liczbami
DaneOK:=DaneOK and TryStrToFloat(TXAp.Text, XAp) = True
               and TryStrToFloat(TYAp.Text, YAp) = True
               and TryStrToFloat(TZAp.Text, ZAp) = True

// sprawdzenie czy błąd pomiaru jest liczbą
               and TryStrToFloat(Tmd.Text, md) = True
end;
if DaneOK then

Kompilator dla każdej linijki mówi mi, że There is no overloadeded version of "TryStrtoFloat" that can be called with this arguments.
Z tego forum dowidziałem się, że "to blad mowiacy, ze zamieniasz pustego stringa na liczbe.", czyli rozumiem to tak, że program nie łączy tego z komponentami zadeklarowanymi automatycznie przez Delphi przy ich tworzeniu jako TX1, TX2, TX3, TY1, TY2... itd.
Co z tym fantem mogę zrobić?

0

Dziwne zmienne masz typu Double, więc powinno działać. U mnie takie coś nie powoduje błędu:

var
  X : Double;
begin
  if TryStrToFloat(Edit1.Text, X) = True then
    // Ok...
end;

A komunikat, który zacytowałeś, oznacza, ze funkcja mimo że jest przeładowana (opis i wyjaśnienia na Overload), to nie można jej używać z parametrami jakie podałeś.

0

w ferworze walki z programem tablice zadeklarowałem of Real. po zmianie na Double brak błędów. Jadę dalej. Dzięki za dotychczasową pomoc.

0

Z tymi zapętlonymi sprawdzeniami danych niestety już na pierwszym kroku obliczeń wychodzą złe liczby. Czy da radę zrobić coś takiego:
Mam kilka editów o nazwach TX1, TX2, TX3 i tak dalej. Gdy deklaruję zmienną X: array[1..6] elementy tej macierzy to wartości z kolejnych Editów TX. Czy mogę tutaj przypisać tej zmiennej wartości z komórek TX1, TX2,...,TX6 ? I później nie sprawdzać, czy wpisane dane to liczby, a od razu przejść do obliczeń?

0
X[i]:=StrToFloat(TEdit(FindComponent('TX'+InttoStr(i))).Text);
0

Czy przypadkiem nie miałeś na myśli coś w tym stylu?

suma:=0;
for i:=1 to 6 do suma:=suma+AT[1,i]*P[i,1];
ShowMessage(Floattostr(suma));
0

Też wychodzi 0 :( Ogólnie muszę wymnożyć macierz AT [3x6] z macierzą P [6x6], wyjść ma macierz ATP [3x6].

0

Ten fragment który pokazałeś to chyba wylicza jedną komórkę wyniku tą 1,1
Poprawiłem ci ten fragment czyli komórka 1,1 wyliczona poprawnie.
Pozostałe analogicznie, lub użyj pętli.

0

To co jest w komentarzu (ręczne obliczenie) liczy prawidłowo (wynik=jakaś liczba), pętla liczy źle (wynik=0). Co może być przyczyną?

//obliczenie ATP[3x6]
for i:=1 to 6 do
begin
  suma:=0;
  suma:= suma + AT[1,i]*P[i,1];
  ATP[1,1]:=suma;
 //ATP[1,1]:=AT[1,1]*P[1,1]+ AT[1,2]*P[2,1]+AT[1,3]*P[3,1]+AT[1,4]*P[4,1]+AT[1,5]*P[5,1]+AT[1,6]*P[6,1]; - to liczy poprawnie
end;
ShowMessage(Floattostr(ATP[1,1])); 

Ok, wstawiłem suma:=0 przed for i działa.

0

Można uprościć

//obliczenie ATP[3x6]
ATP[1,1]:=0;
for i:=1 to 6 do ATP[1,1]:=ATP[1,1]+AT[1,i]*P[i,1];
ShowMessage(Floattostr(ATP[1,1]));
0

Takie uproszczenie owszem zmniejsza ilość kodu zaś spowalnia działanie, lepiej:

suma:=0;
for i:=1 to 6 do suma:=suma+AT[y,i]*P[i,x];
ATP[y,x]:=suma;

Z tym że chcesz obliczyć nie jeden element zaś wszystkie 18 = 3x6

for y:=1 to 3 do
   for x:=1 to 6 do
   begin
     suma:=0;
     for i:=1 to 6 do suma:=suma+AT[y,i]*P[i,x];
     ATP[y,x]:=suma;
   end;
0

Udało mi się wszystko ogarnąć, tak że liczy dobrze, co jest dla mnie najważniejsze. Kod pewnie pozostawia jeszcze wiele do zyczenia, ale tym zajmę się później.

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