一、题目描述
我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减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;
}