我正在研究谐波比例程序,我希望用户能够做的部分是插入各种比率,并且正在播放的十进制值频率显示更高的比率锁定频率或低。
无论如何,在这个网页上有一个javascript算法来显示给定小数的小数值(比率)。
http://www.mindspring.com/~alanh/fracs.html
它是如何工作的?我有兴趣自己实现它,但我真的不明白它是如何运作的。如果你尝试一些分数,它会给你很多选项(一些带有额外的小数),所以它不仅仅是GCD。
编辑:如果这个算法问题更适合程序员。请告诉我,我会转发并删除它。
答案 0 :(得分:2)
正在计算连续分数并显示它。连续分数中的每个项都会为您提供另一个更好的数量级。
有关您可以选择使用的更详细说明和替代算法,请参阅Algorithm for simplifying decimal to fractions。
答案 1 :(得分:1)
您可以利用 IEEE 754 ,因为您的十进制值很可能存储在其中,它使用整数二进制表示,其中尾数是整数,指数也可以转换为整数除法,因此您可以提取{{ 1}}从中直接形成。对于32位浮点数,我们得到了:
a/b
现在以1 bit sign
8 bit exponent (with bias 127)
23+1 bit mantissa (the highest bit is not present in binary but it is 1).
为例。如果我将此float内容读作整数类型,则将其存储为:
float 3.14159265358979
这样:
0x40490FDB hex
0100 0000 0100 1001 0000 1111 1101 1011 bin
0 10000000 10010010000111111011011 bin
s exponent mantissa
如果我将其定义为“代数”等式,我得到了:
3.14159265358979 = +1.10010010000111111011011b*2^(10000000b-01111111b)
3.14159265358979 = +110010010000111111011011b/2^(23-(10000000b-01111111b))
3.14159265358979 = +110010010000111111011011b/2^(23-(10000000b-01111111b))
3.14159265358979 = +110010010000111111011011b/2^22
3.14159265358979 = +110010010000111111011011b/2^22
3.14159265358979 = 13176795 / 4194304 = 3.1415927410125732421875
现在您可以应用 GCD 或者您想要的...这里有简单的 C ++ 代码:
float = (sign) (mantissa+2^23) / 2^(23-(exp-127))
当我们得到二进制指数时,void fraction(int &a,int &b,float c) // a/b ~= c
{
union // convert between float and integer representation
{
float f32;
unsigned int u32;
} x;
x.f32=c;
int s,e;
s =x.u32&0x80000000; // sign bit
a =x.u32&0x007FFFFF; // mantisa
a|= 0x00800000; // add MSB in mantisa (not present in float representation)
e =(x.u32>>23)&0xFF; // exponent
e-= 0x7F; // exponent bias to make exponent signed again
// (optional) divide by 2 while you can (too lazy for GCD as b will be always power of 2 ...) it is better to do it on e instead of b to avoid possible overflows
while ((a>=2)&&((a&1)==0)) { a>>=1; e++; }
b=1<<(23-e); // b= 2^(23-exp)
if (s) a=-a; // sign
}
将始终是b
的幂。这意味着,而不是 GCD 足以将2
除以a
,而我们可以并且首先增加指数2
或除e
在通常小得多的数字上应用 GCD 之后。最好在b
上应用此方法以避免溢出,因为最终指数为e
,结果e=<-104,151>
只是整数,因此它需要的位数要少得多。在这种情况下b
不适合整数相反(将b
乘以2并递减a
或将e
乘以2直到它适合和/或削减一些低位尾数...)
此处链接的页面中的示例:
b
除非你在字符串或任意精度上计算它,否则由于浮动舍入问题你不能得到更好的结果。所以只需选择你想要的浮动精度(32位 a b a / b c
13176795 / 4194304 = 3.141593 ~= 3.141593
11863283 / 8388608 = 1.414214 ~= 1.414214
13573053 / 8388608 = 1.618034 ~= 1.618034
46751 / 128 = 365.242188 ~= 365.242188
,64位float
,80位double
,......)提取尾数,指数并转换为extended
希望现在已经足够清楚了。如果您想知道我们如何从(字符串/值)获取 IEEE 754 表单,它归结为转换为二进制。我们只需要小数部分,这是通过源基(a/b
或2
)中的目标基(10
)的连续乘法来完成的。因此,在每次迭代中乘以该值,结果的整数部分为新数字,并使用小数部分进行下一次迭代...重复,直到该值为非零或使用最大位数。
2^8,2^16,2^32,...