Newsgroup: it.comp.lang.delphi
Titolo: nuova classe: TFraction

che ne pensate? č una classe che gestisce le frazioni e tutte le 
operazioni che le riguardano... forse era piů semplice trasformarle in 
numeri decimali ma volevo provare... il mio obiettivo finale č un 
programma che risolva le espressioni con frazioni, mostrando anche tutti 
i passaggi, come se fosse fatta a mano (faccio prima superiore, č per 
risparmiare un po' di tempo, adesso che ci saranno una marea di compiti 
per natale almeno per le espressioni mi faccio "aiutare" dal 
computer :) )
ecco la classe TFraction al completo:
uses {roba varia di default}, Math
type
  TFraction = class
    num: Integer;
    denom: Integer;
    constructor CreateAssign(numeratore, denominatore: Integer);
    constructor Create();
    procedure Semplifica();
    procedure Somma(Frac1, Frac2: TFraction);
    procedure Moltiplica(Frac1, Frac2: TFraction);
    procedure Dividi(Frac1, Frac2: TFraction);
    procedure Eleva(Exp: Integer);
  private
    primi: array[1..25] of Integer;
end;
implementation
constructor TFraction.CreateAssign(numeratore, denominatore: Integer);
begin
  num := numeratore;
  denom := denominatore;
  // Imposta i numeri primi
  primi[1] := 2; primi[2] := 3; primi[3] := 5; primi[4] := 7; primi 
[5] := 11;
  primi[6] := 13; primi[7] := 17; primi[8] := 19; primi[9] := 23; primi
[10] := 29;
  primi[11] := 31; primi[12] := 37; primi[13] := 41; primi[14] := 43; 
primi [15] := 47;
  primi[16] := 53; primi[17] := 59; primi[18] := 61; primi[19] := 67; 
primi [20] := 71;
  primi[21] := 73; primi[22] := 79; primi[23] := 83; primi[24] := 89; 
primi [25] := 97;
end;
constructor TFraction.Create();
begin
// Imposta i numeri primi
  primi[1] := 2; primi[2] := 3; primi[3] := 5; primi[4] := 7; primi 
[5] := 11;
  primi[6] := 13; primi[7] := 17; primi[8] := 19; primi[9] := 23; primi
[10] := 29;
  primi[11] := 31; primi[12] := 37; primi[13] := 41; primi[14] := 43; 
primi [15] := 47;
  primi[16] := 53; primi[17] := 59; primi[18] := 61; primi[19] := 67; 
primi [20] := 71;
  primi[21] := 73; primi[22] := 79; primi[23] := 83; primi[24] := 89; 
primi [25] := 97;
end;
procedure TFraction.Semplifica();
var i, n: Integer;
var flag: Boolean;
begin
  for i := 1 to 25 do
  begin
    for n := 1 to 20 do
    begin
      flag := False;
      if (Self.num Mod primi[i] = 0) AND (Self.denom Mod primi[i] = 0) 
then
      begin
        flag := True;
        Self.num := round(Self.num / primi[i]);
        Self.denom := round(Self.denom / primi[i]);
      end;
      if not flag then
        break;
    end;
  end;
end;
procedure TFraction.Somma(Frac1, Frac2: TFraction);
var i, n, mcm: Integer;
var flag: Boolean;
var risultato: TFraction;
begin
  //Calcola il minimo comune multiplo delle due frazioni
  Frac1.Semplifica;
  Frac2.Semplifica;
  mcm := 1;
  for i := 1 to 25 do
  begin
    for n := 1 to 20 do
    begin
      flag := False;
      if ((Frac1.denom Mod (primi[i]*mcm) = 0) OR (Frac2.denom Mod (primi
[i]*mcm) = 0))
       AND ((Frac1.denom >= primi[i]*mcm) OR (Frac2.denom >= primi[i]
*mcm)) then
      begin
        flag := True;
        mcm := mcm*primi[i];
      end;
      if not flag then
        break;
    end;
  end;
  Frac1.num := round(mcm/Frac1.denom*Frac1.num);
  Frac2.num := round(mcm/Frac2.denom*Frac2.num);
  Frac1.denom := mcm;
  Frac2.denom := mcm;
  risultato := TFraction.CreateAssign(frac1.num + frac2.num,mcm);
  risultato.Semplifica;
  Self.num := risultato.num;
  Self.denom := risultato.denom;
