引言

前一阵做了一个有理数四则混合运算的程序(详见:用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++实现的更多相关文章

  1. 洛谷P1530 分数化小数 Fractions to Decimals

    P1530 分数化小数 Fractions to Decimals 103通过 348提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目 ...

  2. [C++]2-5 分数化小数

    /* 分数化小数 输入正整数a,b,c,输出a/b的小数形式.精确到小数点后C位.a,b<=10^6,c<=10^6. 输入包含多组数据,结束标记为a=b=c=0 样例输入: 1 6 4 ...

  3. 分数化小数(decimal)

    分数化小数 ①我的程序 #include<iostream>using namespace std;int main(void){ int a,b,c,kase=0; while(scan ...

  4. YTU 1439: 2.4.5 Fractions to Decimals 分数化小数

    1439: 2.4.5 Fractions to Decimals 分数化小数 时间限制: 1 Sec  内存限制: 64 MB 提交: 194  解决: 13 题目描述 写一个程序,输入一个形如N/ ...

  5. Luogu P1530 分数化小数 Fractions to Decimals(模拟)

    P1530 分数化小数 Fractions to Decimals 题意 题目描述 写一个程序,输入一个形如\(N/D\)的分数(\(N\)是分子,\(D\)是分母),输出它的小数形式.如果小数有循环 ...

  6. [LeetCode] Fraction to Recurring Decimal 分数转循环小数

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

  7. 【u237】分数化小数

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式.如果小数有循环节的话,把 ...

  8. 【USACO 2.4.5】分数化小数

    [描述] 写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式. 如果小数有循环节的话,把循环节放在一对圆括号中. 例如, 1/3 =0.33333333 写成0.(3), 4 ...

  9. [LeetCode] 167. Fraction to Recurring Decimal 分数转循环小数

    Given two integers representing the numerator and denominator of a fraction, return the fraction in ...

随机推荐

  1. 【洛谷P2800又上锁妖塔】动态规划

    分析 考虑上一层还是上两层还是爬上去 AC代码 #include <bits/stdc++.h> using namespace std; int f[1000005],a[1000005 ...

  2. Ubuntu 19.10安装Wine软件

    ======================================== 我使用的操作系统版本为Ubuntu 19.10 64位,如果是32位Ubuntu19.10则可以跳过步骤一 1.添加 ...

  3. Python实用案例,Python脚本,Python实现批量加水印

    往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 Python实现帮你选择双色球号码 Python实现每日更换"必应图片"为"桌 ...

  4. SpringBoot AOP中JoinPoint的用法和通知切点表达式

    前言 上一篇文章讲解了springboot aop 初步完整的使用和整合 这一篇讲解他的接口方法和类 JoinPoint和ProceedingJoinPoint对象 JoinPoint对象封装了Spr ...

  5. 一口气说出 Redis 16 个常见使用场景!

    1.缓存 String类型 例如:热点数据缓存(例如报表.明星出轨),对象缓存.全页缓存.可以提升热点数据的访问数据. 文章首发于:http://ht5n8.cn/LEc6v 2.数据共享分布式 St ...

  6. XCTF-Web进阶-upload1

    显然是让我们上传文件,思路当然是上传一个木马文件,然后通过蚁剑连接查看目录获取flag. 但是当我们想要上传php文件的时候会出现弹窗,并且连"上传"按钮都被禁用了. ext = ...

  7. 五、从GitHub浏览Prism示例代码的方式入门WPF下的Prism之MVVM中的EventAggregator

    这一篇我们主要再看完示例12.13后,写了个例子,用于再Modules下执行ApplicationCommands,使用IActiveAware执行当前View的Commands,或者Applicat ...

  8. 干了5年Android开发,突然感觉自己啥也不会,啥也不想干,还要继续吗?

    这是在某论坛看到的一名同行的吐槽: 我干了差不多5年,不过给人感觉跟只有两三年的人一样. 我觉得我不适合干程序员,主要是新东西的接受能力比其他人慢,Android技术又更新得很快,感觉总是跟不上.年纪 ...

  9. Linux下使用pure-ftpd建立匿名ftp访问

    by 无若 (一)ubuntu14.04下使用pure-ftpd建立匿名ftp访问 1.安装apt-get install pure-ftpd 2.修改配置nano /etc/pure-ftpd/co ...

  10. [TensorFlow2.0]-张量与常用函数

    本人人工智能初学者,现在在学习TensorFlow2.0,对一些学习内容做一下笔记.笔记中,有些内容理解可能较为肤浅.有偏差等,各位在阅读时如有发现问题,请评论或者邮箱(右侧边栏有邮箱地址)提醒. 若 ...