如何找到(最佳)不同精度的整数比?

时间:2018-04-24 10:11:05

标签: algorithm floating-point approximation

如果我的变种m类型uint32r类型uint16以及常量float64,其值为f=0.5820766091346741 }。如何查找满足m,r的{​​{1}}?

类似于python中的Fraction.limit_denominator

这个github repo包含各种最合理的近似算法,但只限制了分母。

4 个答案:

答案 0 :(得分:1)

直截了当的答案是:

     ROUND(f * 10^8)
f = ----------------
         10^8

然后,您可以实现一个小循环,尝试将质数和分母除以质数(从2开始向上)。类似的东西(当然没有检查代码):

var m = f * 10^8 ;
var r = 10^8     ;
var Prime_Numbers = [2,3,5,7,11,13,17,19,....] ;

for (var I = 0 ; I < Prime_Numbers.length ; I++) {

    if ((Prime_Numbers[I] > m) ||
        (Prime_Numbers[I] > r)    ) {

       break;
    }

    if (((m % Prime_Numbers[I]) == 0) &&
         (r % Prime_Numbers[I]) == 0)    ) {
          m = m / Prime_Numbers[I] ;
          r = r / Prime_Numbers[I] ;
    }

console.log("Best m is: " + m) ;
console.log("Best r is: " + r) ;
:
:
}

现在,问题是我应该在列表中包含多少个主要数字?

很难说,但直觉上并不是太多...我会说这将取决于严谨你对 OPTIMAL 的看法。

希望这会给你一些指导。

干杯!!

修改

进一步思考,要始终获得ABSOLUTE OPTIMAL值,您需要将所有主数字包括在您希望的最大值的一半作为精度。例如,如果游览精度需要为8位数(99999999),则需要包括所有主数字(99999999/2)。

编辑2

在循环中添加退出条件。

答案 1 :(得分:1)

有一个paper by David T. Ashley et al.提出了一种算法,通过两个不同精度的整数来找到有理逼近。

我实施了basic version,其中不包含推荐论文1的全部复杂性。

基本思想是将浮点数转换为连续分数,然后寻找满足约束的最高阶收敛。有关convergents的介绍,请参见wiki

然而,参考文献描述了一种更复杂的方法,即对整数配给应用约束(见第5节),它使用类似于晶格结构的1

答案 2 :(得分:0)

  

如何查找满足m,r的{​​{1}}?

f=r/m意味着确切。

要完成 ,如果可能,请参阅下文。如果不能满足=的精确解,那么这种方法不会尝试最佳拟合。

所有有限浮点值都是 exact 。 &#34; 0.5820766091346741&#34;保存在f=r/m中可能会给f附近的值,但f中的值是准确的。

给定浮点数的 base (通常为2),它们都可以用:&#34;整数/(base exponent )&#表示。 34。

使用binary64,所需的最大指数约为(1023 + 53)。

由于OP希望结果​​符合32位f和16位r,因此很容易理解大多数m(64位)都没有完全解决方案 - 只需not enough combinations即可保存结果。

下面的注释C中假设基数为2的算法。

float64

答案 3 :(得分:0)

我没有给你一个算法,因为,IMO,继续分数是正确的道路。

但我想说明这种浮点表示是否适合64位IEEE754。所以我在Smalltalk(Squeak 64位)中使用了这个概念。

r / m表示只有48位,许多组合表示相同的值(1/1 = 2/2 = ... 1/2 = 2/4 = 3/6 = ...)在区间[0.5,1.0]中已经有2 ^ 53个不同的64位浮点数。所以我们可以说大多数时候,我们不会完全匹配f。问题是找到一个最接近f的对(r / m)。

我无法合理地使用48位,但我可以精确到半,并收集所有uint8 / uint16组合:

v := Array new: 1<<24.
0 to: 1<<8-1 do: [:r |
    0 to: 1<<16-1 do: [:m |
        v at: (m<<8+r+1) put: ([r asFloat/m asFloat]
            on: ZeroDivide do: [:exc | exc return: Float infinity])]].
