当任何参数为浮点数时,{{quot}} 和 {{rem}} 对于非有限参数给出奇异的结果
(quot Double/POSITIVE_INFINITY 2); Java: Infinity NumberFormatException Infinite or NaN java.math.BigDecimal.<init> (BigDecimal.java:808) (quot 0 Double/NaN); Java: NaN NumberFormatException Infinite or NaN java.math.BigDecimal.<init> (BigDecimal.java:808) (quot Double/POSITIVE_INFINITY Double/POSITIVE_INFINITY); Java: NaN NumberFormatException Infinite or NaN java.math.BigDecimal.<init> (BigDecimal.java:808) (rem Double/POSITIVE_INFINITY 2); Java: NaN NumberFormatException Infinite or NaN java.math.BigDecimal.<init> (BigDecimal.java:808) (rem 0 Double/NaN); Java: NaN NumberFormatException Infinite or NaN java.math.BigDecimal.<init> (BigDecimal.java:808) (rem 1 Double/POSITIVE_INFINITY); 最奇异的一个。Java: 1.0 ⇒ NaN
quot 和 rem 也会对 double 进行除零检查,这与 double 的除法行为不一致
(/ 1.0 0) ⇒ NaN (quot 1.0 0); Java: NaN ArithmeticException Divide by zero clojure.lang.Numbers.quotient (Numbers.java:176) (rem 1.0 0); Java: NaN ArithmeticException Divide by zero clojure.lang.Numbers.remainder (Numbers.java:191)
附带的补丁 并没有 解决这个问题,因为我不知道这是否是预期的行为。没有测试断言上述任何行为。
这种行为的根本原因是 quot 和 rem 的实现仅在除法结果大于 long 时才会取一个 double,将其强制转换为 BigDecimal,然后是 BigInteger,然后又回到了 double。这种转换意味着它无法处理非有限中间值。所有这些都是完全不必要的,我认为这只是当这些方法曾经返回装箱的整数类型(long 或 BigInteger)时的遗留垃圾。这发生在(链接:https://github.com/clojure/clojure/commit/e4a76e058ceed9b152ffd00b3f83e2800207bc25 text: this commit)返回原始 double,但是方法体没有进行足够的重构。
方法体应该是简单的
`
static public double quotient(double n, double d){
if(d == 0)
throw new ArithmeticException("Divide by zero");
double q = n / d;
return (q >= 0) ? Math.floor(q) : Math.ceil(q);
}
static public double remainder(double n, double d){
if(d == 0)
throw new ArithmeticException("Divide by zero");
return n % d;
}
`
这正是附带的补丁所做的。(并且我也不确定 {{d==0}} 检查是否合适。)
即使对于非有限结果的爆炸是 quot 和 rem 的一个期望属性,也没有必要进行 BigDecimal+BigInteger 转换。我可以准备一个补丁来保留现有行为但更有效。
更多信息请参阅(链接:https://groups.google.com/d/msg/clojure-dev/nSqIfpqSpRM/kp3f5h-zONYJ text: Clojure dev)。