您的位置:首页 > 编程语言 > C语言/C++

除法如何舍入?--摘自《C语言陷阱和缺陷》

2008-12-19 15:43 337 查看
假设我们用b除a得到商为q余数为r:

q = a / b;

r = a % b;

我们暂时假设b > 0。

我们期望a、b、q和r之间有什么关联?

最重要的,我们期望q * b + r == a,因为这是对余数的定义。

如果a的符号发生改变,我们期望q的符号也发生改变,但绝对值不变。、

我们希望保证r >= 0且r < b。例如,如果余数将作为一个哈希表的索引,它必须要保证总是一个有效的索引。

这三点清楚地描述了整数除法和求余操作。不幸的是,它们不能同时为真。

考虑3 / 2,商1余0。这满足第一点。而-3 / 2的值呢?根据第二点,商应该是-1,但如果是这样的话,余数必须也是-1,这违反了第三点。或者,我们可以通过将余数标记为1来满足第三点,但这时根据第一点商应该是-2。这又违反了第二点。

因此C和其他任何实现了整数除法舍入的语言必须放弃上述三个原则中的至少一个。

很多程序设计语言放弃了第三点,要求余数的符号必须和被除数相同。这可以保证第一点和第二点。很多C实现也是这样做的。

然而,C语言的定义只保证了第一点和|r| < |b|以及当a >= 0且b > 0时r >= 0。 这比第二点或第三点的限制要小,实际上有些编译器满足第二点或第三点,但不太常见(如一个实现可能总是向着距离0最远的方向进行舍入)。

尽管有些时候不需要灵活性,C语言还是足够可以让我们令除法完成我们所要做的、提供我们所想知道的。例如,假设我们有一个数n表示一个标识符中的字符的一些函数,并且我们想通过除法得到一个哈希表入口h,其中0 <= h <= HASHSIZE。如果我们知道n是非负的,我们可以简单地写:

h = n % HASHSIZE;

然而,如果n有可能是负的,这样写就不好了,因为h可能也是负的。然而,我们知道h > -HASHSIZE,因此我们可以写:

h = n % HASHSIZE;

if(n < 0)

{

h += HASHSIZE;

}

同样,将n声明为unsigned也可以。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: