在Objective-C中将十进制转换为分数?

9
我试图将小数点后的所有内容转换为分数并显示出来。在objective-c中找不到太多关于如何实现这一点的资料。我使用double格式化变量,不确定是否会有影响。这是我用于输出答案的格式:[theTextField setText:[NSString stringWithFormat:@"%f''", (myVariable)]]; 这样显示为十进制数,但我真的希望它是一个整数和一个分数(例如)7 1/2而不是7.5000。谢谢您提前的帮助!
更新:2011年5月13日
好吧,我已经成功地将其显示为7 1/16,但数学计算似乎有误。因为即使更改被除数的值,它也不会从1/16改变。我在哪里出错了?如果有人能够正确地解决这个问题,请完整地发布如何完成的方法。这是应该很简单但却耗费时间的事情。请完整地发布如何完成的方法。谢谢。
更新: 如果这个答案对你不起作用,请查看我的另一篇文章,这个可以! 将小数转换为分数
2个回答

8

Objective-C在基本的数学运算中使用纯C语言。

话虽如此,您可以在这个问题的答案中找到所有必要的信息(以及C代码):

如何将浮点数转换为易于阅读的分数?

(特别是包含实际C代码此答案。)

以下是所述算法的快速C函数封装:

typedef struct {
    long nominator;
    long denominator;
    double error;
} Fraction;

/*
 * Find rational approximation to given real number
 * David Eppstein / UC Irvine / 8 Aug 1993
 *
 * With corrections from Arno Formella, May 2008
 * Function wrapper by Regexident, April 2011
 *
 * usage: fractionFromReal(double realNumber, long maxDenominator)
 *   realNumber: is real number to approx
 *   maxDenominator: is the maximum denominator allowed
 *
 * based on the theory of continued fractions
 * if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...)))
 * then best approximation is found by truncating this series
 * (with some adjustments in the last term).
 *
 * Note the fraction can be recovered as the first column of the matrix
 *  ( a1 1 ) ( a2 1 ) ( a3 1 ) ...
 *  ( 1  0 ) ( 1  0 ) ( 1  0 )
 * Instead of keeping the sequence of continued fraction terms,
 * we just keep the last partial product of these matrices.
 */
Fraction fractionFromReal(double realNumber, long maxDenominator) {
   double atof();
   int atoi();
   void exit();

   long m[2][2];
   double startx;
   long ai;

   startx = realNumber;

   // initialize matrix:
   m[0][0] = m[1][1] = 1;
   m[0][1] = m[1][0] = 0;

   // loop finding terms until denom gets too big:
   while (m[1][0] *  (ai = (long)realNumber) + m[1][1] <= maxDenominator) {
       long t;
       t = m[0][0] * ai + m[0][1];
       m[0][1] = m[0][0];
       m[0][0] = t;
       t = m[1][0] * ai + m[1][1];
       m[1][1] = m[1][0];
       m[1][0] = t;

       if (realNumber == (double)ai) {
           // AF: division by zero
           break;
       }

       realNumber = 1 / (realNumber - (double)ai);

       if (realNumber > (double)0x7FFFFFFF) {
           // AF: representation failure
           break;
       }
   }

   ai = (maxDenominator - m[1][1]) / m[1][0];
   m[0][0] = m[0][0] * ai + m[0][1];
   m[1][0] = m[1][0] * ai + m[1][1];
   return (Fraction) { .nominator = m[0][0], .denominator = m[1][0], .error = startx - ((double)m[0][0] / (double)m[1][0]) };
}

这样调用:

double aReal = 123.45;
long maxDenominator = 42;
Fraction aFraction = fractionFromReal(aReal, maxDenominator);
printf("Real %.3f -> fraction => %ld/%ld, error: %.3f\n",
       aReal,
       aFraction.nominator,
       aFraction.denominator,
       aFraction.error);

打印出这个:
Real 123.450 -> fraction => 3827/31, error: -0.002

最后,让我们看看如何将新创建的分数添加到文本框中:
double myVariable = 7.5;
long maxDenominator = 1000; //sample value
Fraction myFraction = fractionFromReal(abs(myVariable - (NSInteger)myVariable), maxDenominator);
[theTextField setText:[NSString stringWithFormat:@"%d %d/%d", (NSInteger)myVariable, myFraction.nominator, myFraction.denominator]];

期望输出:"7 1/2",实际输出:"7 499/999"
关于为什么会出现这种情况的一些信息,请参见相关问题的答案:如何将浮点数转换为人类可读的分数?


你试过使用这个吗?它会给出4个警告并导致应用程序崩溃,不确定需要修复什么。这应该放在.m文件中对吧? - Jason
对我来说可以用。尝试将"main(ac, av) int ac; char ** av; {"替换为"int main (int ac, const char * av[]) {",它应该能正常工作。 - Regexident
通过将名称从main更改为convert并在末尾添加return 0;,成功解决了问题。谢谢! - Jason
这在很大程度上取决于您之后要对分数做什么。将实数转换为分数并不总是无损的。(正如我的示例输出所显示的那样)因此,通常应在显示前的最后一步执行转换,以确保最佳精度。顺便说一句,我为方便起见添加了一个快速函数封装到我的答案中。 - Regexident
我只是将分数转换后显示在文本框中,就这样。上面是我将答案显示为十进制数的方法,如何在上面的代码中调用它? - Jason
显示剩余11条评论

7

我已经编写了将十进制转换为最简分数的代码,这个功能完美运行。

-(int)gcdForNumber1:(int) m andNumber2:(int) n 
{
    while( m!= n) // execute loop until m == n
    {
        if( m > n)
            m= m - n; // large - small , store the results in large variable<br> 
        else
            n= n - m;
    }
    return ( m); // m or n is GCD
}


-(int)tenRaisedTopower:(int)decimalLength { 
    int answer = 10; 
    while (decimalLength!= 1) {
        answer *= 10;
        decimalLength -- ; 
    } 
    return answer;
}

-(void)floatToFraction:(float)decimalNumber 
{
    NSString *decimalString = [NSString stringWithFormat:@"%f", decimalNumber];
    NSArray *components = [decimalString componentsSeparatedByString:@"."];
    int decimalLength = [[components objectAtIndex:1] length];
    int n = [self tenRaisedTopower:decimalLength];
    int m = [[components objectAtIndex:1] intValue];
    int gcd = [self gcdForNumber1:m andNumber2:n];
    int numer = m/gcd;
    int deno = n/gcd;
    int fractionnumer = ([[components objectAtIndex:0] intValue] * deno) + numer;
    NSLog(@"answer>>%d/%d", fractionnumer, deno);
}

调用方法的方式如下:

[self floatToFraction:2.5];  

你应该熟悉StackOverflow的代码格式:http://stackoverflow.com/editing-help。特别要注意的是,你不需要使用HTML的`<br>`标签来换行。看看我如何编辑你的答案。 - user47589
当您不使用正整数时,这会有一个问题。模块化方法应适用于任何整数。
  • (int)gcdForNumber1:(int) m andNumber2:(int) n { while( n!=0) { int temp = n; n = m % temp; m = temp; } return (m); }
- Paul Solt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接