【问题标题】:Convert Floating-point number into a Rational number in Java? [duplicate]在Java中将浮点数转换为有理数? [复制]
【发布时间】:2012-11-04 20:38:49
【问题描述】:

可能重复:
How can I turn a floating point number into the closest fraction represented by a byte numerator and denominator?

我想在 Java 中采用任意浮点数或双精度数并将其转换为有理数 - 即。 a/b 形式的数字,其中 a 和 b 是长整数。我怎样才能以合理有效的方式做到这一点?

(顺便说一句 - 我已经有了简化分数的代码,所以 a/b 是否是最简单的形式并不重要)。

【问题讨论】:

  • 如果你被传递一个无理数怎么办?即,不能表示为 a/b 的数字
  • @Doug Ramsey - 计算机并没有真正的无理数。如果给你一个浮点数或双精度数,这是合理的。
  • 我“相当肯定”有现有的库可以做到这一点。此外,为该过程找到与语言无关(或以另一种语言实现)的算法应该不会太难。
  • 我在这里的回答为您定义的精度提供了最简单的形式stackoverflow.com/questions/5968636/… 这是它将 PI 转换为不同精度级别的示例。
  • 彼得,很有趣——但这真的有效吗?好像不会。

标签: java floating-point rational-numbers


【解决方案1】:

首先看看 double(或 float,但我在下面仅指 double)是constructed by IEEE-754 rules

然后使用Double.doubleToLongBits 将双精度转换为位。 使用此方法1 + bit_0 * 2^(-1) + bit_1 * 2^(-2) ... 计算分数。 将结果乘以指数(准确地说是2^(exponent))和一个符号。

代码如下:

double number =  -0.15625;
// Code below doesn't work for 0 and NaN - just check before

long bits = Double.doubleToLongBits(number);

long sign = bits >>> 63;
long exponent = ((bits >>> 52) ^ (sign << 11)) - 1023;
long fraction = bits << 12; // bits are "reversed" but that's not a problem

long a = 1L;
long b = 1L;

for (int i = 63; i >= 12; i--) {
    a = a * 2 + ((fraction >>> i) & 1);
    b *= 2;
}

if (exponent > 0)
    a *= 1 << exponent;
else
    b *= 1 << -exponent;

if (sign == 1)
    a *= -1;

// Here you have to simplify the fraction

System.out.println(a + "/" + b);

但要小心 - 使用大指数时,您可能会遇到不适合变量的数字。实际上,您可以考虑将指数沿分数存储,并且仅在指数足够小时才将其相乘。如果不是,您必须向用户显示分数,您可以使用科学记数法(这需要求解方程2^n = x * 10^m,其中 m 是您的十进制指数,x 是您必须乘以分数的数字。但这是个问题另一个问题...)。

【讨论】:

  • 谢谢,虽然我希望得到一个更详细的答案,可以描述一种有效的转换方式。
  • 这个过程不会给你一个有理数。它只会给你价值。没有答案。
  • @EJP 使用此方法,您有序列1 + bit * 1/2 + bit * 1/4 ...。不难弄清楚如何从中提取一部分......
  • 这里没有方法,本质上只有尾数的定义。您需要“弄清楚”的是问题的答案。
  • 好吧,我假设每个人都可以添加分数...无论如何我会编辑答案以提供准确的代码。
【解决方案2】:

long bits = Double.doubleToLongBits(double)。来自Double.longBitsToDouble的Javadoc:

...让 s、e 和 m 是可以从参数计算的三个值:

int s = ((bits >> 63) == 0) ? 1 : -1;
int e = (int)((bits >> 52) & 0x7ffL);
long m = (e == 0) ?
             (bits & 0xfffffffffffffL) << 1 :
             (bits & 0xfffffffffffffL) | 0x10000000000000L;

那么浮点结果等于数学表达式s·m·2e-1075的值。

这个结果肯定是一个有理数。

【讨论】:

    【解决方案3】:

    任何 FP 值对应的有理数是 (mantissa/2^-exponent),其中尾数和指数的定义见 IEEE 754(Wiki 参考)。然后,您可以按 LCD(或者我猜是 GCF)应用除法以获得规范的有理数。

    【讨论】:

    • 您知道获得给定浮点数或双精度数的尾数和指数的简单方法吗?
    • 很好的关系,但是.. 缺少如何实现它的细节(在 Java 中)。
    【解决方案4】:

    标题continued fractions 下包含的各种概念产生给定最大分母的最佳可能有理近似值。具体来说,您要问的是计算convergent sequence。在某些时候,当您的分母根据您想要的任何标准足够大时(或被有限整数实现长度强加给您),终止计算收敛项并使用最后一个。在链接的 Wikipedia 页面上对算法进行了相当详细的描述。

    为了解决您提出的一个问题,收敛序列中生成的分数始终为简化形式。它们也可以证明是给定分母的最佳近似值。准确地说,一个 m/n 形式的收敛项比另一个分母

    【讨论】:

      【解决方案5】:

      如您所知,浮点数甚至无法存储simple numbers such as 0.1 exactly。如果您使用幼稚的方法来转换浮点数,那么您最终可能会得到巨大的分子和分母。

      但是,有些算法可能会有所帮助:Dragon4 and Grisu3 算法旨在为浮点数创建最易读的输出。他们利用某些浮点位序列可以用几个小数表示的优势,并选择其中最短的一个。

      对于第一个实现,我将使用 Dragon4 和/或 Grisu3 从浮点中创建最短的小数部分。例如,带有cd cc cc cc cc cc f4 3f 位的浮点数将导致小数 1.3 而不是 1.29999999。然后我会以 a/b 的形式表示小数部分并简化它。在给定的示例中,这将是 13/10,无需进一步简化。

      请注意,转换为小数可能是不利的。例如,有理数 1/3 不能同时用十进制数和浮点数精确表示。因此,最好的解决方案是修改诸如 Dragon4 之类的算法以使用任意小数分母,而不仅仅是 10。唉,这几乎肯定需要大量的工作和一些 CS 背景。

      【讨论】:

        猜你喜欢
        • 2017-09-16
        • 1970-01-01
        • 2015-06-01
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 2014-03-01
        • 2011-11-25
        • 2012-11-15
        相关资源
        最近更新 更多