【CSP】-- CAP Octal Fractions

Time limit:1 Seconds            

Memory limit:32768KB

Fractions in octal (base 8) notation can be expressed exactly in decimal notation. For example,0.75 in octal is 0.953123 (7/8+5/64) in decimal. All octal numbers of n digits to the right of the octal point can be expressed in no more than 3n decimal digits to the right of the decimal point.

Write a program to convert octal numerals between 0 and 1, inclusive, into equivalent decimal numerals. The input to your program will consist of octal numbers, one per line, to be converted. Each input number has the from 0.d1d2d3...dk, where the di are octal digits (0...7). There is no limit on k. Your output will consist of a sequence of the from

0.d1d2d3....dk [8] = 0.D1D2D3...Dm [10]

where the left side is the input (in octal) ,and the right hand side the decimal (base 10) equivalent. There must be no trailing zeros, i.e. Dm is not equal to 0.

SAMPLE INPUT

0.75

0.0001

0.01234567

SAMPLE OUTPUT 

0.75 [8] = 0.953125 [10]

0.0001 [8] = 0.000244140625 [10]

0.01234567 [8] = 0.020408093929290771484375 [10]

Problem Source:

South Africa 2001

【题目大意】

八进制表示的小数可用十进制数精确地表示。例如:八进制数0.75等于十进制数00.953125(7/8+5/64)。八进制小数点右边的n位数可表示成小数位数不多于3n位的十进制数。

编程任务:将0~1之间的八进制小数,转换成等值的十进制数。程序的输入是八进制数,每行一个,分别转换成十进制数。输入数据的格式为0.d1d2d3...dk,其中di为八进制数值(0...7),k值没有限制。程序输出格式:

0.d1d2d3...dk [8] = 0.D1D2D3...Dm [10]

左边是输入的八进制数,而右边是等值的十进制数。小数后面没有拖零,也就是Dm不为0。

【算法分析】

本题需要将八进制表示的小数用十进制数精确地表示,由于位数很多,需要采用高精度的方法计算。用数学公式表达这种转换关系:

(0.75)_{8} = (7*8^{-1} + 5*8^{-2})_{10} = (0.93125)_{10}

被除数和除数都要使用高精度运算,编程是比较麻烦的。改变一下计算公式:

(0.75)_{8} = (7*8^{-1}+5*8^{-2})_{10} = ((5/8+7)/8)_{10} = (0.93125)_{10}

也就是采用累除的方法,计算起来就很方便。从八进制小数的最低位开始,除以8后,与其前一位相加,一直到小数点后的第一位小数。如上例数据,只有两个小数位,分两步运算:

① 5/8 = 0.615

② (0.625 + 7)/8 = 0.93125

这样,我们只要实现除以8的高精度运算。

【程序代码】

#include<stdio.h>
#include<string.h>
#define MaxN 100
int main()
{
    char src[MaxN];
    int i,j;
    while(scanf("%s",src)!=EOF)
    { 
        char dest[MaxN] = {'0'};  //十进制的小数
        int index = 0;  //十进制小数的长度
        //从八进制小数的最后一位开始累除
        for(i = srelen(src)-1; i > 1; i--)
        {
            int num = src[i] -'0';   //八进制小数的当前位
            //实现除以8的高精度运算
            int temp;
            //最后的余数num也必须除尽
            for(j = 0; j < index || num; j++)
            {
                temp = num*10 + (j<index?dest[j]-'0':0);
                dest[j] = temp/8 + '0';   //商
                num = temp%8;   //余数
            }
            index = j;   //十进制小数的实际位数
        }
        dest[j] = '\0';   //字符串结束标志
        printf("%s [8] = 0.%s [10]\n",src,dest);
    }
    return 0;
}

【代码解释补充】

①、采用高精度运算的原因:若不使用高精度运算,则会需要依次进行除法运算再进行加运算,这样可能导致计算后小数点后的位数可能会因为位数过长而导致被舍掉,而使之后面进行加运算时精度降低。

②、j < index || num:很巧妙的加入了 j < index,从而实现了余数是否为零的判断。

③、需要注意的是,以上代码中的 num 和 temp 定义的为 int 型。

④、除此之外,需要注意的是,定义的 数组dest 为 char 型,因此数组中的每一个元素都需要进行字符向数字的转换(即为:减去 '0' (减去字符0))。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值