除法运算时发生的截断
q = a / b;
r = a % b;
这里,不妨假定b大于0.
我们希望a,b,q,r之间维持怎样的关系呢?
1、最重要的一点,我们希望q * b + r == a,因为这是定义余数的关系。
2、如果我们改变a的正负号,我们希望这会改变q的符号,但这不会改变q的绝对值。
3、当b>0时,我们希望保证r>=0且r<b。例如,如果余数用于哈希表的索引,确保它是一个有效的索引值很重要。
但是它们不可能同时成立。
然而,C语言的定义只保证了第1条形式,以及当a>=0且b>0时,保证|r|<|b|以及r>=0.
0 <= h < HASHSIZE, n恒为非负,那么我们只需要像下面一样简单地写:
h = n % HASHSIZE;
然而,如果n可能为负数,而此时h也有可能为负,那么这样做就不一定总是合适的了。不过,我们已知h > -HASHSIZE,因此可以这样写:
h = n % HASHSIZE;
if (h < 0) {
h += HASHSIZE;
}
更好的做法是,程序在设计时就应该避免n的值为负这样的情形,并且声明n为无符号数。
/*
** 商和余数。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
int a, b;
int quot;
int rem;
a = 5;
b = 3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
a = -5;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
a = 5;
b = -3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
a = -5;
b = -3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
return EXIT_SUCCESS;
}
输出:
/*
** 用于索引表。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
int a;
int b;
int quot;
int rem;
a = -5;
b = 3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
if( b > 0 ){
if( rem < 0 ){
rem += b;
quot -= 1;
}
} else{
if( rem < 0 ){
rem += -b;
quot += 1;
}
}
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
a = -5;
b = -3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
if( b > 0 ){
if( rem < 0 ){
rem += b;
quot -= 1;
}
} else{
if( rem < 0 ){
rem += -b;
quot += 1;
}
}
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
a = 5;
b = -3;
quot = a / b;
rem = a % b;
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
if( b > 0 ){
if( rem < 0 ){
rem += b;
quot -= 1;
}
} else{
if( rem < 0 ){
rem += -b;
quot += 1;
}
}
printf( "a = %d, b = %d, quot = %d, rem = %d\n", a, b, quot, rem );
return EXIT_SUCCESS;
}
输出: