分数化循环小数C++实现
引言
前一阵做了一个有理数四则混合运算的程序(详见:用C++实现的有理数(分数)四则混合运算计算器),以分数形式呈现运算结果。这次添加以循环小数形式呈现运算结果的功能。例如:
Please input a rational expression to calculate its value or input q to quit:
67+34*(23-78/(54*5))-2*(5/37-6.5789)
= 67 + 34 * ( 23 - 78 / ( 270 ))-2*(5/37-6.5789)
= 67 + 34 * ( 23 - 13/45 )-2*(5/37-6.5789)
= 67 + 34 * ( 1022/45 )-2*(5/37-6.5789)
= 67 + 34748/45 -2*(5/37-6.5789)
= 37763/45 -2*(5/37-6.5789)
= 37763/45 - 2 * ( 5/37 -6.5789)
= 37763/45 - 2 * ( 5/37 - 65789/10000 )
= 37763/45 - 2 * ( -2384193/370000 )
= 37763/45 - -2384193/185000
= 852[108737/1665000] {852.0653`075}
算法分析
由分数化循环小数不像由循环小数化分数那么简单明了。比如 0.2`142857 这个小数,它等于 0.2 加上 0.0`142857,用分数表示分别是 2/10 和 142857/9999990,化简即是 1/5 和 1/70,相加并化简得到分数运算结果:3/14。
现在考察由 3/14 如何反推出 0.2`142857。
1、3 / 14 = 0...3 商为0,得到小数形式结果的整数部分,余数不为0,继续
2、30 / 14 = 2...2 商为2,得到小数点后第1位小数,余数不为0,继续
3、20 / 14 = 1...6 商为1,得到小数点后第2位小数,余数不为0,继续
4、60 / 14 = 4...4 商为4,得到小数点后第3位小数,余数不为0,继续
5、40 / 14 = 2...12 商为2,得到小数点后第4位小数,余数不为0,继续
6、120 / 14 = 8...8 商为8,得到小数点后第5位小数,余数不为0,继续
7、80 / 14 = 5...10 商为5,得到小数点后第6位小数,余数不为0,继续
8、100 / 14 = 7...2 商为7,得到小数点后第7位小数,余数不为0,继续
9、20 / 14 = 1...6 商为1,得到小数点后第8位小数,余数不为0,继续
......
上述试商过程,当进行到第8步时,得到的余数是2,和第2步得到的余数相同,于是从第9步开始就会周而复始重复第3步到第8步的过程。说明已经找到了循环小数的循环体。
由于余数要小于指定的除数(即分数中的分母),上述过程必然会在有限的步数(小于除数)出现相同余数。
算法实现
在 SFraction 里增加 toDecimal 接口:
1 struct SFraction
2 {
3 u64 numerator;
4 u64 denominator;
5 bool bNegative;
6
7 SFraction() {
8 numerator = 0;
9 denominator = 1;
10 bNegative = false;
11 }
12
13 std::string toStr(bool bFinal = false) const;
14 std::string toDecimalStr() const;
15 };
SFraction 的 toDecimal 接口实现如下:
1 std::string SFraction::toDecimalStr() const
2 {
3 std::ostringstream oStream;
4 if (bNegative)
5 {
6 oStream << "-";
7 }
8 u64 quotient = numerator / denominator;
9 oStream << quotient;
10 u64 remainder = numerator % denominator;
11 if (remainder == 0)
12 {
13 return oStream.str();
14 }
15 oStream << ".";
16 u64 pos = 0;
17 u64 posMatched = 0;
18 std::map<u64, u64> mapRemainderPos;
19 std::vector<u64> vecQuotient;
20 while (true)
21 {
22 mapRemainderPos[remainder] = pos++;
23 remainder *= 10;
24 vecQuotient.push_back(remainder / denominator);
25 remainder = remainder % denominator;
26 if (remainder == 0)
27 break;
28 std::map<u64, u64>::iterator it = mapRemainderPos.find(remainder);
29 if (it != mapRemainderPos.end())
30 {
31 posMatched = it->second;
32 break;
33 }
34 }
35 if (remainder == 0)
36 {
37 for (size_t idx = 0; idx < vecQuotient.size(); ++idx)
38 oStream << vecQuotient[idx];
39 return oStream.str();
40 }
41 size_t idx = 0;
42 for (; idx < posMatched; ++idx)
43 oStream << vecQuotient[idx];
44 oStream << "`";
45 for (; idx < vecQuotient.size(); ++idx)
46 oStream << vecQuotient[idx];
47 return oStream.str();
48 }
然后对 SFraction 的 toStr 接口稍作调整,即可达到增加循环小数形式的呈现效果:
1 std::string SFraction::toStr(bool bFinal) const
2 {
3 std::ostringstream oStream;
4 if (bNegative)
5 {
6 oStream << "-";
7 }
8 if (denominator == 1)
9 {
10 oStream << numerator;
11 return oStream.str();
12 }
13 if (!bFinal)
14 {
15 oStream << numerator << "/" << denominator;
16 return oStream.str();
17 }
18 if (numerator < denominator)
19 {
20 oStream << numerator << "/" << denominator << " {" << toDecimalStr() << "}";
21 return oStream.str();
22 }
23 u64 quotient = numerator / denominator;
24 u64 remainder = numerator % denominator;
25 oStream << quotient << "[" << remainder << "/" << denominator << "] {" << toDecimalStr() << "}";
26 return oStream.str();
27 }
完整代码文件提取位置
https://github.com/readalps/RationalCalculator
分数化循环小数C++实现的更多相关文章
- 洛谷P1530 分数化小数 Fractions to Decimals
P1530 分数化小数 Fractions to Decimals 103通过 348提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目 ...
- [C++]2-5 分数化小数
/* 分数化小数 输入正整数a,b,c,输出a/b的小数形式.精确到小数点后C位.a,b<=10^6,c<=10^6. 输入包含多组数据,结束标记为a=b=c=0 样例输入: 1 6 4 ...
- 分数化小数(decimal)
分数化小数 ①我的程序 #include<iostream>using namespace std;int main(void){ int a,b,c,kase=0; while(scan ...
- YTU 1439: 2.4.5 Fractions to Decimals 分数化小数
1439: 2.4.5 Fractions to Decimals 分数化小数 时间限制: 1 Sec 内存限制: 64 MB 提交: 194 解决: 13 题目描述 写一个程序,输入一个形如N/ ...
- Luogu P1530 分数化小数 Fractions to Decimals(模拟)
P1530 分数化小数 Fractions to Decimals 题意 题目描述 写一个程序,输入一个形如\(N/D\)的分数(\(N\)是分子,\(D\)是分母),输出它的小数形式.如果小数有循环 ...
- [LeetCode] Fraction to Recurring Decimal 分数转循环小数
Given two integers representing the numerator and denominator of a fraction, return the fraction in ...
- 【u237】分数化小数
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式.如果小数有循环节的话,把 ...
- 【USACO 2.4.5】分数化小数
[描述] 写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式. 如果小数有循环节的话,把循环节放在一对圆括号中. 例如, 1/3 =0.33333333 写成0.(3), 4 ...
- [LeetCode] 167. Fraction to Recurring Decimal 分数转循环小数
Given two integers representing the numerator and denominator of a fraction, return the fraction in ...
随机推荐
- 【洛谷P2800又上锁妖塔】动态规划
分析 考虑上一层还是上两层还是爬上去 AC代码 #include <bits/stdc++.h> using namespace std; int f[1000005],a[1000005 ...
- Ubuntu 19.10安装Wine软件
======================================== 我使用的操作系统版本为Ubuntu 19.10 64位,如果是32位Ubuntu19.10则可以跳过步骤一 1.添加 ...
- Python实用案例,Python脚本,Python实现批量加水印
往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 Python实现帮你选择双色球号码 Python实现每日更换"必应图片"为"桌 ...
- SpringBoot AOP中JoinPoint的用法和通知切点表达式
前言 上一篇文章讲解了springboot aop 初步完整的使用和整合 这一篇讲解他的接口方法和类 JoinPoint和ProceedingJoinPoint对象 JoinPoint对象封装了Spr ...
- 一口气说出 Redis 16 个常见使用场景!
1.缓存 String类型 例如:热点数据缓存(例如报表.明星出轨),对象缓存.全页缓存.可以提升热点数据的访问数据. 文章首发于:http://ht5n8.cn/LEc6v 2.数据共享分布式 St ...
- XCTF-Web进阶-upload1
显然是让我们上传文件,思路当然是上传一个木马文件,然后通过蚁剑连接查看目录获取flag. 但是当我们想要上传php文件的时候会出现弹窗,并且连"上传"按钮都被禁用了. ext = ...
- 五、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之MVVM中的EventAggregator
这一篇我们主要再看完示例12.13后,写了个例子,用于再Modules下执行ApplicationCommands,使用IActiveAware执行当前View的Commands,或者Applicat ...
- 干了5年Android开发,突然感觉自己啥也不会,啥也不想干,还要继续吗?
这是在某论坛看到的一名同行的吐槽: 我干了差不多5年,不过给人感觉跟只有两三年的人一样. 我觉得我不适合干程序员,主要是新东西的接受能力比其他人慢,Android技术又更新得很快,感觉总是跟不上.年纪 ...
- Linux下使用pure-ftpd建立匿名ftp访问
by 无若 (一)ubuntu14.04下使用pure-ftpd建立匿名ftp访问 1.安装apt-get install pure-ftpd 2.修改配置nano /etc/pure-ftpd/co ...
- [TensorFlow2.0]-张量与常用函数
本人人工智能初学者,现在在学习TensorFlow2.0,对一些学习内容做一下笔记.笔记中,有些内容理解可能较为肤浅.有偏差等,各位在阅读时如有发现问题,请评论或者邮箱(右侧边栏有邮箱地址)提醒. 若 ...