HDU 1717 小数化分数2(数学基本知识)

HDU 1717   小数化分数2


Problem Description
Ray 在数学课上听老师说,任何小数都能表示成分数的形式,他开始了化了起来,很快他就完成了,但他又想到一个问题,如何把一个循环小数化成分数呢?
请你写一个程序不但可以将普通小数化成最简分数,也可以把循环小数化成最简分数。
 

Input
第一行是一个整数N,表示有多少组数据。
每组数据只有一个纯小数,也就是整数部分为0。小数的位数不超过9位,循环部分用()括起来。
 

Output
对每一个对应的小数化成最简分数后输出,占一行。
 

Sample Input
  
  
3 0.(4) 0.5 0.32(692307)
 

Sample Output
4/9
1/2
17/52

【思路分析】
  该题的关键点就是循环小数化为分数,有一个结论,假如这个循环小数是0.(1234),其化为分数即为1234/9999,也就是循环的部分除以这个循环部分长度个9,即1234除以4个(1234的长度)9。证明如下:
  设这个循环小数x为0.(yyy),将这个x乘以10的循环长度的次方,即10^3,得到yyy.(yyy),从而可以得出下列等式:
x*10^3 - x = yyy  =>  x(10^3 - 1) = yyy  =>  x = yyy/999。其他长度同理可证。
  有了以上的结论便可以将循环小数化为分数。然后由gcd求出最大公约数对分数化简。
  还有一点需要注意的就是这个小数包括不循环小数和循环小数两个部分,则需要分别对这两个部分化为分数,然后再相加、通分、合并、化简。这个过程需要注意通分后的数据范围,由于小数位数最长为9,所以通分时int会存不下这个结果,因此需要用long long 或者_int64 的变量来存结果,否则会报WA。

代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
__int64 gcd(__int64 a,__int64 b)
{
    __int64 r = 1;
    while (r > 0)
    {
        r = a % b;
        a = b;
        b = r;
    }
    return a;
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        char num[20];
        scanf("%s",num);
        int len = strlen(num);
        int i;
        __int64 a = 0,b = 0;//a记录不循环的小数部分,b记录循环的小数部分
        int lenofA = 0,lenofB = 0;//a的长度和b的长度
        __int64 div1 = 1,div2 = 0;//不循环小数和循环小数的对应的分母

        for(i = 2;i < len;i++)//存取不循环小数
        {
            if(num[i] != '(')
            {
                a *= 10;
                a += num[i] - '0';
                lenofA++;
                div1 *= 10;
            }
            if(num[i] == '(')
                break;
        }
        i++;
        while(i < len)//存取循环小数
        {
            if(num[i] != ')')
            {
                b *= 10;
                b += num[i] - '0';
                lenofB++;
                div2 *= 10;
                div2 += 9;
            }
            i++;
        }

        if(lenofA != 0)
            div2 *= div1;
        int gcd1,gcd2;
        if(a == 0 && b != 0)//不存在不循环小数部分
        {
            gcd2 = gcd(b,div2);
            b /= gcd2;
            div2 /= gcd2;
            printf("%I64d/%I64d\n",b,div2);
        }
        if(b == 0 && a != 0)//不存在循环小数部分
        {
            gcd1 = gcd(a,div1);
            a /= gcd1;
            div1 /= gcd1;
            printf("%I64d/%I64d\n",a,div1);
        }
        if(a != 0 && b != 0)
        {
            gcd1 = gcd(a,div1);
            gcd2 = gcd(b,div2);
            a /= gcd1;
            div1 /= gcd1;
            b /= gcd2;
            div2 /= gcd2;
            __int64 top = a * div2 + b * div1;
            __int64 down = div1 * div2;
            __int64 gcd3 = gcd(top,down);
            top /= gcd3;
            down /= gcd3;
            printf("%I64d/%I64d\n",top,down);

        }

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值