我正在开发一个解决方程组的程序。当它给我结果时,它就像:“x1 = 1,36842”。我想得到“1,36842”的一小部分,所以我写了这段代码。
procedure TForm1.Button1Click(Sender: TObject);
var numero,s:string;
a,intpart,fracpart,frazfatta:double;
y,i,mcd,x,nume,denomin,R:integer;
begin
a:=StrToFloat(Edit1.Text); //get the value of a
IntPart := Trunc(a); // here I get the numerator and the denominator
FracPart := a-Trunc(a);
Edit2.Text:=FloatToStr(FracPart);
numero:='1';
for i:= 1 to (length(Edit2.Text)-2) do
begin
numero:=numero+'0';
end; //in this loop it creates a string that has many 0 as the length of the denominator
Edit3.text:=FloatToStr(IntPart);
y:=StrToInt(numero);
x:=StrToInt(Edit3.Text);
while y <> 0 do
begin
R:= x mod y;
x:=y;
y:=R;
end;
mcd:=x; //at the end of this loop I have the greatest common divisor
nume:= StrToInt(Edit3.Text) div mcd;
denomin:= StrToInt(numero) div mcd;
Memo1.Lines.Add('fraction: '+IntToStr(nume)+'/'+IntToStr(denomin));
end;
它无法正常工作,因为它给我的分数是错误的。有人可以帮我吗?
答案 0 :(得分:5)
您的代码无法正常工作,因为您使用的是二进制浮点数。二进制浮点类型不能表示您尝试表示的十进制数。可表示的二进制浮点数的形式为 s2 e ,其中 s 是有效数, e 是指数。因此,例如,您不能将0.1表示为二进制浮点值。
最明显的解决方案是使用整数运算执行计算。根本不要调用StrToFloat。不要触摸浮点运算。自己解析输入字符串。找到小数点。使用后面的位数来计算小数位。剥去任何前导或尾随零。并使用整数运算来完成剩下的工作。
例如,假设输入为'2.79'
。通过处理文本将其转换为分子和分母变量
Numerator := 279;
Denominator := 100;
显然你必须编写字符串解析例程而不是使用整数文字,但那是常规的。
最后,通过找到这两个整数的gcd来完成问题。
最重要的是,要表示和操作十进制数据,您需要一个十进制算法。这不包括二进制浮点数。
答案 1 :(得分:3)
我建议先定义一个函数GreaterCommonDivisor函数(wiki reference)
这将是类似Java / C的代码,因为我不熟悉Delphi
让
float x = inputnum // where inputnum is a float
// eg. x = 123.56
然后,乘以
int n = 1;
while(decimalpart != 0){// or cast int and check if equal-> (int)x == x
x = x * 10;
decimalpart = x % 1;
// or a function getting the decimal part if the cast does work
n *= 10;
}
// running eg. x = 123.56 now x = 12356
// n = 100
此时您应该(float)x/n == inputnum
eg. (12356/100 == 123.56)
这意味着你有一个在这一点上可能不会简化的分数。您现在所做的就是实现并使用GCD功能
int gcd = GreaterCommonDivisor(x, n);
// GreaterCommonDivisor(12356, 100) returns 4
// therefore for correct implementation gcd = 4
x /= gcd; // 12356 / 4 = 3089
n /= gcd; // 100 / 4 = 25
这应该快速而简单地实施,但是:
答案 2 :(得分:2)
Continued fractions可用于查找实数的良好有理逼近。这是JavaScript中的一个实现,我确信移植到Delphi是微不足道的:
function float2rat(x) {
var tolerance = 1.0E-6;
var h1=1; var h2=0;
var k1=0; var k2=1;
var b = x;
do {
var a = Math.floor(b);
var aux = h1; h1 = a*h1+h2; h2 = aux;
aux = k1; k1 = a*k1+k2; k2 = aux;
b = 1/(b-a);
} while (Math.abs(x-h1/k1) > x*tolerance);
return h1+"/"+k1;
}
例如,1.36842被转换为26/19。
您可以找到实时演示以及有关此算法的更多信息on my blog。