From: "kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core" <ruby-core@...>
Date: 2023-05-14T03:01:27+00:00
Subject: [ruby-core:113470] [Ruby master Bug#5179] Complex#rationalize and to_r with approximate zeros

Issue #5179 has been updated by kjtsanaktsidis (KJ Tsanaktsidis).


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.

----------------------------------------
Bug #5179: Complex#rationalize and to_r with approximate zeros
https://bugs.ruby-lang.org/issues/5179#change-103049

* Author: marcandre (Marc-Andre Lafortune)
* Status: Assigned
* Priority: Normal
* Assignee: mrkn (Kenta Murata)
* ruby -v: r32354
----------------------------------------
Currently, Complex#rationalize and Complex#to_r raise a RangeError if the imaginary part is nonzero *or is a Float*. Note that a BigDecimal(0) is accepted, though:

    Complex(1, 0).to_r                 # => Rational(1,1)
    Complex(1, BigDecimal("0.0")).to_r # => Rational(1,1)
    Complex(1, 0.0).to_r               # => RangeError

This is inconsistent. I recommend not raising an error for 0.0 (Float or BigDecimal). Any objection?




-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/