我正在尝试将十进制数转换为小数。十进制数的小数位后最多有4位。例如:- 12.34 = 1234/100 12.3456 = 123456/10000
密码:
#include <stdio.h>
int main(void) {
double a=12.34;
int c=10000;
double b=(a-floor(a))*c;
int d=(int)floor(a)*c+(int)b;
while(1) {
if(d%10==0) {
d=d/10;
c=c/10;
}
else break;
}
printf("%d/%d",d,c);
return 0;
}
字符串
但我没有得到正确的输出,十进制数将只有双精度。请指导我应该怎么做。
7条答案
按热度按时间qltillow1#
如果你的浮点数是
x
,那么超过10000的分数的分子将是(x + 0.00005) * 10000
的整数部分。这取决于你是否要将分数简化为最简单的项(即除以分子和分母的gcd)。dsekswqp2#
字符串
问题是
b
得到的是3400.00,但是当你执行(int) b
时,你得到的是3399,所以你需要加上0.5
,这样数字就可以截断为3400。得到3400.00与得到3400不同,3400.00意味着数字被舍入到3400,这就是为什么当你做(int)3400.00时,它假设最接近的整数(小于你正在转换的数字)是3399,但是,当你向那个数字添加0.5时,最后一个最接近的整数现在是3400。
如果你想更深入地了解浮点运算,请阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic
eiee3dmh3#
我的解决方案很简单,“懒惰”,通过迭代运行,没有什么花哨的。
在大多数有一个不错的数学库的语言中,你只需要算法本身。
但是在bc中,您需要实现一些简单的函数,例如
字符串
如果在(1/eps)次迭代后没有找到任何东西,则循环将以最后一个结果中断。
型
在标准精度(eps=.0001)下,可以得到:
型
n53p2ov04#
下面是我使用的算法。它是一个迭代过程,工作原理如下:
1.分子的初始近似值为1,分母为1除以浮点值的小数部分。例如,当将0.06转换为小数时,分母= 1/0.06 = 16.6666667(四舍五入为17),因此初始近似值为1/17。
1.计算浮点值和当前近似值之间的差值。例如,差值为1/17 - 0.06 = 0.058824 - 0.06 =-0.001176。
1.如果差值的绝对值小于定义的公差(即0.000005),则迭代终止。
1.使用步骤2中计算的差值来改进分数的近似。这是通过将差值转换为分数并添加(或减去)到当前近似值。在示例中,负差值表示低近似值--因此需要将差值添加到当前近似值中。差值分数为分子= 1,分母= 1/0.001176 = 850 --分数差为1/850。新的近似值为(1/17)+(1/850)=(8501 + 171)/(850*17)= 867/14450。
1.重复步骤2至4,直到找到解决方案。
1.在找到解之后,分数可以被减小。例如,867/14450正好是0.06,并且迭代过程终止。867/14450可以被减小到3/50。
这种方法的一些特点是:
我在github上发布了这个算法的代码--https://github.com/tnbezue/fraction
wz1wpwve5#
这是一个有趣的问题。我想你可能最好从阅读关于计算“最大公约数”的倍数方法开始(http://en.wikipedia.org/wiki/Greatest_common_divisor是一个很好的来源)。
实现一个快速和肮脏的算法,使这些计算就像你用笔和纸做的那样,然后研究如何表示双精度(符号,指数,尾数),并改进你的算法以利用这种表示。
不幸的是,如果不写你的代码,我也做不了什么。
ulmd4ohb6#
一个用c++创建的算法,可以从小数到分数。
字符串
6ojccjat7#
正确的解决方案是使用continued fraction。用与问题相关的可理解的术语总结维基百科文章:每个十进制数都可以用一个连续的分数表示,达到所需的准确度,然后计算为:一个整数,一个分子和一个分母(即三个独立的整数值)。连续的分数也恰好产生完全约化的分数。
第一步是从浮点数生成连分数项。下面是广义伪代码,其中假设输入数为正数(支持负数作为练习,但我们实际上只关心小数部分,例如0.34):
字符串
下面是结果向量,其中包含12.34至约4位小数精度的连分数项:
型
下一步是通过向后遍历生成的向量/数组并建立分子和分母来执行连分数计算本身。下面是使用上面的术语填写的连分数公式:
12+(1 /(2+(1 /(1+(1 /16))
简化后的计算如下:
型
17/50也恰好是不可约的,因为17是一个素数,这有助于验证前面的陈述,即连分数是完全约化的。
上面的数学 * 看起来 * 很复杂,但上面计算的伪代码非常简单:
型
先前向量的示例值:
型
正如在其他地方所指出的,浮点数是不精确的。这可能导致在连分数
result
向量中出现非常大的数字,即使上面的阈值取决于输入的值。您必须决定什么精度阈值对您的应用程序有意义。您始终可以过度生成
result
矢量精度(例如1.0e-15)和估计的最大值(例如1.0e15),然后基于硬分母限制多次执行连续分数计算步骤,直到不再超过您设置的阈值。作为应用上述过度生成技术的一个示例,假设您将分母的硬限制设置为49。测试上面的完整向量的结果为17/50,正如我们之前看到的那样。由于50大于49,因此我们可以从向量中删除最后一项并再次尝试连分数计算:
12+(1 /(2+(1 /1)
型
12.333333是12.34的一个相当好的估计(在一定的误差范围内),分母3现在福尔斯在所需的最大分母阈值49内。作为旁注,1/3也恰好是不可约的。如果分母仍然不够小,只要不断地删除末尾的项并重新计算,直到它足够小。删除项会增加误差量,但也会减少分母的值。
各种图形计算器,甚至Microsoft Excel都以这种方式使用连分数来显示浮点数作为分数。我也见过一些在线连分数计算器。因此,您可以利用这些工具来确认您自己的实现是否正常运行。