题解
十进制小数转为N进制数
1 条题解
-
0
解题思路
把十进制小数 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