首先,除法总是向0取整的,即2/3=0,-2/3还是0,因此可以把负号拿出来变成-(2/3).提取(除数或被除数)负号总是可行的,这还包括-2/-3,2/-3之类的情况.
而负数的取模运算如a%b,标准规定其可由a-(a/b)*b得出,那么可知
1.运算结果的符号与a相同. (因为减号右侧的绝对值一定不大于a)
2.(这意味着)b的符号不影响运算结果. (把上式中的b换为-b,提取符合后与原式相等)
所以对于涉及负数取模的运算a%b,如果你单纯地想要得到等价的运算结果,可以用这样的方法思考:
- 用b的绝对值替换b
- 把a的符号提取出来
- 进行两正整数之间的取模,并加上a的符号
下面这题中,需要你对负数的取模,整除进行特殊处理,如负数除以负数求正余数,负数除以负数"向下"取整.
来看看-15转为-2进制的过程.
不停地用-2为除数去除-15,并取余数(正数)为结果中的一位.
-15/-2=7余1,看上去是符合的,然而此时1x(-2)4+1x(-2)3=8,不为7.
当进行正数的进制转化时,每次除总是向下取整取余数为结果,而进行负数的进制转化时,每次除总是向0,也就是向上取整了,我们需要向下取整.
想要这样操作只需要进行一下判断再处理就可以了.
现在,每次除之后想要得到一个正余数,a%b若左侧数为正数,不需要额外处理,如果为负数,写为-b+a%b即可.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; char num[30] = "0123456789ABCDEFGHIJKLMN"; void slove(int n, int m) { if (n > 0 || n % m == 0) { slove(n / m, m); putchar(num[n % m]); } else if (n < 0) { slove(n / m + 1, m); putchar(num[-m + n % m]); } } int main() { int n, m; scanf("%d%d", &n, &m); printf("%d=", n); slove(n, m); printf("(base%d)", m); return 0; }