end;
procedure TFraction.Moltiplica(Frac1, Frac2: TFraction);
var risultato: TFraction;
begin
  Frac1.Semplifica;
  Frac2.Semplifica;
  risultato := TFraction.CreateAssign(frac1.num * frac2.num, frac1.denom 
* frac2.denom);
  risultato.Semplifica;
  Self.num := risultato.num;
  Self.denom := risultato.denom;
end;
procedure TFraction.Dividi(Frac1, Frac2: TFraction);
var risultato: TFraction;
begin
  Frac1.Semplifica;
  Frac2.Semplifica;
  risultato := TFraction.CreateAssign(frac1.num * frac2.denom, 
frac1.denom * frac2.num);
  risultato.Semplifica;
  Self.num := risultato.num;
  Self.denom := risultato.denom;
end;
procedure TFraction.Eleva(Exp: Integer);
begin
  Self.Semplifica;
  Self.num := round(Power(self.num, exp));
  Self.denom := round(Power(self.denom, exp));
end;
end.
se ci sono possibili miglioramenti ditemi... e poi non so ancora bene 
come fare a svolgere le espressioni, in particolare a trasformare la 
stringa che contiene l'espressione in una serie di operazioni e oggetti 
TFraction
grazie mille
p.s. Se potrebbe esservi utile questa classe (anche se ho qualche 
dubbio), utilizzatela pure, no problem di "diritti d'autore" e roba del 
genere: č freeware!
--- posted by geoForum on 
http://www.delphiedintorni.it

 le operazioni che le riguardano...
Ne ho avuto bisogno anch'io, qualche tempo fa. Poi ho abbandonato tutto
e mi sono rimaste solo qualche classe completa gia' sviluppate da altri
dalle quali prendere spunto e ricavare diverse mezze idee.
Ad una scorsa veloce del tuo codice ho notato alcune ingenuita'
probabilmente dovute al fatto che sei solo un "primino" e quindi molte
cose ancora non le conosci, ma che in realta' semplificano di molto lo
sviluppo.
Vediamo un po', allora, come aiutarti (presumo che tu lo faccia per
imparare quindi saro' un poco didascalico) nello sviluppo della tua classe
-
sperando di ricordare bene tutto quanto riguarda la matematica e che
qualcuno mi
corregga alla svelta se sbaglio qualcosa sui concetti base dell'OOP.
Ecco il codice:
Unit Unit2;
Interface
Uses math, sysutils;
Type
  TFraction = Class(TObject)
// dichiaro due campi privati per la gestione interna della classe
  Private
    FNum, FDen: Int64;
// il metodo che semplifica la frazione lo dichiaro protected
// in quanto necessita solo all'interno della classe
  Protected
    Procedure Semplifica;
// metodi pubblici
 Public
// la visibilita' all'esterno della classe delle variabili interne ad essa
 
// e' data dall'uso delle proprieta'
    Property Numeratore: Int64 Read FNum;
    Property Denominatore: Int64 Read FDen;
// costruttori dichiarati con la direttiva overload per avere due 
//versione dello stesso
    Constructor Create; Overload;
    Constructor Create(const R: Extended); Overload;
    Constructor Create(Const Numeratore: Int64; Const Denominatore: Int64
= 1); Overload;
// metodi Assign: servono per assegnare dei valori alla frazione
// varia il tipo del parametro passato
    Procedure Assign(Const R: TFraction); Overload; // riceve una
"frazione"
    Procedure Assign(Const R: Extended); Overload; // riceve un valore
numerico
    Procedure Assign(Const Numeratore: Int64; Const Denominatore: Int64 =
1); Overload;
          // riceve due valori, dai nomi abbastanza descrittivi
