问题:输入整数a和b,输出a/b的循环小数表示以及其循环节长度。例如 a=5 b=43 小数表示为0.(116279069767441860465),循环节长度为21
分析:模拟长除法的计算过程。
①mod = a%b;
②小数 = (mod*10) / b;
③mod = (mod*10)%b;
循环②③步,当出现重复的余数的时候,也就是循环节出现了
例如 3/7
1. mod = 3%7 = 3;
2. mod = (3*10)/ 7 = 4 (小数点后第一个数)
3. mod = (3*10)%7 = 2
4. mod = (2*10)/ 7 = 2 (小数点后第二个数)
5. mod = (2*10)%7 = 6
...........
我的方法(菜鸟):
#include<iostream>
using namespace std;
int main() {
int a, b, t, k, i;
int book[3000] = { 0 }; //标记第一个余数
int count[100] = { 0 };// 记录循环小数
cin >> a >> b;
count[0] = a / b; // 小数点左边的数
t = a%b; // 余数
book[t] = 1; // 记下第一个余数
count[1] = (t * 10) / b; // 小数点后一位数
t = (t*10)%b; //继续求余
k = 2;
while (book[t] == 0) { //循环直到出现 第一次出现 的 余数
count[k] = (t * 10) / b;
t = (t*10)%b;
k++;
}
cout << count[0] << ".(";
for (i = 1; i < k; i++)cout << count[i];
cout << ")";
return 0;
}
大牛的方法:
#include<iostream>
using namespace std;
#include<string>
#include<map>
#include<assert.h>
map<int, int> Pos; //记录每一次的 被除数 以及 被除数在循环小数中的位置
void solve(int n, const int d, string &ans, int &r) {
assert(n < d && n%d);
ans = '.';
Pos.clear();
while (1) {
n *= 10;
int p = Pos[n];
if (p == 0) Pos[n] = ans.size(); // 如果被除数没有出现过,则把 被除数的位置 用ans的索引值
else {
r = ans.size() - p; // 如果出现重复的被除数,则用当前的 ans长度 - 重复被除数的最初位置 得到 节长度
if (r > 50) { // 节长度大于50 用...表示后面
ans.erase(p + 50);
ans += "...";
}
ans.insert(p, "(");
ans += ")";
break;
}
if (n < d) {
ans += "0"; //被除数 小于 除数的时候 ans补上0
continue;
}
int mod;
mod = n%d;
ans += (char)(n / d + '0'); //整数转换成字符
n = mod;
if (n == 0) { //如果不是循环小数
ans += "0";
r = 1;
break;
}
}
}
int main() {
int a, b;
cin >> a >> b;
int r = 1;
string ans = "0";
solve(a%b, b, ans, r);
printf("%d%s", a / b, ans.c_str());
cout << r;
return 0;
}