Author: Jonas Bilinkevicius
I'm looking for a function that I can pass in a decimal and return a fraction.
Answer:
Solve 1:
The "Denominators" parameter is an array of potential denominators that would be
acceptable. For example, to get a fractional inch dimension with a power of 2
denominator, you'd pass [2, 4, 8, 16, 32] for that parameter, and the function will
figure out which potential denominator will work best.
1
2 function ConvertFloatToFraction(const Value: Double;
3 const Denominators: array of Integer): string;
4 var
5 Index: Integer;
6 TempDelta: Double;
7 MinDelta: Double;
8 TempNumerator: Integer;
9 FracValue: Double;
10 Numerator: Integer;
11 Denominator: Integer;
12 IntValue: Integer;
13 begin
14 IntValue := Trunc(Value);
15 FracValue := Abs(Frac(Value));
16 MinDelta := 0;
17 Numerator := 0;
18 Denominator := 0;
19 for Index := 0 to High(Denominators) do
20 begin
21 TempNumerator := Round(FracValue * Denominators[Index]);
22 TempDelta := Abs(FracValue - (TempNumerator / Denominators[Index]));
23 if ((Index = 0) or (TempDelta < MinDelta)) then
24 begin
25 MinDelta := TempDelta;
26 Numerator := TempNumerator;
27 Denominator := Denominators[Index];
28 end;
29 end;
30 if (Numerator = Denominator) then
31 begin
32 IntValue := IntValue + Sign(IntValue);
33 Numerator := 0;
34 end;
35 Result := '';
36 if ((IntValue <> 0) or (Numerator = 0)) then
37 Result := IntToStr(IntValue);
38 if ((IntValue <> 0) and (Numerator <> 0)) then
39 Result := Result + ' ';
40 if (Numerator <> 0) then
41 Result := Result + IntToStr(Numerator) + '/' + IntToStr(Denominator);
42 end;
Solve 2:
This function takes the number to convert, the fraction scale you want returned
such as 8 for eighths or 10 for tenths, etc. and a boolean to tell it to round up
or down the nearest fraction. It returns a string with the integer portion, a space
and then the fraction portion. It will also reduce the fraction to the smallest
common denominator. You can use the ErrorFactor variable to adjust the percentage
of when to consider a number close enough to the next level to be close enough. I
use 4 percent of the fractional scale value.
43
44 function ToFraction(num: double; scale: integer; RoundUp: boolean): string;
45
46 {Function to find greatest common denominator}
47 function GCD(A, B: integer): integer;
48 begin
49 if (B mod A) = 0 then
50 result := A
51 else if (B mod A) = 1 then
52 result := 1
53 else
54 result := GCD((B mod A), A);
55 end;
56
57 var
58 x, y: integer;
59 ScaleFrac,
60 NumFrac,
61 ErrorFactor: double;
62 begin
63 ScaleFrac := 1 / scale;
64 NumFrac := Frac(Num);
65 ErrorFactor := ScaleFrac * 0.04; {error factor of 4 percent}
66 x := 0;
67 while (((x + 1) * ScaleFrac) < (NumFrac + ErrorFactor)) do
68 inc(x);
69 if RoundUp then
70 if (((((x + 1) * ScaleFrac) - NumFrac) / 2) > (ScaleFrac / 2)) then
71 inc(x);
72 if (x = 0) then {no fraction, just the integer portion}
73 begin
74 result := IntToStr(Trunc(Num))
75 end
76 else
77 begin {reduce the fraction as much as possible}
78 y := GCD(x, scale);
79 while (y <> 1) do
80 begin
81 x := x div y;
82 scale := scale div y;
83 y := GCD(x, scale);
84 end;
85 result := IntToStr(Trunc(Num)) + ' ' + IntToStr(x) + '/' + IntToStr(scale);
86 end;
87 end;
|