// metodi EsponiCome: servono per "mostrare" la frazione in maniera
differente
    Function EsponiComeValore: Extended;
    Function EsponiComeStringa: String;
// metodi di supporto per assegnazione di valori particolari alla frazione
    Procedure AssegnaZero; // imposta la frazione a zero (cioe' 0 fratto X)
    Procedure AssegnaUno; // imposta a frazione al valore uno (cioe' 1
fratto 1)
// metodi per "conoscere" il valore della frazione
    Function ValeZero: Boolean;
    Function ValeUno: Boolean;
// metodi per le operazioni matematiche sulla frazione
// il concetto e': alla frazione rappresentata da questa classe
// sommo-divido-moltiplico-ecc. un'altro valore (mentre tu
// presumo che utilizzassi questa classe come contenitore del risultato
// p.e. procedure Somma(Frac1, Frac2: TFraction) -> risultato nei due campi
// num e denom
// Cosi come per gli assegnamenti, anche per le operazioni matematiche
// e' possibile usare implementazioni diverse in modo tale da avere piu'
flessibilta'
// nei parametri da passare
    Procedure Somma(Const R: TFraction); Overload; // riceve una frazione
    Procedure Somma(Const V: Extended); Overload; // riceve una valore
numerico
    Procedure Somma(Const V: Int64); Overload; // riceve una intero
    Procedure Sottrai(Const R: TFraction); Overload;
    Procedure Sottrai(Const V: Extended); Overload;
    Procedure Sottrai(Const V: Int64); Overload;
    Procedure Moltiplica(Const R: TFraction); Overload;
    Procedure Moltiplica(Const V: Extended); Overload;
    Procedure Moltiplica(Const V: Int64); Overload;
    Procedure Dividi(Const R: TFraction); Overload;
    Procedure Dividi(Const V: Extended); Overload;
    Procedure Dividi(Const V: Int64); Overload;
    Procedure ElevaAPotenza(Const R: TFraction); Overload;
    Procedure ElevaAPotenza(Const V: Extended); Overload;
    Procedure ElevaAPotenza(Const V: Int64); Overload;
  End; // fine della classe
implementation
{ TFraction }
Procedure TFraction.AssegnaUno;
Begin
  FNum := 1; FDen := 1;
End;
Procedure TFraction.AssegnaZero;
Begin
  FNum := 0; FDen := 1;
End;
Procedure TFraction.Assign(Const Numeratore, Denominatore: Int64);
Begin
  // 0 fratto 1 uguale a 0
  // x fratto 0 non e' valido (non vale infinito!)
  If Denominatore = 0 Then // genera una eccezzione
    Raise EDivByZero.Create('Valore indefinito');
  FNum := Numeratore;
  FDen := Denominatore;
  If FDen <> 1 Then // c'e' bisogno di semplificare la frazione
    Semplifica;
End;
Procedure TFraction.Assign(Const R: TFraction);
Begin
  FNum := R.FNum;
  FDen := R.FDen;
End;
Procedure TFraction.Assign(Const R: Extended);
Begin
   // l'implementazione di questo metodo
   // e' piuttosto complicata. E' necessario
   // cercare un algoritmo che, dato un numero decimale
   // qualsiasi, generi la frazione corrispondente
   // esempio da 0.3 periodico --> 1/3
End;
Constructor TFraction.Create(Const Numeratore, Denominatore: Int64);
Begin
   inherited Create;
    Assign (Numeratore, Denominatore);
End;
Constructor TFraction.Create(const R: Extended);
Begin
    inherited Create;
    Assign (R);
end;
Constructor TFraction.Create;
Begin
    inherited Create;
    AssegnaZero; // inizializzo la frazione a zero
End;
Procedure TFraction.Dividi(Const V: Int64);
Begin
End;
Procedure TFraction.Dividi(Const R: TFraction);
Begin
End;
Procedure TFraction.Dividi(Const V: Extended);
Begin
End;
Procedure TFraction.ElevaAPotenza(Const V: Extended);
Begin
End;
Procedure TFraction.ElevaAPotenza(Const R: TFraction);
Begin
End;
Procedure TFraction.ElevaAPotenza(Const V: Int64);
Begin
End;
Function TFraction.EsponiComeStringa: String;
Begin
  Result :=  IntToStr (FDen) + '/' + IntToStr (FNum);
