Repeating Decimals UVA - 202 手算除法模拟

模拟手算计算小数循环部分,长除法的使用例如3 / 7
3 / 7 = 0 … 3
30 / 7 = 4 … 2
20 / 7 = 2 … 4
40 / 7 = 5 … 5
50 / 7 = 7 … 1
10 / 7 = 1 … 3
30 / 7 = 4 … 2
可以看到,已经出现循环0.(42571)。
每一次的除法时都有被除数和余数,当除数重复出现时就表示出现循环节。
如果除数出现第二次,例如上例中30出现的时刻,就是第二次循环开始的位置。
所以需要记住每一次的商及除数的位置,除数不够除的时候,补零。

#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <algorithm>
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
using namespace std;
map<int, int> Pos;//用于计算除数的相应位置
/*
 * 从除数和被除数的关系得到循环小数
 * @param n 除数
 * @param d 被除数
 * @param ans 小数部分
 * @param r 循环部分长度
*/
void solve(int n, const int d, string& ans, int& r)
{
    Pos.clear();
    ans = ".";//初始位置是1,ans.size() = 1
    while (true)
    {
        n *= 10;
        int p = Pos[n];
        if (p == 0) Pos[n] = ans.size();//Pos[n], 表示除数是第几个的位置
        else
        {   //如果除数再次出现,Pos[n]此时大于0
            r = ans.size() - p;//找到循环节
            if (r > 50) {ans.erase(p+50); ans += "...";}//删除ans的50位置后字符
            ans.insert(p, "(");
            ans += ")";
            break;
        }

        if (n < d) {ans += '0'; continue;}

        int div = n / d, mod = n % d;
        ans += (char)(div + '0');//添加手算小数
        n = mod;
        if (n == 0) {ans += "(0)"; r = 1;break;}
    }
}

int main()
{
    int a, b;
    while (~scanf("%d%d", &a, &b))
    {
        string ans = ".(0)";
        int r = 1;
        if (a % b) solve(a % b, b, ans, r);
        printf("%d/%d = %d%s\n", a, b, a/b, ans.c_str());
        printf("   %d = number of digits in repeating cycle\n\n", r);
    }
    return 0;
}

发布了51 篇原创文章 · 获赞 19 · 访问量 8298

猜你喜欢

转载自blog.csdn.net/WxqHUT/article/details/98631312