65.9K
CodeProject 正在变化。 阅读更多。
Home

小数转分数的简便方法

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.89/5 (9投票s)

2011年3月9日

CPOL

2分钟阅读

viewsIcon

120599

downloadIcon

891

如何在 C# 中将给定的十进制数或双精度数转换为分数

引言

将小数简化为分数在编写解决数学问题的程序时非常有用。用分数表示长小数和循环小数比它们的小数形式更清晰。

背景

在研究了确定分数的小数算法后,大部分内容来自一篇 1991 年发表的论文,我觉得它有点复杂,并且在 stackoverflow 上提问后,我决定编写一个更简单的代码,以一种清晰的方式完成相同的任务。但是,此代码有一些缺点,因为它主要侧重于使用 string 操作(一种更自然的方式)来实现其目的。

Using the Code

该代码非常易于使用。有一个名为 dec2frac 的方法,它接受一个 double 参数。调用此方法会返回简化小数的等效分数的 string 表示形式。

它是如何工作的:

  1. 确定给定的十进制数是否为负数。
  2. 将十进制数转换为绝对值。
  3. 获取给定小数的整数部分。
  4. 获取小数部分。
  5. 检查小数是否为循环小数。如果小数是循环小数,则返回精确的循环小数。
  6. 如果小数不是循环小数,则通过将分子更改为 10^小数位数来开始简化,否则从分子中减去 1。
  7. 然后简化分数。

让我们看一下 dec2frac 方法

private static string Dec2Frac(double dbl)
        {
            char neg = ' ';
            double dblDecimal = dbl;
            if (dblDecimal < 0)
            {
                dblDecimal = Math.Abs(dblDecimal);
                neg = '-';
            }
            var whole = (int) Math.Truncate(dblDecimal);
            if (whole == dbl) {
                return String.Format("{0} because supplied value is not a fraction", dbl); //return no if it's not a decimal
            }
            string decpart = dblDecimal.ToString(CultureInfo.InvariantCulture).Replace(Math.Truncate(dblDecimal) + ".", "");
            double rN = Convert.ToDouble(decpart);
            double rD = Math.Pow(10, decpart.Length);

            string rd = Recur(decpart);
            int rel = Convert.ToInt32(rd);
            if (rel != 0)
            {
                rN = rel;
                rD = (int) Math.Pow(10, rd.Length) - 1;
            }
            //just a few prime factors for testing purposes
            var primes = new[] {47, 43, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2};
            foreach (int i in primes) reduceNo(i, ref rD, ref rN);

            rN = rN + (whole*rD);
            return string.Format("{0}{1}/{2}", neg, rN, rD);
        }  

首先,我们注意十进制数是否为负数,然后获取十进制数的整数部分。然后,我们通过适当地将数字除以 10 的幂来简化小数部分。

接下来,我们使用 recur 方法检查它是否是循环小数,如果存在循环小数,该方法将以 string 格式返回循环小数。这是因为小数部分可能以零开头,如 1 / 11 所示。这里

private static string Recur(string db)
{
    if (db.Length < 13) return "0";
    var sb = new StringBuilder(); 
    for (int i = 0; i < 7; i++)
    {
        sb.Append(db[i]);
        int dlength = (db.Length/sb.ToString().Length); 
        int occur = Occurence(sb.ToString(), db);
        if (dlength == occur || dlength == occur - sb.ToString().Length)
        {
            return sb.ToString();
        }
    } 
    return "0";
}   

关注点

在开发这个类时,我发现 C# String 类不够强大(目前不再成立,因为 LINQ 提供了许多用于任何类型操作的方法)。例如,我找不到一种方法来查找 string 或字符在 string 中出现的次数,并且不得不自己开发一个,如 occurrence 方法。

private static int Occurence(string s, string check)
{
    int i = 0;
    int d = s.Length;
    string ds = check;
    for (int n = (ds.Length/d); n > 0; n--)
    {
        int si = ds.IndexOf(s, StringComparison.Ordinal);
        if (si != -1)
        {
            i++;
            ds = ds.Remove(si, d);
        }
    }
    return i;
}

值得注意的是,此方法会做你可能认为它所做的事情。此方法检查某个数字在另一个数字中出现的次数,以确定某个数字是否为循环小数。

历史

这是编写一个简单的分数转换类的第一次成功尝试,于 2011 年 3 月 6 日编写和发布。如果我以后对其进行改进,代码将会更新。

© . All rights reserved.