【问题标题】:Get a fraction from its decimal number从十进制数中获取分数
【发布时间】:2013-04-01 22:50:16
【问题描述】:

我正在开发一个求解方程组的程序。当它给我结果时,它就像:“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;

它不能正常工作,因为它给我的分数是错误的。谁能帮帮我?

【问题讨论】:

  • 当 x1= 123,56(例如)时,正确的分数应该是 3089/25。我的程序作为输出显示 123/100 是错误的
  • 看来你自己不知道怎么做。一旦你能做到这一点,你就可以轻松地用任何语言创建一个程序来完成你已经知道的事情。我的建议是在纸上写一些数字,然后开始编写你的算法(也许从头开始)

标签: delphi math


【解决方案1】:

您的代码无法运行,因为您使用的是二进制浮点数。并且二进制浮点类型不能表示您试图表示的十进制数。可表示的二进制浮点数的形式为 s2e,其中 s 是有效数,e 是指数。因此,例如,您不能将 0.1 表示为二进制浮点值。

最明显的解决方案是使用整数算术进行计算。根本不要调用 StrToFloat。不要碰浮点运算。自己解析输入字符串。找到小数点。使用后面的位数来计算小数刻度。去掉任何前导或尾随零。其余的使用整数算术来完成。

例如,假设输入是'2.79'。通过处理文本将其转换为分子和分母变量

Numerator := 279;
Denominator := 100;

显然,您必须编写字符串解析例程而不是使用整数文字,但这是例程。

最后,通过求这两个整数的gcd来完成问题。

底线是,要表示和操作十进制数据,您需要一个十进制算法。这不包括二进制浮点数。

【讨论】:

    【解决方案2】:

    我建议先定义一个函数 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 == inputnumeg. (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
    

    这应该快速简单地实现,但是:

    主要缺陷:

    • 浮点必须终止。例如,0.333333333333333333 的预期值不会四舍五入为 1/3
    • Float * n

    【讨论】:

    • 也谢谢你,非常有用(我也知道 C 和 Java)我会在 Delphi 上为我的项目转换代码。
    【解决方案3】:

    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找到一个现场演示和更多关于这个算法的信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      • 2014-02-18
      • 2021-09-09
      • 2012-02-17
      • 2019-09-26
      • 1970-01-01
      • 2018-03-12
      相关资源
      最近更新 更多