【问题标题】:Converting a float into a string fraction representation将浮点数转换为字符串分数表示
【发布时间】:2011-08-23 13:00:51
【问题描述】:

在 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 中做到这一点?

【问题讨论】:

  • 但是1.33333 不是1 1/3,而是1 33333/100000。我想你想为这样的重复数字设置某种模糊阈值,否则任何算法都几乎不可能得出你想要的答案(而不是“正确”的答案)。
  • 另见Stern–Brocot,显示为here

标签: java string floating-point fractions


【解决方案1】:

最简单的方法可能是反复试验。

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 位数。
  • 这对我来说效果很好。这是针对我正在开发的烹饪应用程序,所以它不需要非常复杂。永远不会有“1 7/8 杯牛奶”之类的东西。只要 1/2、3/4、1/4 和 1/3 等常见的东西有效,我就很好。
  • 这个因子可以让你确定你想要的最大分母,它会找到最接近的近似值。
【解决方案2】:

查看链分数。这使您可以在给定的精度范围内确定分母和分数。

对于 Pi,您可以获得 22/7 或 355/113,具体取决于您选择停止的时间。

【讨论】:

    【解决方案3】:

    这可能会有所帮助:

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

    否则,您需要某种方式来告诉 Convert() 您想要多远。也许是最大减少的恶魔或类似的东西。这样,您将在上面的前两个示例中获得“1 1/3”,而不是第一个示例为“1 33333/100000”,第二个示例为“1 333/1000”。

    【讨论】:

      【解决方案4】:

      提取数字的小数部分(例如,((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
      

      【讨论】:

        【解决方案5】:

        假设您有“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 次方。
        【解决方案6】:

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

        if (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));
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2011-11-25
          • 1970-01-01
          • 2019-08-13
          • 1970-01-01
          • 2014-09-25
          • 2020-12-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多