Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - komplizierte Verschachtelungen mit "if then" / "case of"


Dibelius - Di 29.04.08 17:05
Titel: komplizierte Verschachtelungen mit "if then" / "case of"
Hi,

ich möchte bei meinem Programm (zur Differentialrechnung) ein paar Optimierungen vornehmen. Vorweg: ich hab mich dabei auf nur 3 Funktionstypen festgelegt, lineare, quadratische Fkt. sowie solche 3. Grades.

Mein erstes Problem ist nun die Ausgabe der Funktionsgleichung. Es funktioniert zwar, aber die function, die ich dafür schreiben musste, ist ein einziger Wulst aus case of (für Funktionstyp) und if then Verschachtelungen (für Parameter a - d). Hier die function, wie ich sie momentan habe - wohlgemerkt fehlt noch die Fkt. 3. Grades...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
function ErstelleFunktionsgleichung: string;
begin
  case FuncType of
    1:begin  // lineare Fkt.
        if (a=0then begin
          if (b=0then result:= sfx+' = 0';
          if (b<>0then result:= Format(sfx+' = %s', [b]);
        end
        else begin  // a<>0
          if (b=0then result:= Format(sfx+' = %sx', [a]);
          if (b<0then result:= Format(sfx+' = %sx %s', [a,b]);
          if (b>0then result:= Format(sfx+' = %sx +%s', [a,b]);
        end;
      end;
    2:begin  // quadr. Fkt.
        if (a=0then begin
          if (b=0then begin
            if (c=0then result:= sfx+' = 0';
            if (c<>0then result:= Format(sfx+' = %s', [c]);
          end
          else begin  // b<>0
            if (c=0then result:= Format(sfx+' = %sx', [b]);
            if (c<0then result:= Format(sfx+' = %sx %s', [b,c]);
            if (c>0then result:= Format(sfx+' = %sx +%s', [b,c]);
          end;
        end
        else begin  // a<>0
          if (b=0then begin
            if (c=0then result:= Format(sfx+' = %sx²', [a]);
            if (c<0then result:= Format(sfx+' = %sx² %s', [a,c]);
            if (c>0then result:= Format(sfx+' = %sx² +%s', [a,c]);
          end
          else begin  // b<>0
            if (b<0then begin
              if (c=0then result:= Format(sfx+' = %sx² sx', [a,b]);
              if (c<0then result:= Format(sfx+' = %sx² %sx %s', [a,b,c]);
              if (c>0then result:= Format(sfx+' = %sx² %sx +%s', [a,b,c]);
            end;
            if (b>0then begin
              if (c=0then result:= Format(sfx+' = %sx² +sx', [a,b]);
              if (c<0then result:= Format(sfx+' = %sx² +%sx %s', [a,b,c]);
              if (c>0then result:= Format(sfx+' = %sx² +%sx +%s', [a,b,c]);
            end;
          end;
        end;
      end;
    3:begin  // Fkt. 3. Grades
        //
      end;
  end;
end;

Es soll vom Prinzip her alles so bleiben.
Parameter des Wertes 0 bleiben unberücksichtigt und erscheinen nicht im string.
Ist ein Parameter positiv, dann bekommt er ein vorangestelltes '+'
Die Ausgabe soll natürlich in der Standardform für zb. quadr. Fkt. sein:
f(x) = ax² + bx + c

Wie gesagt, es funktioniert auch alles, nur frage ich mich, ob es nicht eine elegantere Lösung gibt, mit der man sehr viel weniger Zeilen Code braucht... ich meine, ich will gar nicht dran denken, was wäre, wenn ich noch Funktionen 5. oder 10. Grades hätte Oo

Wäre nett, wenn sich das mal jemand anschauen könnte. Danke

MfG
Dibelius


Jakob_Ullmann - Di 29.04.08 18:07

Also ich würde auf jeden Fall noch ein paar Mal else einbauen. Warum? Weil dann, wenn die Bedingung davor ausgeführt worden ist, die Zeile mit else übersprungen wird und somit das Proggi ein wenig schneller läuft:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  case FuncType of
    1:begin  // lineare Fkt.
        if (a=0then begin
          if (b=0then result:= sfx+' = 0';
          if (b<>0then result:= Format(sfx+' = %s', [b]);
        end
        else begin  // a<>0
          if (b=0then result:= Format(sfx+' = %sx', [a]);
          if (b<0then result:= Format(sfx+' = %sx %s', [a,b]);
          if (b>0then result:= Format(sfx+' = %sx +%s', [a,b]);
        end;
      end;

==>

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  case FuncType of
    1:begin  // lineare Fkt.
        if (a=0then begin
          if (b=0then result:= sfx+' = 0'
          else if (b<>0then result:= Format(sfx+' = %s', [b]);
        end else begin  // a<>0
          if (b=0then result:= Format(sfx+' = %sx', [a])
          else if (b<0then result:= Format(sfx+' = %sx %s', [a,b])
          else if (b>0then result:= Format(sfx+' = %sx +%s', [a,b]);
        end;
      end;


Achso, und diesen Teil:


Delphi-Quelltext
1:
2:
3:
4:
5:
else begin  // a<>0
          if (b=0then result:= Format(sfx+' = %sx', [a])
          else if (b<0then result:= Format(sfx+' = %sx %s', [a,b])
          else if (b>0then result:= Format(sfx+' = %sx +%s', [a,b]);
        end;


Brauchst du nicht immer zu wiederholen, du kannst es als extra-Fall betrachten, also anstelle von default in C(++).


delfiphan - Di 29.04.08 18:34

Du solltest auf jeden Fall nicht alle Möglichkeiten ausprogrammieren sondern eine allgemeine Lösung schreiben. Könnte vielleicht so aussehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
function PolyToStr(const AParams: array of Integer; AVarName: Char = 'x'): String;
  function PrepareSummand(var AFirstNonZero: Boolean; ABase: Integer; AExponent: Integer): String;
  begin
    Result := '';
    if ABase = 0 then
      exit;
    if AFirstNonZero then
    begin
      if ABase < 0 then
        Result := Result + '-';
    end else
      if ABase < 0 then
        Result := Result + ' - '
      else
        Result := Result + ' + ';
    ABase := abs(ABase);
    if (ABase <> 1or (AExponent = 0then
      Result := Result + IntToStr(ABase);
    if AExponent <> 0 then
      Result := Result + AVarName;
    if AExponent >= 2 then
      Result := Result + '^' + IntToStr(AExponent);
    AFirstNonZero := False;
  end;
var
  I: Integer;
  FirstNonZero: Boolean;
begin
  Result := Format('f(%s) = ', [AVarName]);
  FirstNonZero := True;
  for I := 0 to Length(AParams) - 1 do
    Result := Result + PrepareSummand(FirstNonZero, AParams[I], Length(AParams) - I - 1);
  if FirstNonZero then
    Result := Result + '0';
end;


Beispiele:
PolyToStr([0])             // f(x) = 0
PolyToStr([1])             // f(x) = 1
PolyToStr([0,0,1])         // f(x) = 1
PolyToStr([1,2])           // f(x) = x + 2
PolyToStr([1,2,3])         // f(x) = x^2 + 2x + 3
PolyToStr([1,1,1])         // f(x) = x^2 + x + 1
PolyToStr([-1,-1,-1])      // f(x) = -x^2 - x - 1
PolyToStr([-1,0,0])        // f(x) = -x^2
PolyToStr([1,2,3,4,5,6,7]) // f(x) = x^6 + 2x^5 + 3x^4 + 4x^3 + 5x^2 + 6x + 7

//Edit: unnötiges abs() entfernt


Dibelius - Di 29.04.08 18:46

oh, das kommt dem ganzen schon recht nahe.
Die Parameter sind allerdings vom Typ real. das hab ich vergessen zu erwähnen.


jaenicke - Di 29.04.08 18:50

Das macht ja keinen Unterschied, da musst du ja nur Integer durch Real ersetzen, und entsprechend nicht von Integer in String umwandeln sondern von einer Gleitkommazahl (Float) in String.


delfiphan - Di 29.04.08 19:01

Das schaffst du wohl noch selbst ;)


Dibelius - Di 29.04.08 20:26

indeed :oops:

naja, danke jedenfalls. das hat mir sehr geholfen.

// Edit:
weil ich es in der Funktion gerade sehe: wozu ist die Funktion Abs() gut?
Laut F1 gibt die den absoluten Betrag des Arguments zurück. Wie ist das gemeint und was bewirkt das in deiner Funktion? bspw hier:


Delphi-Quelltext
1:
2:
    if abs(AExponent) >= 2 then
      Result := Result + '^' + IntToStr(AExponent);

Wenn AbsoluterBetrag(Exponent) >= 2 dann füge '^' + Exponent-String an


Delete - Di 29.04.08 20:48

abs hat doch jedes auto.
nein spaß beiseite genau weiß ich es auch nicht, aber guckdir mal
das beispiel im hilfe-menu an.


Dibelius - Di 29.04.08 21:00

ja also... wie der Name schon sagt. der Betrag
(ich glaub, ich sollte ins Bett gehen, um wieder klar denken zu können *lol*)


jaenicke - Di 29.04.08 21:34

Dir ist es ja jetzt anscheinend klar, was das für einen Sinn hat, aber um es nochmal für alle späteren Leser klar zu machen:
Ein Exponent, dessen Betrag kleiner als 2 ist, also -1, 0 oder 1 ist, der muss ja auch nicht hingeschrieben werden, dementsprechend passiert das nur, wenn der Betrag kleiner oder gleich 2 ist. ;-)


delfiphan - Mi 30.04.08 14:48

Ich wollte das eigentlich noch entfernen, hab's dann aber gelassen ;). Es müsste entweder ohne abs sein, oder mit, dann aber noch mit der Ausnahme, dass -1 eben doch dargestellt wird.

Da im Code keine negativen Exponenten dargestellt werden, ist's egal. Kannst es ja einfach entfernen.