如果我的变种m
类型uint32
和r
类型uint16
以及常量float64
,其值为f=0.5820766091346741
}。如何查找满足m,r
的{{1}}?
类似于python中的Fraction.limit_denominator。
这个github repo包含各种最合理的近似算法,但只限制了分母。
答案 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的域是什么,并了解平均精度,以及在该域中可实现的最差情况精度。