End;
Function TFraction.EsponiComeValore: Extended;
Begin
 Result := Fnum / FDen;
End;
Procedure TFraction.Moltiplica(Const R: TFraction);
Begin
End;
Procedure TFraction.Moltiplica(Const V: Int64);
Begin
End;
Procedure TFraction.Moltiplica(Const V: Extended);
Begin
End;
Procedure TFraction.Semplifica;
// per semplificare una frazione bisogna dividere
// il numeratore e il denomitaore per il loro
// massimo comune divisore
Function  MassimoComuneDivisore (const N1, N2 : Int64) : Integer;
Procedure Swap (var X, Y : Int64);
var F : Int64;
  Begin
    F := X;
    X := Y;
    Y := F;
  end;
 // l'implementazione la lascio volutamente vuota.
 // Cerca in rete info sull'algortimo di Euclide -
 // se non ricordo male detto anche "delle sottrazioni successive"
 // per sviluppare questa funzione
 // P.S.: non ho capito come fai tu a semplificare la frazione!
 var X, Y, J : Int64;
  Begin
    X := N1;
    Y := N2;
    if X < Y then
      Swap (X, Y);
    While (X <> 1) and (X <> 0) and (Y <> 1) and (Y <> 0) do
      begin
        J := (X - Y) mod Y;
        if J = 0 then
          begin
            Result := Y;
            exit;
          end;
        X := Y;
        Y := J;
      end;
    Result := 1;
  End;   // fine MassimoComuneDivisore
var I : Int64;
Begin
    // se il numeratore e' minore di zero
    // inverto il segno dei valori - per semplicita'
    if FNum < 0 then
      begin
        FDen := -FDen;
        FNum := -FNum;
      end;
    // se la frazione vale uno o zero
    // non ha bisogno di essere semplificata
    if (FDen = 1) or (FNum = 1) or (FDen = 0) then
      exit;
    I := MassimoComuneDivisore (FDen, FNum);
    FDen := FDen div I;
    FNum := FNum div I;
end;
Procedure TFraction.Somma(Const R: TFraction);
Begin
 // somma di frazioni a/b + c/d =
 // (a*d)+(b*c) tutto diviso per (b*d)
 FDen := (FNum * R.FDen) + (FDen * R.FNum);
 FNum := FNum * R.FNum;
 Semplifica;
End;
Procedure TFraction.Somma(Const V: Extended);
Begin
 // Questa operazione non ha nulla a che fare con la matematica!
 Assign(EsponiComeValore + V);
End;
Procedure TFraction.Somma(Const V: Int64);
Begin
 // x + Num/Den = ((x*Den)+Num)/Den
 FNum := (V * FDen) + FNum;
End;
Procedure TFraction.Sottrai(Const V: Extended);
Begin
  Assign(EsponiComeValore - V);
End;
Procedure TFraction.Sottrai(Const R: TFraction);
Begin
    FDen := FDen * R.FNum - R.FDen;
    FNum := FNum * R.FNum;
    Semplifica
End;
Procedure TFraction.Sottrai(Const V: Int64);
Begin
   FNum := (V * FDen) - FNum;
End;
Function TFraction.ValeUno: Boolean;
Begin
   Result := (FDen = 1) and (FNum = 1);
end;
Function TFraction.ValeZero: Boolean;
Begin
    Result := FDen = 0;
end;
End.
Attenzione che questo codice non e' compilabile, devi sistemare i buchi
nel 
codice che ho lasciato. Tutto questo e' solo per darti una idea di
come io avrei proceduto.
Ciao
ACSH
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

  // P.S.: non ho capito come fai tu a semplificare la frazione!
Ecco, come non detto: non ho tolto il codice che avresti dovuto
sviluppare tu!
