Division with ∞ - #68
Hidden character warning
dlfivefifty wants to merge 6 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #68 +/- ##
==========================================
- Coverage 99.08% 98.69% -0.39%
==========================================
Files 6 6
Lines 218 230 +12
==========================================
+ Hits 216 227 +11
- Misses 2 3 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| convert(::Type{ComplexInfinity}, ::Infinity) = ComplexInfinity() | ||
| convert(::Type{ComplexInfinity{T}}, x::RealInfinity) where T = ComplexInfinity{T}(x) | ||
| convert(::Type{ComplexInfinity}, x::RealInfinity) = ComplexInfinity(x) | ||
| float(x::ComplexInfinity) = exp(im*angle(x)) * Inf |
There was a problem hiding this comment.
This is not correct:
julia> float(ComplexInfinity())
Inf + NaN*imGaps that JuliaMath#68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions also answered for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` answers `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. JuliaMath#68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins.
Gaps that JuliaMath#68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions were also defined for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` returns `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. JuliaMath#68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins.
Gaps that JuliaMath#68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions were also defined for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` returns `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. JuliaMath#68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins.
|
Everything from here should now be taken over into the other PRs. 🤖 helped me in checking for completeness and collecting this information: Once #81, #82, #86 and #87 land, everything here should be covered: all sixteen division One deliberate difference: So I would suggest closing this once the other PRs are merged. |
Gaps that JuliaMath#68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions were also defined for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` returns `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. JuliaMath#68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins.
Gaps that JuliaMath#68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions were also defined for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` returns `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. JuliaMath#68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins.
* Give `ComplexInfinity` its `abs`, `sign`, `conj` and negation All four were `MethodError`s for an angle that is not a multiple of π: negation existed only for an integer factor, and the other three not at all. Negation and conjugation rotate and reflect the angle, reduced so that both stay involutions; `abs` is `∞` whichever way the infinity points; `sign` is the unit vector, `cispi` giving it exactly on the axes. The integer factor keeps its own methods, which already returned an `Int` and are what `AllRealInfinities` relies on. * Give an infinite complex summand the direction it points in `ComplexInfinity` stores its direction in half turns, but `toinf` filled the field with the radians of `angle(x)`. The direction of an infinite complex summand was therefore off by a factor of π: `angle(toinf(complex(0, Inf)))` gave 4.93 rather than `π/2`. `_infadd` compares those angles, so a sum whose parts point the same way threw although `==` called them equal: both `complex(-Inf, 0.0) + -∞` and `complex(0.0, Inf) + im*∞` raised an ArgumentError. Only the positive real axis escaped, angle `0` being the fixed point of the missing scaling. `_sb` is the conversion the multiplication already uses, so it moves above the addition and both sections share it. * Add `isinteger` and the rounding functions for an infinity Both were `MethodError`s, which also made `∞ in 1:5` fail, a range asking `isinteger` before it compares. `Inf` is not an integer and rounding leaves it alone, so an infinity does the same and returns itself. `InfiniteCardinal` is left out of both: it is an `Integer`, for which `Base` already returns `true` and the value unchanged. * Divide by and into an infinity `∞ / 2` and `2 / ∞` were promotion errors, though `inv` was already there to build them from: division is multiplication by the inverse, which brings the sign and the `NaN` handling of `*` with it. `\` needs nothing of its own, `Base` defining it as `y / x`. `∞ / ∞` returns `NotANumber`, as `div(∞, ∞)` and `mod(∞, ∞)` already do, rather than the `NaN` of the floats. `2 / ∞` inherits the `Int` zero of `inv(∞)` where the floats give `0.0`, which fixing `inv` will settle in one place. `Rational` and `Complex` need the same explicit pairs in `ambiguities.jl` as the other operators. * Take the remainder against an infinity `3 % ∞` was a promotion error, though `mod` and `div` were both already there. `rem` keeps the sign of the dividend, so unlike `mod` it needs no bound: `-3 % ∞` is `-3`, where `mod(-3, ∞)` is unbounded and throws. `divrem` follows from the two. The other direction returns `NotANumber`, as `mod(∞, x)` and `div(∞, ∞)` do. `Rational` and `BigInt` need the explicit pairs in `ambiguities.jl`, an `InfiniteCardinal` being an `Integer` that `Base` has its own methods for. * Let `isapprox` compare an infinity `∞ ≈ Inf` threw, `Base` promoting its arguments before it compares them and an infinity having no common type with a number. Nothing is near an infinity but an equal one, which is what the floats do too, so approximate equality is exact equality and the keywords have nothing to loosen. * Complete `float` and the rounding forms for an infinity Gaps that #68 covers and this branch did not, plus the types they missed. `round(x, ::RoundingMode)` was a MethodError, and `round(x; digits)` fell through to `Base` and returned `Inf` rather than the infinity, disagreeing with the plain `round(x)` next to it. `isinteger` and the four rounding functions were also defined for `Infinity` and `RealInfinity` alone, so a `ComplexInfinity` raised a MethodError where `Base` returns `false` and the value itself for the matching `Complex`, and `ℵ₀` took a rounding mode but not the keywords. `float(::ComplexInfinity)` was a MethodError, the real infinities having got theirs from the `AbstractFloat` conversion. #68 proposes `exp(im*angle(x))*Inf`, which is unsound: `0 * Inf` is a `NaN`, so `float(ComplexInfinity())` gives `Inf + NaN*im`, and the imaginary and negative real axes come back as diagonals. `cospi`/`sinpi` are exact at the half-integers, so building the parts from them keeps the axes exact. Two saturating parts can express only eight rays, so an angle off them lands on the nearest one, which the test pins. --------- Co-authored-by: Patrick Häcker <patrick.haecker@bosch.com>
No description provided.