将浮点数转换为字符串分数表示形式

11

在Java中,我正在尝试找到一种将浮点数转换为分数字符串的方法。例如:

float num = 1.33333;
String numStr = Convert(num); // Should return "1 1/3"

float num2 = 1.333;
String numStr2 = Convert(num2); // Should also return "1 1/3"

float num3 = 0.5;
String numStr3 = Convert(num3); // Should return "1/2"

float num4 = 2.25;
String numStr4 = Convert(num4); // Should return "2 1/4"

有什么想法可以用Java来实现这个功能吗?


6
但是 1.33333 不是 1 1/3,它是 1 33333/100000。我想你希望有一定的模糊阈值来处理这种重复的数字,否则任何算法都很难得出你想要的答案(而不是“正确”的答案)。 - CanSpice
请参见Stern-Brocot,此处显示链接 - trashgod
6个回答

12

最简单的方法可能是试错。

public static String toFraction(double d, int factor) {
    StringBuilder sb = new StringBuilder();
    if (d < 0) {
        sb.append('-');
        d = -d;
    }
    long l = (long) d;
    if (l != 0) sb.append(l);
    d -= l;
    double error = Math.abs(d);
    int bestDenominator = 1;
    for(int i=2;i<=factor;i++) {
        double error2 = Math.abs(d - (double) Math.round(d * i) / i);
        if (error2 < error) {
            error = error2;
            bestDenominator = i;
        }
    }
    if (bestDenominator > 1)
        sb.append(' ').append(Math.round(d * bestDenominator)).append('/') .append(bestDenominator);
    return sb.toString();
}

public static void main(String... args)  {
    System.out.println(toFraction(1.3333, 1000));
    System.out.println(toFraction(1.1428, 1000));
    for(int i=1;i<100000000;i*=10) {
        System.out.println("PI "+i+": "+toFraction(3.1415926535897932385, i));
    }
}

打印

1 1/3
1 1/7
PI 1: 3
PI 10: 3 1/7
PI 100: 3 14/99
PI 1000: 3 16/113
PI 10000: 3 16/113
PI 100000: 3 14093/99532
PI 1000000: 3 140914/995207
PI 10000000: 3 244252/1725033

我相信对于更大的分母,一定有一个不那么蛮力的解决方案,但是这个方法可以快速处理到6位数字。 - Peter Lawrey
这对我很有效。这是我正在开发的烹饪应用程序,所以它不需要非常复杂。永远不会出现像“1 7/8杯牛奶”这样的东西。只要像1/2、3/4、1/4和1/3这样的常见内容可以使用,我就满意了。 - Icemanind
该因子将让你确定最大的分母,然后找到最接近的近似值。 - Peter Lawrey

1

研究连分数。这可以让你确定给定精度内的分母和分数。

对于圆周率,你可以选择停止时获得22/7或355/113。


0

这可能会有所帮助:

http://www.merriampark.com/fractions.htm

否则,您需要某种告诉Convert()函数您想要将事物拓展到多远的方法。也许是最大分母或类似的东西。这样,您将获得前两个示例中的“1 1/3”,而不是第一个示例中的“1 33333/100000”和第二个示例中的“1 333/1000”。

0
假设您有"0.1234567",然后计算小数点后面有多少数字(这是7)。 然后将数字乘以10 ^ 7,现在您有“1234567”。
将1234567除以10 ^ 7。 然后使用两个数字的GCD简化分数。
0.1234567 * 10000000 = 1234567
=> 1234567 / 10000000
=> System.out.println(1234567 / gcd(1234567,10000000) + "/" + 10000000/gcd(1234567,10000000));

问题在于Java(以及大多数其他语言)中的浮点数不是十进制,而是二进制。因此,您必须使用适当的2的幂而不是10的幂。 - Paŭlo Ebermann

0

修改了FOR循环以在已经确定最佳分母时中断循环。

如果(error2 == 0)则中断;

public static String toFraction(double d, int factor) {
    StringBuilder sb = new StringBuilder();
    if (d < 0) {
        sb.append('-');
        d = -d;
    }
    long l = (long) d;
    if (l != 0) sb.append(l);
    d -= l;
    double error = Math.abs(d);
    int bestDenominator = 1;
    for(int i=2;i<=factor;i++) {
        double error2 = Math.abs(d - (double) Math.round(d * i) / i);
        if (error2 < error) {
            error = error2;
            bestDenominator = i;
            if (error2 == 0) break;
        }
    }
    if (bestDenominator > 1)
        sb.append(' ').append(Math.round(d * bestDenominator)).append('/') .append(bestDenominator);
    return sb.toString();
}

public static void main(String... args)  {
    System.out.println(toFraction(1.3333, 1000));
    System.out.println(toFraction(1.1428, 1000));
    for(int i=1;i<100000000;i*=10) {
        System.out.println("PI "+i+": "+toFraction(3.1415926535897932385, i));
    }
}

0

提取数字的小数部分(例如,((int) 0.5 + 1) - 0.5),然后将其除以结果(1 / 0.5)。您将获得分数的分母。然后将浮点数转换为整数,您将获得整数部分。然后将两者连接起来。

这只是一个简单的解决方案,仅在分数的分子为1时有效。

double n = 1.2f;

int denominator = 1 / (Math.abs(n - (int) n - 0.0001)); //- 0.0001 so the division doesn't get affected by the float point aproximated representation
int units = (int) n;

int numerator = units * denominator + 1;

System.out.println("" + numerator + "/" + denominator); //6/5
System.out.println("" + units + " 1/" + denominator); //1 1/5

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