Floating point 将浮点数转换为保证转换回原始浮点数的有理数

Floating point 将浮点数转换为保证转换回原始浮点数的有理数,floating-point,fractions,numerical-analysis,rational-number,Floating Point,Fractions,Numerical Analysis,Rational Number,我正在寻找一种算法,将一个浮点数转换为一个有理数,这样可以保证有理数的计算返回到原始浮点数,并且分母最小化 一个简单的算法可以将浮点的实际值返回为X/2N,但是对于任何不是有限二进制分数的东西,2N往往都非常大。例如,当存储在双精度浮点中时,数字0.1实际上近似为3⁶⁰²⁸⁷⁹⁷⁰¹⁸⁹⁶³⁹⁷⁄₃₆₀₂₈₇₉₇₀₁₈₉₆₃₉₆₈ (分母为255)。但是,将0.1转换为1/4₁₀ 显然更好,并且₁₀ 将评估为3⁶⁰²⁸⁷⁹⁷⁰¹⁸⁹⁶³⁹⁷⁄₃₆₀₂₈₇₉₇₀₁₈₉₆₃₉₆₈ 在浮点运算下 一个

我正在寻找一种算法,将一个浮点数转换为一个有理数,这样可以保证有理数的计算返回到原始浮点数,并且分母最小化

一个简单的算法可以将浮点的实际值返回为X/2N,但是对于任何不是有限二进制分数的东西,2N往往都非常大。例如,当存储在双精度浮点中时,数字0.1实际上近似为3⁶⁰²⁸⁷⁹⁷⁰¹⁸⁹⁶³⁹⁷⁄₃₆₀₂₈₇₉₇₀₁₈₉₆₃₉₆₈ (分母为255)。但是,将0.1转换为1/4₁₀ 显然更好,并且₁₀ 将评估为3⁶⁰²⁸⁷⁹⁷⁰¹⁸⁹⁶³⁹⁷⁄₃₆₀₂₈₇₉₇₀₁₈₉₆₃₉₆₈ 在浮点运算下

一个相关的问题是打印小数位数最少的浮点数(这描述了一些技术),这可以被认为是这个问题的一个特殊版本,还有一个额外的限制,即分母必须是10的幂


有,而且可能更多,但它们没有转换后的有理数必须计算为原始浮点的约束。

让我们从一个定义开始,该定义精确地确定在任何特定情况下我们要寻找的分数:

定义。说一个分数
a/b
比另一个分数
c/d
更简单(两个分数都是用最低的术语写的 正分母)如果
b=3.9,则提供一个函数
math.nextafter
,允许我们从
x
上下检索下一个浮点数。下面是一个对最接近π的浮点数执行此操作的示例:

导入数学 >>>x=3.141592653589793 >>>x_plus=math.nextafter(x,math.inf) >>>x_减号=数学下一步(x,0.0) >>>x_加,x_减 (3.1415926535897936, 3.1415926535897927)
(请注意,一般来说,要做到这一点,我们还需要处理特殊情况,
x
是最大的可表示浮点,
math.nextafter(x,math.inf)
给出无穷大。)

四舍五入到
x
的间隔边界位于
x
和相邻浮点数之间的中间位置。Python允许我们将浮点值转换为相应的精确值作为分数:

>>从分数导入分数
>>>左=(分数(x)+分数(x_减))/2
>>>右=(分数(x)+分数(x_+)/2
>>>打印(左、右)
14148475504056879/4503599627370496 14148475504056881/4503599627370496
我们还需要知道我们有一个封闭的还是开放的区间。我们可以查看位表示来了解这一点(这取决于浮点的最低有效位是
0
还是
1
),或者我们可以只测试看看我们的区间端点是否舍入到
x

浮动(左)=x 符合事实的 >>>浮动(右)=x 符合事实的 是的,所以我们有一个封闭的时间间隔。这可以通过查看浮点的十六进制表示来确认:

>>x.hex()
'0x1.921FB542D18P+1'
因此,我们可以使用
simplest\u in\u closed\u interval
,找到四舍五入到
x
的最简单分数:

>>>最简单的间隔(左、右)
分数(24585092278256779)
>>>245850922/78256779==x
符合事实的
把它们放在一起 虽然核心算法很简单,但有足够多的角落案例需要处理(负值、开放与闭合区间、
sys.float\u info.max
等),完整的解决方案最终有点过于混乱,无法在这个答案中完整发布。不久前,我编写了一个名为
simplefractions
的Python包,该包处理所有这些极端情况;是的。这就是它的作用:

>>>从simplefraction从\u float导入最简单的\u
>>>最简单的浮点数(0.1)
分数(1,10)
>>>来自浮点数的最简单浮点数(-3.3333)
分数(-10,3)
>>>最简单的浮点数(22/7)
分数(22,7)
>>>输入数学
>>>最简单的浮点数(math.pi)
分数(24585092278256779)

让我们从一个定义开始,该定义准确地确定了我们在任何特定情况下要寻找的分数:

定义。说一个分数
a/b
比另一个分数
c/d
更简单(两个分数都是用最低的术语写的 正分母)如果
b=3.9,则提供一个函数
math.nextafter
,允许我们从
x
上下检索下一个浮点数。下面是一个对最接近π的浮点数执行此操作的示例:

导入数学 >>>x=3.141592653589793 >>>x_plus=math.nextafter(x,math.inf) >>>x_减号=数学下一步(x,0.0) >>>x_加,x_减 (3.1415926535897936, 3.1415926535897927)
(请注意,一般来说,要做到这一点,我们还需要处理特殊情况,
x
是最大的可表示浮点,
math.nextafter(x,math.inf)
给出无穷大。)

四舍五入到
x
的间隔边界位于
x
和相邻浮点数之间的中间位置。Python允许我们将浮点值转换为相应的精确值作为分数:

>>从分数导入分数
>>>左=(分数(x)+分数(x_减))/2
>>>右=(分数(x)+分数(x_+)/2
>>>打印(左、右)
14148475504056879/4503599627370496 14148475504056881/4503599627370496
我们还需要知道我们有一个封闭的还是开放的区间。我们可以查看位表示来了解这一点(这取决于浮点的最低有效位是
0
还是
1
),或者我们可以只测试看看我们的区间端点是否舍入到
x

浮动(左)=x 符合事实的 >>>浮动(右)=x 符合事实的 是的,所以我们