s := v asSet sorted.
s size-2.

除了0和inf之外,在16,777,216中有大约10,173,377种不同的组合。

我对两个连续可表示的花车之间的差距感兴趣:

x := s copyFrom: 2 to: s size - 1.
y := (2 to: s size-1) collect: [:i |  (s at: i) - (s at: i-1) / (s at: i) ulp].

最小值是

u := y detectMin: #yourself.

约2.71618435e8 ulp。

让我们看看分子和分母是如何形成的:

p := y indexOf: u.
{((v  indexOf: (x at: p)) - 1) hex.
 ((v  indexOf: (x at: p-1)) - 1) hex}.

导致#('16rFDFFFE' '16rFEFFFF')前4位编码den(m),后两位num(r)。

因此获得了

的最小差距
s1 := (1<<8-1) / (1<<8-1<<8-1).
s2 := (1<<8-2) / (1<<8-2<<8-1).
s2 asFloat - s1 asFloat / s2 asFloat ulp = u.

大约是1/256(或接近某处)的值。

我们可以推测,48位再入的最小间隙是

s1 := (1<<16-1) / (1<<16-1<<16-1).
s2 := (1<<16-2) / (1<<16-2<<16-1).
s2 asFloat - s1 asFloat / s2 asFloat ulp.

那是大约16 ulp,并没有那么糟糕,最大密度大约是1/65536(或接近某处)。

在你的例子中,密度接近0.5是多少? 对于24位表示:

h := x indexOf: 0.5.

是10133738.让我们检查附近的精确度:

k := (h to: h +512) detectMin: [:i | (y at: i)].
u2 := y at: k.

那是3.4903102168e10 ulp(密度减少约128倍)。它是为了获得:

s1 := (1<<8-1) / (1<<8-1<<1-1).
s2 := (1<<8-2) / (1<<8-2<<1-1).
s2 asFloat- s1 asFloat / s2 asFloat ulp = u2.

因此,对于48位,我们可以预期密度约为

s1 := (1<<16-1) / (1<<16-1<<1-1).
s2 := (1<<16-2) / (1<<16-2<<1-1).
s2 asFloat- s1 asFloat / s2 asFloat ulp.

即524320 ulp,或精度约为5.821121362714621e-11。

编辑:最差精度怎么样?

在最佳密度区域:

q := (p-512 to:p+512) detectMax: [:i | y at: i].
{((v  indexOf: (x at: q)) - 1) hex.
 ((v  indexOf: (x at: q-1)) - 1) hex.}.

那是#('16rFEFFFF' '16r10001'),或者换句话说,就在最佳精度之前,我们在本地最差:w := y at: q.对于这些数字是6.8990021713e10 ulp:

s2 := (1<<8-1) / (1<<8-1<<8-1).
s1 := (1) / (1<<8).
s2 asFloat - s1 asFloat / s2 asFloat ulp = w.

转换为48位,即大约1.048592e6 ulp:

s2 := (1<<16-1) / (1<<16-1<<16-1).
s1 := (1) / (1<<16).
s2 asFloat - s1 asFloat / s2 asFloat ulp.

接近0.5,最差的是24位的8.847936399549e12 ulp:

j := (h-512 to: h +512) detectMax: [:i | (y at: i)].
w2 := y at: j.
s2 := (1<<8-1) / (1<<8-1<<1-1).
s1 := (1) / (1<<1).
s2 asFloat- s1 asFloat / s2 asFloat ulp = w2.

或翻译为48位,3.4360524818e10 ulp:

s2 := (1<<16-1) / (1<<16-1<<1-1).
s1 := (1) / (1<<1).
s2 asFloat- s1 asFloat / s2 asFloat ulp.

那是关于绝对精度的3.814784579114772e-6,不是那么好。

在采用这样的表示之前,最好知道f的域是什么,并了解平均精度,以及在该域中可实现的最差情况精度。