Fractions to Decimals && 精确表达浮点数

1、Fractions to Decimals(USACO 2.4)

Write a program that will accept a fraction of the form N/D, where N is the numerator and D is the denominator and print the decimal representation. If the decimal representation has a repeating sequence of digits, indicate the sequence by enclosing it in brackets. For example, 1/3 = .33333333...is denoted as 0.(3), and 41/333 = 0.123123123...is denoted as 0.(123). Use xxx.0 to denote an integer. Typical conversions are:

1/3     =  0.(3)
22/5    =  4.4
1/7     =  0.(142857)
2/2     =  1.0
3/8     =  0.375
45/56   =  0.803(571428)

PROGRAM NAME: fracdec

INPUT FORMAT

A single line with two space separated integers, N and D, 1 <= N,D <= 100000.

SAMPLE INPUT (file fracdec.in)

45 56

OUTPUT FORMAT

The decimal expansion, as detailed above. If the expansion exceeds 76 characters in length, print it on multiple lines with 76 characters per line.

SAMPLE OUTPUT (file fracdec.out)

0.803(571428)
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
#include <math.h>
#define _DEBUG 0
#define MAX 100000
int hash[MAX+1];
int str[MAX+1];

int gcd(int a,int b){//最大公约数
     if(b == 0)
          return a;
     if(a < b){
          return gcd(b,a);
     }
     if(a & 1){//a为奇数
          if(b & 1){//b为奇数
               return gcd(b,a-b);
          }else{
               return gcd(a,b>>1);
          }
     }else{
          if(b & 1)
               return gcd(a>>1,b);
          else
               return gcd(a>>1,b>>1)<<1;
     }
}
bool check(int x){//验证被2、5整除   ===,如果能被整除返回0 ,否则返回整除的个数
     while(x %2 == 0){
          x /= 2;
     }
     while(x % 5 == 0){
          x /=5;
     }
     if(x == 1)//=1,而不是0
          return true;
     else
          return false;
}

int main(){
     int n,d;
     int count=0;
    
#if _DEBUG==0
     freopen("fracdec.in","r",stdin);
     freopen("fracdec.out","w",stdout);
#endif
     scanf("%d %d",&n,&d);

     int t = n/d;
     n %= d;

    
     printf("%d.",t);//打印整数部分
     if(t >= 1){//要是0的话,log10(0)为负,注意
          count += (int)log10((double)t)+1;//计算整数部分位数
         count += 1;//小数点位数
     }else
          count = 2;

     int g = gcd(n,d);
     n /=g;d /=g;
    
     if(n == 0){//正好整除
          printf("0\n");
          return 0;
     }

     int s;
     //int gc = check(d);//被2、5整除的个数
     if( check(d)){//可以被2、5整除,没有循环
          while(n){
               n *= 10;
               s = n/d;
               n %= d;
               printf("%d",s);
               count++;
               if(n!=0 && count % 76 ==0){
                    printf("\n");
               }
          }
          printf("\n");
     }else{         
          int pos=-1;//左括弧位置
          int i;
          int m=n;//保存n
          memset(hash,-1,sizeof(hash));//涉及到位置,要设置为-1,防止与位置0冲突
          for(i=0;;++i){
               if(hash[n] == -1){
                    hash[n]=i;
               }else{
                    pos = hash[n];
                    break;
               }
               n *= 10;
               str[i] = n/d;
               n %= d;
          }
          for(int j=0;j<i;++j){
               if(j == pos){
                    printf("(%d",str[j]);
                    count++;//加1个括号,注意
               }else{
                    printf("%d",str[j]);
               }
               count++;
               if(j!=i && count % 76 ==0 )
                    printf("\n");
          }
          printf(")\n");
     }
     return 0;
}
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;
ofstream out("fracdec.out");
int colcount=0;
int numBeforeRepeat(int n, int d) {
    int c2=0, c5=0;
    if (n == 0) return 1;
    while (d%2==0) { d/=2; c2++; }
    while (d%5==0) { d/=5; c5++; }
    while (n%2==0) { n/=2; c2--; } /* can go negative */
    while (n%5==0) { n/=5; c5--; } /* can go negative */
    if (c2>c5)
        if (c2>0) return c2;
        else return 0;
    else
        if (c5>0) return c5;
        else return 0;
}
void print (char c) {
    if (colcount==76) {
        out<<endl;
        colcount=0;
    }
    out<<c;
    colcount++;
}
void print (int n) {
    if (n>=10) print (n/10);
    print ((char)('0'+(n%10)));
}
int main() {
    int n, d;
    ifstream in("fracdec.in");
    in>>n>>d;
    in.close();

    print (n/d);
    print ('.');
    n=n%d;
    int m=numBeforeRepeat(n,d);
    for(int i=0;i<m;i++) {
        n*=10;
          print (n/d);
        n%=d;
    }
    int r=n;
    if(r!=0) {
     print ('(');
     do {
            n*=10;
               print (n/d);
            n%=d;
        } while (n!=r);
     print (')');
    }
    out<<endl;
    out.close();
    return 0;
}

2、精确表达浮点数(编程之美2.6)

在计算机中,使用float或者double来存储小数是不能得到精确值的。如果你希望得到精确计算结果,最好是用分数形式来表示小数。有限小数或者无
限循环小数都可以转化为分数。比如:
0.9=9/10
0.333(3)=1/3(括号中的数字表示是循环节)
当然一个小数可以用好几种分数形式来表示。如:
0.333(3)=1/3=3/9
给定一个有限小数或者无限循环小数,你能否以分母最小的分数形式来返回这个小数呢?如果输入为循环小数,循环节用括号标记出来。下面是一些
可能的输入数据,如0.3、0.30、0.3(000)、0.3333(3333)、……

对于无限循环小数X=0.a1a2…an(b1b2…bm)来说,其复杂部分在于小数点后同时有非循环部分和循环部分,我们可以做如下的转换:

X=0.a1a2…an(b1b2…bm)

=>10^n*X=a1a2…an.(b1b2…bm)

=>10^n*X=a1a2…an+0.(b1b2…bm)

    =>X=(a1a2…an+0.(b1b2…bm))/10^n

令Y=0.b1b2…bm,那么

10^m*Y=b1b2…bm.(b1b2…bm)

=>10^m*Y=b1b2…bm+0.(b1b2…bm)

=>10^m*Y-Y=b1b2…bm

=>Y=b1b2…bm/(10^m-1) 

将Y代入前面的X的等式可得:

X=(a1a2…an+Y)/10^n

=(a1a2…an+b1b2…bm/(10^m-1))/10^n

=((a1a2…an)*(10^m-1)+(b1b2…bm))/((10^m-1)*10^n)



发布了27 篇原创文章 · 获赞 4 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/hysfwjr/article/details/11815935
今日推荐