分数转换算法的小数,它是如何工作的?

时间:2017-09-25 22:36:10

标签: algorithm decimal fractions

我正在研究谐波比例程序,我希望用户能够做的部分是插入各种比率,并且正在播放的十进制值频率显示更高的比率锁定频率或低。

无论如何,在这个网页上有一个javascript算法来显示给定小数的小数值(比率)。

http://www.mindspring.com/~alanh/fracs.html

它是如何工作的?我有兴趣自己实现它,但我真的不明白它是如何运作的。如果你尝试一些分数,它会给你很多选项(一些带有额外的小数),所以它不仅仅是GCD。

编辑:如果这个算法问题更适合程序员。请告诉我,我会转发并删除它。

2 个答案:

答案 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/b2)中的目标基(10)的连续乘法来完成的。因此,在每次迭代中乘以该值,结果的整数部分为新数字,并使用小数部分进行下一次迭代...重复,直到该值为非零或使用最大位数。

2^8,2^16,2^32,...