在数学和编程领域,将小数转换为分数是一种常见的需求。传统的算法往往复杂且不易理解。本文将介绍一种简化的算法实现,该算法能够将小数以分数的形式清晰地表示出来。
在研究了1991年的一篇论文以及其他一些资料后,发现现有的算法对于将小数转换为分数的处理过于复杂。因此,决定编写一个更简洁的代码来实现相同的功能。尽管这个代码主要侧重于使用字符串操作来实现目的,但它也有一些局限性。
这个代码的使用非常简单。它提供了一个名为dec2frac
的方法,该方法接受一个double
类型的参数。调用这个方法会返回等效分数的字符串表示形式。
算法的工作原理如下:
以下是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);
}
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;
}
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);
}
以下是检测循环小数的recur
方法的实现:
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";
}
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;
}