2009年5月21日星期四

Ruby中的负数整除问题

Ruby中两个整数相除,其结果为整数,例如1/2为0,7/3为2。这跟C是一样的,所以我一直以为Ruby的除法运算跟C是一回事。前些日子移植一个C程序时结果出错,这才发现自己又想当然了。在Ruby中,-7/3不等于-2,而是-3。

翻书,《The Ruby Programming Language》有提到这个问题。书中解释,Ruby作整除运算时对结果进行向下(负无穷大)取整,而C则是向零取整。相应的,Ruby中-7%3的结果就是2,而非-1,想来这样的结果是为了满足(a/b)*b+(a%b)=a这一等式。

C当然也可以进行向下取整,函数名为floor。近似地,向上(正无穷大)取整的函数名则叫ceil。Ruby中也有同名的两个取整方法,若想在Ruby中进行向零取整,需要调用truncate方法,而想获得跟C一样的求余结果则要用remainder方法。

仔细想想,总觉得Ruby这样的处理方式有点不妥。

像Ruby这样的动态语言,由于不存在类型声名,运算结果类型不确定就很容易出错,而且这种错误很难发现。既然都自诩为高级语言了,还不如像Javascript那样直接返回实数,这样更明确,也更贴近于数学。

退一步说,即使要取整,似乎也应该用truncate而非floor。前者是直接丢弃小数部分,应该比较快,而且跟广为流行的C保持一致。

很想知道为什么Ruby、Python、Tcl都采用(过)floor,查了查却不得其解,算了。

2012-06-28 Update

经某位家住清华园的友人指点,原来是为了所谓数学上的完备性。

当a和b都是正数时,a整除b,得数q,余数r,则满足b*q + r == a,且0 <= r < b。

当a是负数,b是正数时,向下取整可以保证上述表达式仍然成立。

至于为什么要使modulo返回正数,请参考Wikipedia

似乎不是个很有趣的原因…

没有评论 :