top1编程
← 返回题目
题解

十进制小数转为N进制数

1 条题解

  • 0
    @ 2026-8-4 1:13:28

    解题思路

    把十进制小数 x 转成 n 进制(n 是 2、8、16),要分成整数部分和小数部分两个地方分别处理。

    整数部分用"除 n 取余"法:

    • 每次用 n 去除整数部分,记下余数;
    • 继续除,直到变成 0;
    • 把所有余数从后往前排,就是 n 进制整数。

    比如 12 转 8 进制:12÷8 余 4,1÷8 余 1,余数倒过来是 14。

    小数部分用"乘 n 取整"法:

    • 把小数乘 n,整数部分就是这一位;
    • 剩下的小数再乘 n,再取整数位……这样一位一位往外取。

    比如 0.827 转 8 进制:0.827×8=6.616,第一位是 6;0.616×8=4.928,第二位是 4;0.928×8=7.424,第三位是 7,所以是 0.647。

    怎么避免浮点数误差? 我们不用 double 算小数,而是把小数当成"千分之几"的整数。比如 0.827 就当成 827,乘 n 之后除以 1000 得到整数位,余下的数继续乘 n。这样每一步都是整数运算,绝对不会错。

    输出细节(以本题判题数据为准):

    • 16 进制里 10~15 要用大写字母 A~F 表示;
    • 小数部分算出 3 位后,要把末尾多余的 0 去掉(比如 0.100 写成 0.1);
    • 如果 3 位小数全是 0,就不输出小数点和后面的数字。

    参考代码

    // 用途:十进制小数x转成n进制(n=2/8/16)
    // 整数部分用"除n取余"法;小数部分用"乘n取整"法(用3位整数表示避免浮点误差)
    // 小数保留3位,但去掉末尾多余的0;若3位全是0则不输出小数点
    #include <iostream>
    using namespace std;
    int main() {
        char xs[20];
        int n;
        cin >> xs >> n;           // 读入十进制小数和进制
        // ---- 整数部分转n进制 ----
        int ip = 0, i = 0;
        while (xs[i] && xs[i] != '.') { ip = ip * 10 + xs[i] - '0'; i++; } // 整数部分的值
        char h[20];
        int hlen = 0;
        if (ip == 0) h[hlen++] = '0';                 // 整数部分是0
        while (ip > 0) {                              // 除n取余,倒着存
            int d = ip % n;
            h[hlen++] = (d < 10) ? '0' + d : 'A' + d - 10;
            ip /= n;
        }
        for (int k = hlen - 1; k >= 0; k--) cout << h[k]; // 倒序输出整数部分
        // ---- 小数部分:把小数看作3位整数,乘n取整3次 ----
        if (xs[i] == '.') i++;
        int frac = 0, cnt = 0;
        while (xs[i]) { frac = frac * 10 + xs[i] - '0'; cnt++; i++; } // 小数部分的值
        while (cnt < 3) { frac *= 10; cnt++; }         // 补足3位
        char f[3];
        for (int k = 0; k < 3; k++) {
            frac *= n;
            int d = frac / 1000;                       // 取整数位作为当前位
            frac %= 1000;                              // 余下的小数继续
            f[k] = (d < 10) ? '0' + d : 'A' + d - 10;
        }
        int flen = 3;
        while (flen > 0 && f[flen - 1] == '0') flen--; // 去掉末尾多余的0
        if (flen > 0) {                                // 还有小数位才输出小数点
            cout << '.';
            for (int k = 0; k < flen; k++) cout << f[k];
        }
        return 0;
    }
    

    复杂度分析

    整数部分要不断除 n,次数大约是 log 的级别;小数部分固定算 3 位。所以时间复杂度是 O(log n),非常快。

    • 1