Here's a version with operator overloading, using advanced records.
program fractions;
{$mode objfpc}{$H+}
{$MODESWITCH ADVANCEDRECORDS}
uses
Classes, sysutils;
type
{ TFraction }
TFraction = record
Numerator,
Denominator: Int64;
procedure Init(ANumerator,ADenominator: Int64);
procedure Normalize;
function ToString: String;
function Resolve: String;
end;
function GreatestCommonDivisor(a, b: Int64): Int64;
var
temp: Int64;
begin
while b <> 0 do
begin
temp := b;
b := a mod b;
a := temp
end;
result := a
end;
operator := (I: Int64) F: TFraction;
begin
F.Numerator := I;
F.Denominator := 1;
end;
operator := (S: String) F: TFraction;
var
N,D,P: Int64;
begin
P := Pos('/',S);
if (P > 0) then
begin
N := StrToint(Copy(S,1,P-1));
D := StrToInt(Copy(S,P+1,MaxInt));
{$PUSH}{$WARNINGS OFF}
F.Init(N, D);
{$POP}
end
else
begin
N := StrToInt(S);
F := N;
end;
end;
operator + (L: TFraction; R: TFraction) F: TFraction;
begin
F.Denominator := L.Denominator * R.Denominator;
F.Numerator := L.Numerator * R.Denominator + R.Numerator * L.Denominator;
F.Normalize;
end;
operator + (L: TFraction; R: Int64) F: TFraction;
var
Temp: TFraction;
begin
Temp := R;
F := L + Temp;
end;
operator + (L: Int64; R: TFraction)F : TFraction;
begin
F := R + L;
end;
operator - (L: TFraction; R: TFraction) F: TFraction;
begin
R.Numerator := - R.Numerator;
F := L + R;
end;
operator - (L: TFraction; R: Int64) F: TFraction;
var
Temp: TFraction;
begin
Temp := R;
F := L + Temp;
end;
operator - (L: Int64; R: TFraction) F: TFraction;
begin
F := R - L;
end;
operator * (L: TFraction; R: TFraction) F: TFraction;
begin
L.Normalize;
R.Normalize;
F.Numerator := L.Numerator * R.Numerator;
F.Denominator := L.Denominator * R.Denominator;
F.Normalize;
end;
operator * (L: TFraction; R: Int64) F: TFraction;
begin
F := L;
F.Normalize;
F.Numerator := L.Numerator * R;
F.Normalize;
end;
operator * (L: Int64; R: TFraction) F: TFraction;
begin
F := R * L;
end;
operator / (L: TFraction; R: TFraction) F: TFraction;
var
Temp: TFraction;
begin
Temp.Numerator := R.Denominator;
Temp.Denominator := R.Numerator;
F := L * Temp;
end;
operator / (L: TFraction; R: Int64) F: TFraction;
begin
F := L;
F.Normalize;
F.Denominator := F.Denominator * R;
F.Normalize;
end;
operator / (L: Int64; R: TFraction) F: TFraction;
begin
F := R / L;
end;
var
F1, F2, Res: TFraction;
{ TFraction }
procedure TFraction.Init(ANumerator, ADenominator: Int64);
begin
if (ADenominator = 0) then raise EZeroDivide.Create('TFraction: denominator cannot be 0');
if (ADenominator < 0) then
begin
ANumerator := - ANumerator;
ADenominator := - ADenominator;
end;
Numerator := ANumerator;
Denominator := ADenominator;
end;
procedure TFraction.Normalize;
var
GCD: Int64;
begin
if (Denominator < 0) then
begin
Numerator := - Numerator;
Denominator := - Denominator;
end;
GCD := GreatestCommonDivisor(Numerator, Denominator);
if (GCD <> 1) then
begin
Numerator := Numerator div GCD;
Denominator := Denominator div GCD
end;
end;
function TFraction.ToString: String;
begin
if (Denominator < 0) then
begin
Numerator := - Numerator;
Denominator := - Denominator;
end;
Result := IntToStr(Numerator) + '/' + IntToStr(Denominator);
end;
function TFraction.Resolve: String;
var
IntPart: Int64;
begin
Normalize;
if (Abs(Numerator) > Abs(Denominator)) then
begin
IntPart := Numerator div Denominator;
Numerator := Numerator mod Denominator;
if (IntPart < 0) then Numerator := -Numerator;
if (Numerator <> 0) then
Result := IntToStr(IntPart) + #32 + ToString
else
Result := IntToStr(IntPart);
end
else
begin
Result := ToString;
end;
end;
begin
F1.Init(2,3);
F2.Init(1,5);
Res := F1 + F2;
writeln(F1.ToString,' + ',F2.ToString,' = ',Res.ToString);
Res := F1 - F2;
writeln(F1.ToString,' - ',F2.ToString,' = ',Res.ToString);
Res := F1 * F2;
writeln(F1.ToString,' * ',F2.ToString,' = ',Res.ToString);
Res := F1 / F2;
writeln(F1.ToString,' / ',F2.ToString,' = ',Res.ToString);
Res := '123/456';
writeln('123/456 -> ',Res.ToString);
Res := '123';
writeln('123 -> ',Res.ToString);
Res := '456/123';
writeln('456/123: ToString = ',Res.ToString,' Resolve = ',Res.Resolve);
Res := '456/-123';
writeln('456/-123: ToString = ',Res.ToString,' Resolve = ',Res.Resolve);
end.
It has an overlaode := operator, so you can do:
Fraction := '123/456';
Example output:
C:\Users\Bart\LazarusProjecten\ConsoleProjecten\fractions>fractions
2/3 + 1/5 = 13/15
2/3 - 1/5 = 7/15
2/3 * 1/5 = 2/15
2/3 / 1/5 = 10/3
123/456 -> 123/456
123 -> 123/1
456/123: ToString = 456/123 Resolve = 3 29/41
456/-123: ToString = -456/123 Resolve = -3 29/41
25/5: ToString = 25/5 Resolve = 5
Bart