Delphi-PRAXiS
Seite 5 von 6   « Erste     345 6      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Zahl als Bruch speichern (https://www.delphipraxis.net/100045-zahl-als-bruch-speichern.html)

WS1976 15. Okt 2007 08:25

Re: Zahl als Bruch speichern
 
Hallo alzaimar,

Wie kommst du zu dem Schluss?
GGT, KGV und auch REG sollen auch von aussen zur Verfügung stehen.
Ich kann mir schon vorstellen dass man GGT und KGV und reg (kürzen) auch noch für andere Zwecke brauchen kann (Primzahlenberechnung oder ähnliches).

Im übrigen hab ich vergessen bei der Division und Multiplikation zu kürzen (reg).
Wer die Unit benützt bitte nachtragen.

Grüsse
Rainer

WS1976 15. Okt 2007 08:34

Re: Zahl als Bruch speichern
 
Hallo,

hab das Kürzen bei mul und div eingebaut!

Grüsse
Rainer

alzaimar 15. Okt 2007 08:35

Re: Zahl als Bruch speichern
 
Zitat:

Zitat von WS1976
Wie kommst du zu dem Schluss?
GGT, KGV und auch REG sollen auch von aussen zur Verfügung stehen.
Ich kann mir schon vorstellen dass man GGT und KGV und reg (kürzen) auch noch für andere Zwecke brauchen kann (Primzahlenberechnung oder ähnliches).

Wieso sollte ich eine TBruch-Klasse nehmen, um den KGV zu berechnen? Das wäre ja so, als ob ich eine Gabel benutze, um eine Schraube rauszudrehen. Das versteht man nun wirklich nicht unter 'Wiederverwendbarkeit'. GGT und KGV solltest Du dann auslagern.

Die Funktion 'Kürzen' wird nun wirklich nicht außerhalb benötigt, da Du das ja nach jeder Operation ohnehin durchführst.

WS1976 15. Okt 2007 08:47

Re: Zahl als Bruch speichern
 
Hallo alzaimar,

jetzt versteh ich! Im Allgemeinen hast du recht.
Man sollte KGV und GGT aus der Klasse Tbruch nehmen und als unabhängige Prozeduren deklarieren.

Grüsse
Rainer

WS1976 15. Okt 2007 08:52

Re: Zahl als Bruch speichern
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

hier nocheinmal der korrigierte und verbesserte Code:

Delphi-Quellcode:
unit U_bruchrechnen;

interface
Type
  Bruchtyp=packed record
    z,n: int64; // Int64 bei sehr großen Zahlen
  end;

  TBruch = class(TObject)
    function red(b0,b1:int64):Bruchtyp;
    function add(b0,b1: Bruchtyp):Bruchtyp;
    function sub(b0,b1: Bruchtyp):Bruchtyp;
    function mul(b0,b1: Bruchtyp):Bruchtyp;
    function divide(b0,b1: Bruchtyp):Bruchtyp;
  end;

function kgv(b0,b1:int64):int64;
function ggt(b0,b1:int64):int64;

implementation

function kgv(b0,b1:int64):int64;
  Begin
    result:=b0*b1 div ggt(b0,b1);
  End;

function ggt(b0,b1:int64):int64;
var a,b,r:integer;
  Begin
    If b0>b1 then
       Begin
         a:=b0; b:=b1
       end
    else
       begin
         b:=b0; a:=b1;
       end;
  // Berechnung des ggt
  repeat
    r:= a mod b;
    a:=b;
    b:=r
  until (r=0);
  result:=a;
End;

function TBruch.add(b0,b1: Bruchtyp):Bruchtyp;
var a:integer;b:bruchtyp;
  Begin
    a:=kgv(b0.n,b1.n);
    b.n:=a;
    b.z:=(a div b0.n)*b0.z+(a div b1.n)*b1.z;
    result:=red(b.z,b.n);
  End;

function TBruch.sub(b0,b1: Bruchtyp):Bruchtyp;
var a:integer;b:bruchtyp;
  Begin
    a:=kgv(b0.n,b1.n);
    b.n:=a;
    b.z:=(a div b0.n)*b0.z-(a div b1.n)*b1.z;
    result:=red(b.z,b.n);
  End;

function TBruch.mul(b0,b1: Bruchtyp):Bruchtyp;
  Begin
    result:=red(b0.z*b1.z,b0.n*b1.n);
  End;

function TBruch.divide(b0,b1: Bruchtyp):Bruchtyp; // div geht nicht, weil das ja ein geschützter begriff ist...
  Begin
    result:=red(b0.z*b1.n,b0.n*b1.z);
  End;

function TBruch.red(b0,b1:int64):Bruchtyp;
var a,a0,a1:integer;
  Begin
    a0:=b0;a1:=b1;
    while ggt(a0,a1)<>1 do
      Begin
        a:=ggt(a0,a1);
        a0:=a0 div a;
        a1:=a1 div a;
      End;
    result.z:=a0;
    result.n:=a1;
  End;
end.
Grüsse
Rainer

PS: Bevor die nächsten meckern; man kann GGT und KGV natürlich auch in eine andere Unit packen. Hat mit Bruchrechnung nur mittelbar was zu tun.

Amateurprofi 15. Okt 2007 18:41

Re: Zahl als Bruch speichern
 
@ws1976

Ich schlage folgende Änderungen vor

In der Funktion ggt sollten die lokalen Variablen den Typ Int64 haben.
Warum?:
Weils sonst falsche Ergebnisse bringt, wenn nur einer der Parameter > maxint ist.

in der Funktion kgv sollte nicht stehen
result:=b0*b1 div ggt(b0,b1);
sondern
result:=b0 div ggt(b0,b1) * b1;

Warum?:
Weils sonst falsche Ergebnisse gibt, wenn b0*b1 > High(int64) ist.
Das ist zwar auch bei der geänderten Variante nicht ausgeschlossen, tritt aber erst bei deutlich höheren Werten auf.

alzaimar 15. Okt 2007 19:42

Re: Zahl als Bruch speichern
 
Bist Du dir sicher, das a*b div c identisch mit (b div c)*a ist?
Beispiel : a=3, b=4, c=3.
(a*b) div c
a*b = 12 div 3 = 4

(b div c)*a
4 div 3 = 1 * 3 = 3

Amateurprofi 15. Okt 2007 20:04

Re: Zahl als Bruch speichern
 
Zitat:

Zitat von alzaimar
Bist Du dir sicher, das a*b div c identisch mit (b div c)*a ist?
Beispiel : a=3, b=4, c=3.
(a*b) div c
a*b = 12 div 3 = 4

(b div c)*a
4 div 3 = 1 * 3 = 3

@alzaimar:
Nein, im Gegenteil. Ich bin mir, so wie auch du, sicher daß "a*b div c" nicht identisch ist mit "b div c * a", und ich bin auch sicher daß die Konstrukte i.d.R. unterschiedliche Resultate bringen.

Ich bin mir aber sehr sicher, daß die Konstrukte identische Ergebnisse bringen, wenn c ein "GGT" von a und b ist, und das ist bei dem diskutierten Code der Fall.
Der Vorteil der letztgenannten Konstruktion ist, daß sie höhere Werte verarbeiten kann.
Stell dir vor a und b seien beide 9999999999 (also > maxint), dann wird bei der vorgeschalteten Multiplikation ein Zahlenüberlauf stattfinden, bei der nachgeschalteten Multiplikation aber nur dann, wenn das Gesamtergebnis > High(Int64) wird.
Somit dürfte diese Konstruktion zuverlässiger arbeiten.

cruiser 16. Okt 2007 06:27

Re: Zahl als Bruch speichern
 
mh... im Grunde habt ihr recht. Beachtet aber bitte, das c hier der ggt von a und b ist:

/ entspicht div

a = 6
b = 4
c = ggt(6,4) = 2

(a x b) / c = (6 x 4) / 2 = 24 / 2 = 12
a x (b / c) = 6 x (4 / 2) = 6 x 2 = 12
b x (a / c) = 4 x (6 / 2) = 4 x 3 = 12

in diesem speziellen Fall entspricht (a x b) / c auch a x (b / c) und b x (a / c)

Edit: Das kommt davon, wenn man früh morgens nur den halben letzten Beitrag liest...

:duck:

Edit2: Bei negativen Bruchzahlen kommts unweigerlich zum Crash. GGT darf nur Absolutwerte annehmen!

Amateurprofi 16. Okt 2007 12:19

Re: Zahl als Bruch speichern
 
Zitat:

Zitat von cruiser
mh... im Grunde habt ihr recht. Beachtet aber bitte, das c hier der ggt von a und b ist:

/ entspicht div

a = 6
b = 4
c = ggt(6,4) = 2

(a x b) / c = (6 x 4) / 2 = 24 / 2 = 12
a x (b / c) = 6 x (4 / 2) = 6 x 2 = 12
b x (a / c) = 4 x (6 / 2) = 4 x 3 = 12

in diesem speziellen Fall entspricht (a x b) / c auch a x (b / c) und b x (a / c)

Edit: Das kommt davon, wenn man früh morgens nur den halben letzten Beitrag liest...

:duck:

Edit2: Bei negativen Bruchzahlen kommts unweigerlich zum Crash. GGT darf nur Absolutwerte annehmen!

Hast du ein Beispiel bei welchen negativen Zahlen es zum Crash kommt ?
Ich sehe im Moment keinen Grund, warum die von ws1976 vorgestellte GGT-Version Probleme mit negativen Zahlen haben sollte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:27 Uhr.
Seite 5 von 6   « Erste     345 6      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz