I've explored the behaviour here a bit, and I think I do believe that 0.0
really does represent the concept of "zero". Specifically, it's the number that satisfies the following properties, for all possible non-NaN floats N:
abs(0.0 * N) == 0.0
0.0 + N == N
You might obtain a bit pattern for 0.0 from the result of a calculation which might have otherwise produced a non-zero result if there was more precision; however that doesn't change the fact that the bit pattern you have really does satisfy the mathematical properties of zero.
Additionally, I think the distinction that complex.c currently draws between floating-point and non-floating-point zero also results in some other surprising results:
irb(main):030:0> Complex(3, 7) ** 0.0
=> (1.0+0.0i)
irb(main):031:0> Complex(3, 7) ** 0
=> (1+0i)
irb(main):032:0> Complex(3.2, 7) ** 0
=> (1+0i)
irb(main):033:0> Complex(3.2, 7) ** 0.0
=> (1.0+0.0i)
Why does the type of A ** B
depend on whether B is a float or not, but not A?
irb(main):034:0> Complex(3.2, 7) ** Complex(1, 0.0)
=> (3.200000000000001+6.999999999999999i)
irb(main):035:0> Complex(3.2, 7) ** Complex(1, 0)
=> (3.2+7i)
This doesn't need to accumulate floating point error - the code in rb_complex_pow
special-cases (a + bi) ** (c + 0i) -->(a + bi) ** c
, but the special-casing is skipped if 0i
is 0.0i
instead.
Also, #to_i
and #to_f
have the same issue as #to_r
:
irb(main):037:0> Complex(3, 0.0).to_i
(irb):37:in `to_i': can't convert 3+0.0i into Integer (RangeError)
irb(main):038:0> Complex(3, 0.0).to_f
(irb):38:in `to_f': can't convert 3+0.0i into Float (RangeError)
This is especially odd for #to_i
because it of course has no problems truncating away the real part:
irb(main):040:0> Complex(3.1, 0).to_i
=> 3
I think we should change all the checks for k_exact_zero_p
in complex.c
to f_zero_p
; i.e. in all the places where complex.c
special-cases integer zero, also make it special-case floating-point zero. If people agree with this (especially people who actually use Complex in their code - I have pretty much never used it!) I can send a pretty simple patch to cloe this out.