一、相关题目
二、问题描述
输入一个十进制数n和一个负进制数的基数R,输出转换后的负进制数。
三、原理分析
十进制数转换为负进制数与十进制数转换为正进制数的原理相同。 我们需要不断用所给数除基数,获得一个余数,这个余数摆在最后一位,然后用商除基数再得新的商和余数,并不断将余数放在前一位,直到商为0。最终得到的这样一个由余数组成的数便是我们所需的答案。
有些人编程运算发现怎么也得不到正确答案,那是因为,这样转换的前提是我们每次得到的余数是一个正数或0,而根据c++和java的特性,对负数取模时向零取整(使商绝对值尽可能小),这使得我们可能得到一个小于0的余数。
例如:-15%-2==-1,商为7 && 15%-2==1,商为-7
而不是-15%-2==1,商为8 && 15%-2==-1,商为-8,因为上面行商的绝对值更小
四、算法解析
我们可以将取模的式子表示为如下形式
n=aR+b,a为商,b为余数
此时,如果b<0,根据取余运算的性质,将会有以下关系
R<b<0,由此得到 b-R>0
从而我们在n=aR+b中将a借出一位,得到
n=(a+1)R+b-R
这时我们得到的商变为了a+1,余数变为了b-R,可以满足余数大于0的要求。所以我们只需对每次算出的余数进行判断,若小于0,就令余数减去基数,除去基数得到的商再加1,否则按正常的方法转换。
五、代码实现(c++)
while(n!=0)
{
int b;//b为余数
b=n%R;
if(b<0)
{
ans=getnum(b-R)+ans;
n=n/R+1;
}
else
{
ans=getnum(b)+ans;
n/=R;
}
}
printf("%d=%s(base%d)",num,ans.c_str(),R);
压缩后完整代码
#include<iostream>
using namespace std;
int n,R;
std::string ans="";
inline char getnum(int x)
{
return x<10?x+'0':(x-10)+'A';
}
int main()
{
scanf("%d%d",&n,&R);
int num=n;
while(n!=0)
n%R<0?(ans=getnum(n%R-R)+ans,n=n/R+1):(ans=getnum(n%R)+ans,n/=R);
printf("%d=%s(base%d)",num,ans.c_str(),R);
return 0;
}