【问题标题】:Convert Decimal number into Fraction将十进制数转换为分数
【发布时间】:2012-11-13 16:18:26
【问题描述】:

我正在尝试将十进制数转换为其分数。小数点后最多有 4 位数字。 例如:- 12.34 = 1234/100 12.3456 = 123456/10000

我的代码:-

#include <stdio.h>
int main(void) {
  double a=12.34;
  int c=10000;
  double b=(a-floor(a))*c;
  int d=(int)floor(a)*c+(int)b; 
  while(1) {
     if(d%10==0) {
    d=d/10;
    c=c/10;
 }
 else break;
  }
  printf("%d/%d",d,c);
 return 0;
}

但我没有得到正确的输出,十进制数只能是双精度的。请指导我应该怎么做。

【问题讨论】:

  • 完全不要使用浮点数,而是使用定点整数,即让你的单位为 1/10000。
  • int d = (int)round(a * c); 将是一个很好的起点。如果你只使用floor 和截断,像12.34 = 12.339999999999999857891452847979962825775146484375 这样的东西会让你大吃一惊。但我同意 Kerrek 的观点,你应该从一开始就使用整数。
  • One of my questions 被标记为与这个重复,即使它是关于 JavaScript,而不是 C。:/

标签: c math


【解决方案1】:

如果您的浮点数是x,那么超过10000 的分数的分子将是(x + 0.00005) * 10000 的整数部分。是否要将分数简化为最简单的项(即除以分子和分母的 gcd)取决于您。

