十进制小数:循环节等问题

小数化为分数

 可以化为分数形式的小数有两类:一类是有限小数,一类是无限循环小数。
 对于有限小数,我们只要将小数点移到最右,然后除以相应的10的几次方, 最后再约分即可。例如0.1234 就是1234/10000。
 而对于无限循环小数,我们先从一个最简单的例子来分析 – 0.(1) , 即0.11111…, 这里使用括号表示最小的循环节, 那么它对应的分数是多少呢?我们很容易得知如果将0.(1)乘以9的话,结果就是0.(9), 又因为它是无限循环的,所以0.(9)会无限地接近于1,那么我们可以说,0.(1) = 1/9, 这个式子从右往左推是显然的,从左往右推则需要将0.(9)近似地看作1才行。
 那么对于更加复杂一点的呢。比如 0.(345), 我们可以使用同样的方法,考虑到

0.(345)=3450.(001)

0.(001)999=0.(999)=0.(9)=1

所以
0.(345)=3451999=345999

 综合上面两点,我们可以求出任何形式的小数的分数形式,再举个例子,0.23(45),我们只要将它变成
0.23(45)=0.23+0.0010.(45)
即可分别求解。代码如下:

/*==================================================*\
| 小数化为分数 -- p/q(分子/分母)
| 括号表示循环节 -- 0.23(45) = 0.23454545...
\*==================================================*/
void DecToFrac(char str[], int& p, int& q) {
    int a = 0, b = 0;
    int L1 = 0,L2 = 0;
    int len = strlen(str);

    for(int i = 2; i < len; i++) {
        if(str[i] == '(') break;
        a = a * 10 + str[i] - '0';
        L1++;
    }

    bool flag = 0;
    for(int i = 2; i < len; i++) {
        if(str[i] == '(' || str[i] == ')') {
            flag = 1; continue;
        }
        b = b * 10 + str[i] - '0';
        L2++;
    }

    L2 -= L1;
    p = b - a; q = 0;

    if(!flag) {
        p = b; q = 1; L2 = 0;
    }

    for(int i = 0; i < L2; i++)
        q = q * 10 + 9;
    for(int i = 0; i < L1; i++)
        q = q * 10;

    int g = gcd(p, q);
    p /= g; q /= g;
}

分数化为小数

直接模拟除法即可,注意求循环节可用一个vis数组记录余数是否出现过,要求循环节还可用一个pre数组记录此余数上次出现的位置。

/*==================================================*\
| 分数化为小数 -- 求1/n的分数
| 输出第一个循环节(如果有)
\*==================================================*/
void FracToDec(int n) {
    bool isNeg = 0;  if(n < 0) { n = -n; isNeg = 1; } //负数标志

    int res[maxn], ok[maxn];
    met(res, 0); met(ok, 0);

    int k = 1; ok[k] = 1;
    int cnt = 0;
    W(k && n != 1) {
        k *= 10; res[cnt++] = k / n; k %= n;
        if(ok[k]) break; ok[k] = 1;
    }//模拟除法

    //输出
    if(isNeg) printf("-"); if(n == 1) puts("1");
    else {
        printf("0.");
        rep(i, 0, cnt) printf("%d", res[i]);
        puts("");
    }
}

循环节

这个要等到看完素数测试和高精度分解因式之后了。。。
小数问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值