进制转换题目解析
一、题目描述
我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减 1)为指数,以 10 为底数的幂之和的形式。例如:123 可表示十进制为 1x10^2+2x10^1+3x10^0 这样的形式。 与之相似的,对二进制数来说,也可表示成每个二进制数码乘以一个以该数字所处位置的(值-1)为指数,以 2 为底数的幂之和的形式。一般说 来,任何一个正整数 R 或一个负整数-R 都可以被选来作为一个数制系统的基数。如果是以 R 或-R 为基数,则需要用到的数码为 0,1,….R-1。例如,当 R=7 时,所需用到的数码是 0,1,2,3,4,5 和 6,这与其是 R 或-R 无关。如果作为基数的数绝对值超过 10,则为了表示这些数码,通常使用英文字母来表示那些大于 9 的数码。例如对 16 进制数来说,用 A 表示 10,用 B 表示 11,用 C 表示 12,用 D 表示 13,用 E 表示 14,用 F 表示 15。 在负进制数中是用-R 作为基数,例如-15(十进制)相当于 110001(-2 进制),并且它可以被表示为 2 的幂级数的和数:
110001=1*(-2)^5+1*(-2)^4+0*(-2)^3+0*(-2)^2+0*(-2)^1+1*(-2)^0
设计一个程序,读入一个十进制数和一个负进制数的基数,并将此十进制数转换为此负进制下的数:-R∈{-2,-3,-4,…,-20}。
输入
每个测试文件只包含一组测试数据,每组输入两个整数,第一个是十进制数 N(-32768<=N<=32767);第二个是负进制数的基数-R。
输出
对于每组输入数据,输出此负进制数及其基数,若此基数超过 10,则参照 16 进制的方式处理。
输入样例 1
3000 -2
输出样例 1
30000=11011010101110000(base-2)
二、问题分析
涉及知识点: - 十进制数转化成二进制或者八进制或者 16 进制。 - 短除法。 - 数字的求模取余。
注意:一个负数表示成二进制的方法可以先求它相反数的二进制数,然后取反码,最后取补码,所得结果就是负数的二进制形式。不 知道什么是原码、补码、反码的不要紧与解本题没有太大关系。
比较难为人的事情是,题目中介绍了什么是二进制与十六进制,但要我们求解一个负二进制到负二十进制。
简单介绍一下什么是短除法 短除法是十进制转换成任意进制形式的计算方法。十进制数转换成任意进制只要用短除法除对应的码数就行了,比如,十进制数 1500 转换成二进制形式应该用短除法除 2,如果要转成十六进制那应该短除 16,转成二十进制应该短除 20。 十进制数 13 转换成二进制的计算过程:
2 |13 1 2 |6 0 2 |3 1 1
所以 13 的二进制形式是 1101,注意要从下往上写。 短除法右边的值是余数,13 除 2 等 6 余 1。
十进制数-15 转换成负二进制的计算过程: 这个过程需要特别注意!
错误的运算:
-2 |-15 -1 7 -1 = -15-(-2x7) 发现短除右边余数是-1,显然错了,二进制形式余数只能为0或1,同理十六进制余数只能为0~15
正确的运算:余数为负数时,商应该+1,使得余数不为负数。
-2 |-15 1 -2 |8 0 -2 |-4 0 -2 |2 0 -2 |-1 1 1
1 = -15-(-2x8) = -15+16 0 = 8-(-2x-4) 0 = -4-(-2x2) 0 = 2-(-2x-1) 1 = -1-(-2x1)
所以-15 的负二进制为 110001。 多问就会了。
所以我们把要做的事情分为以下几步: -首先进行求模运算,判断余数是否为负数 -如果余数为负数,则商+1,再求余数,把余数记录下来 -如果余数不为负数,正常求模运算,把余数记录下来
为了方便转换,定义一个字符数组 charList,用于十六进制往后余数对应的字母 A、B ~ F。
Java 代码实现:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();// 手动输入
int base = sc.nextInt(); // 手动输入
int num_copy = num;
int quotient = 0;// 商
List<Character> list = new ArrayList<>();// 动态数组来存,因为不知道转换后有几位
char[] charList = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J' };
while (num != 0) {
int mod = num % base;
if (mod < 0) {
quotient = num / base + 1;
mod = num - quotient * base;
list.add(charList[mod]);
num = quotient;
}else{
mod = num % base;
num /= base;
list.add(charList[mod]);
}
}
Collections.reverse(list);//数组倒序
StringBuilder sb = new StringBuilder(256);
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
}
System.out.println(num_copy+"="+sb.toString() + "(base" + base + ")");
sc.close();
}
}
C 代码实现:
#include <stdio.h>
#include <stdlib.h>
int main() {
int num = 0;
int base = 0;
scanf("%d", &num); //手动输入
scanf("%d", &base); //手动输入
int num_copy = num;
int quotient = 0; // 商
char *list; // C语言中的动态数组
list = (char *)malloc(256 * sizeof(char));
char charList[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};
int i = 0; //计数器
while (num != 0) {
int mod = num % base;
if (mod < 0) {
quotient = num / base + 1;
mod = num - quotient * base;
list[i] = charList[mod];
num = quotient;
i++;
} else {
mod = num % base;
num /= base;
list[i] = charList[mod];
i++;
}
}
int k = 0;
printf("%d=", num_copy);
for (int i = 256; i >= 0; i--) {
if (list[i] == NULL) {
continue;
}
printf("%c", list[i]);
}
printf("(base%d)", base);
return 0;
}