【讨论】:

    【解决方案2】:
    #include <stdio.h>
    
    int main(void) {
        double a = 12.34;
        int c = 10000;
        double b = (a - floor(a)) * c;
        int d = (int)floor(a) * c + (int)(b + .5f); 
        printf("%f %d\n", b, d);
    
        while(1) {
           if(d % 10 == 0) {
               d = d / 10;
               c = c / 10;
           }
           else break;
        }
        printf("%d/%d\n", d, c);
        return 0;
    }
    

    问题是 b 得到 3400.00,但是当你执行 (int) b 时你得到 3399,所以你需要添加 0.5 这样数字可以截断为 3400。

    获取 3400.00 与拥有 3400 不同,3400.00 意味着该数字四舍五入到 3400,这就是为什么当您执行 (int) 3400.00 时,它假定最接近的整数(小于您要转换的数字)是 3399,但是,当您将该数字加上 0.5 时,最后一个最接近的整数现在是 3400。

    如果您想更深入地了解浮点运算,请阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic

    【讨论】:

      【解决方案3】:

      我的解决方案很简单,“懒惰”,通过迭代运行,没什么花哨的。

      在大多数拥有不错数学库的语言中,您只需要算法本身。

      但在 bc 中,您需要实现简单的功能,例如

      int() to return integer part of a number ,
      abs() to return absolute value ,
      float() to return floating part of a number ,
      round() to round to nearest integer.
      

      如果在 (1/eps) 次迭代后没有找到任何东西,则循环以最后一个结果中断。

      eps=10^-4 /*Tweak for more or less accuracy */
      
      define int(x) {
        auto s ;
        s = scale ;
        scale = 0 ;
        x /= 1 ;
        scale = s ;
        return x ;
      }
      define round(x) { return int(x+.5-(x<0)) ; }
      define abs(x) { if ( x < 0 ) x=-x ; return x ; }
      define float(x) { return abs(x-int(x)) ; }
      
      define void frac(x) {
          auto f, j, n, z ;
          f = float(x) ;    
          j = 1 / eps ;
          z = .5 ;
          if ( f != 0 ) {
              while ( ( n++ < j ) && ( abs( z - round(z) ) > eps ) ) z = n / f ;
              n -= 1 ;
              if ( x < 0 ) n = -n ;
              x = int(x)
              z = round(z) ;
              print n + x*z , "/" , z , " = "
              if ( x != 0 )  print x , " + " , n , "/" , z , " = "
          }
          print x+n/z , "\n" ;
      }
      

      使用标准精度 (eps=.0001),您可以得到:

      frac(-.714285)
      -5/7 = -.71428571428571428571
      
      sqrt(2)
      1.414213562373
      frac(sqrt(2))
      19601/13860 = 1 + 5741/13860 = 1.414213564213
      
      6-7/pi
      3.77183080
      eps=.000001 ; frac(6-7/pi)
      1314434/348487 = 3 + 268973/348487 = 3.77183080
      

      【讨论】:

        【解决方案4】:

        这是我使用的算法。这是一个迭代过程,其工作原理如下:

        1. 分子的初始近似值为 1,分母为 1 除以浮点值的小数部分。例如,将 0.06 转换为分数时,分母 = 1/0.06 = 16.66666667(四舍五入为 17),因此初始近似值为 1/17。
        2. 计算浮点值与当前近似值之间的差值。例如,差值为 1/17 - 0.06 = 0.058824 - 0.06 = -0.001176。
        3. 如果差值的绝对值小于定义的容差(即 0.000005),则终止迭代。
        4. 使用在步骤 2 中计算的差值来改进分数的近似值。这是通过将差值转换为分数并添加(或减去)到当前近似值来完成的。在该示例中,负差异表示低近似值 - 因此需要将差异添加到当前近似值中。差异分数是分子 = 1 和分母 = 1/0.001176 = 850 - 分数的差异是 1/850。新的近似值为 (1/17) + (1/850) = (850*1 + 17*1)/(850*17) = 867/14450。
        5. 重复步骤 2 到 4,直到找到解决方案。
        6. 找到解决方案后,可以减少分数。例如,867/14450 正好是 0.06,迭代过程终止。 867/14450 可以减少到 3/50。

        这种方法的一些特点是:

        • 如果得到的分数是 1/anything,则第一个近似值将是精确的。例如,将 0.25 转换为分数,第一个近似值将是 1/4。因此不需要进一步的迭代。
        • 在 1,000,000 个测试用例的大多数 (> 80%) 中,收敛发生在 2 次或更少的迭代中。
        • 对于所有测试用例,最大迭代次数为 3。

        我在github上发布了这个算法的代码——https://github.com/tnbezue/fraction

        【讨论】:

          【解决方案5】:

          这是一个有趣的问题。 我认为您最好从阅读计算“最大公约数”的倍数方法开始(http://en.wikipedia.org/wiki/Greatest_common_divisor 是一个很好的来源)。

          实现一个快速而肮脏的算法,让这些计算就像你用笔和纸做的那样,然后研究双精度数的表示方式(符号、指数、尾数)并改进你的算法以利用这种表示。

          遗憾的是,如果不编写您的代码,我将无能为力。

          【讨论】:

          • 这并不能真正回答问题 - 它只会提示提问者搜索他们自己问题的答案。 ://
          【解决方案6】:

          用 c++ 创建的一种算法,可以将小数转换为分数。

          #include <iostream>
          using namespace std;
          
          
          // converts the string half of the inputed decimal number into numerical values
          void converting (string decimalNumber, float& numerator, float& denominator )
          
          {
          float number;
          string valueAfterPoint = decimalNumber.substr(decimalNumber.find(".") + 1,((decimalNumber.length() -1) )); // store the value after the decimal into a valueAfterPoint
          cout << valueAfterPoint<< " "<< endl;
          int length = valueAfterPoint.length(); //stores the length of the value after the decimal point into length
          
           numerator = atof(valueAfterPoint.c_str()); // converts the string type decimal number into a float value and stores it into the numerator
          
          // loop increases the decimal value of the numerator and the value of denominator by multiples of ten as long as the length is above zero of the decimal
          
          cout << length<< endl;
          for (; length > 0; length--)
          {
              numerator *= 10;
          
          }
          do
              denominator *=10;
              while  (denominator < numerator);
          
          }
          
          // simplifies the the converted values of the numerator and denominator into simpler values for          an easier to read output
            void simplifying (float& numerator, float& denominator)
          {
          int maximumNumber = 9; //Numbers in the tenths place can only range from zero to nine so the maximum number for a position in a poisitino for the decimal number will be nine
          
          bool isDivisble; // is used as a checker to verify whether the value of the numerator has the       found the dividing number that will a value of zero
          
          // Will check to see if the numerator divided denominator is will equal to zero
          
          
          
          if(int(numerator) % int(denominator) == 0)
          {
              numerator /= denominator;
              denominator = 1;
              return;
          }
          
          
          //check to see if the maximum number is greater than the denominator to simplify to lowest form
          while (maximumNumber < denominator)
          {
              maximumNumber *=10;
           }
          
          
          // the maximum number loops from nine to zero. This conditions stops if the function isDivisible is true
          for(; maximumNumber > 0; maximumNumber --)
          {
          
              isDivisble = ((int(numerator) % maximumNumber == 0) && int(denominator)% maximumNumber == 0);
              cout << numerator << denominator <<" " <<endl;
              if(isDivisble)
              {
                  numerator /= maximumNumber;  // when is divisible true numerator be devided by the max    number value for example 25/5 = numerator = 5
          
                  denominator /= maximumNumber; //// when is divisible true denominator be devided by the max number value for example 100/5 = denominator = 20
          
              }
              // stop value if numerator and denominator is lower than 17 than it is at the lowest value
              int stop = numerator + denominator;
          
              if (stop < 17)
              {
                  return;
              }
          }
          }
            int main()
          {
          string decimalNumber;
          float numerator = 0;
          float denominator = 1;
          
          cout << "Enter the decimal number";
          cin >> decimalNumber;
          
          //convert function
          converting(decimalNumber, numerator, denominator);
          
          
          //call simplyfication funcition
          simplifying(numerator, denominator);
          
          
          cout<< "Fraction: "<< numerator << "/" << denominator<< endl;
           return 0; 
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-01-06
            • 2020-06-18
            • 2017-02-19
            • 1970-01-01
            • 1970-01-01
            • 2013-05-31
            • 2018-07-04
            • 1970-01-01
            相关资源
            最近更新 更多