diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36623f3..d97b4ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ jobs: strategy: fail-fast: false matrix: - elixir: ["1.12.0"] - otp: ["24.0"] + elixir: ["1.18.0"] + otp: ["27.0"] env: MIX_ENV: test steps: @@ -22,7 +22,7 @@ jobs: otp-version: ${{ matrix.otp }} elixir-version: ${{ matrix.elixir }} - name: Retrieve dependencies cache - uses: actions/cache@v1 + uses: actions/cache@v4 id: mix-cache # id to use in retrieve action with: path: deps @@ -42,8 +42,8 @@ jobs: strategy: fail-fast: false matrix: - elixir: ["1.12.0"] - otp: ["24.0"] + elixir: ["1.18.0"] + otp: ["27.0"] env: MIX_ENV: test steps: @@ -57,7 +57,7 @@ jobs: otp-version: ${{ matrix.otp }} elixir-version: ${{ matrix.elixir }} - name: Retrieve dependencies cache - uses: actions/cache@v1 + uses: actions/cache@v4 id: mix-cache # id to use in retrieve action with: path: deps diff --git a/lib/complex.ex b/lib/complex.ex index 8542a29..4c48d39 100644 --- a/lib/complex.ex +++ b/lib/complex.ex @@ -389,6 +389,12 @@ defmodule Complex do @spec add(t | number | non_finite_number, t | number | non_finite_number) :: t | number | non_finite_number + def add(z, %Complex{re: re, im: im}) when z in [:infinity, :neg_infinity, :nan], + do: Complex.new(add(z, re), im) + + def add(%Complex{re: re, im: im}, z) when z in [:infinity, :neg_infinity, :nan], + do: Complex.new(add(z, re), im) + def add(:nan, _), do: :nan def add(_, :nan), do: :nan @@ -431,6 +437,12 @@ defmodule Complex do @spec subtract(t | number | non_finite_number, t | number | non_finite_number) :: t | number | non_finite_number + def subtract(z, %Complex{re: re, im: im}) when z in [:infinity, :neg_infinity, :nan], + do: Complex.new(subtract(z, re), negate(im)) + + def subtract(%Complex{re: re, im: im}, z) when z in [:infinity, :neg_infinity, :nan], + do: Complex.new(subtract(re, z), im) + def subtract(:nan, _), do: :nan def subtract(_, :nan), do: :nan def subtract(:infinity, :infinity), do: :nan @@ -472,12 +484,22 @@ defmodule Complex do %Complex{im: 6.0, re: 3.0} iex> Complex.multiply(-2, Complex.new(:infinity, :neg_infinity)) - %Complex{im: :infinity, re: :neg_infinity} + %Complex{im: :nan, re: :nan} """ @spec multiply(t | number | non_finite_number, t | number | non_finite_number) :: t | number | non_finite_number + def multiply(x, c = %Complex{re: _re, im: _im}) when is_non_finite_number(x) or is_number(x) do + z = new(x, 0) + multiply(z, c) + end + + def multiply(c = %Complex{re: _re, im: _im}, x) when is_non_finite_number(x) or is_number(x) do + z = new(x, 0) + multiply(c, z) + end + def multiply(:infinity, right) when is_number(right) and right > 0, do: :infinity def multiply(:infinity, right) when right == 0, do: :nan def multiply(:infinity, right) when is_number(right) and right < 0, do: :neg_infinity @@ -500,28 +522,6 @@ defmodule Complex do def multiply(:infinity, :neg_infinity), do: :neg_infinity def multiply(:infinity, :infinity), do: :infinity - def multiply(x, %Complex{re: re, im: im}) when is_non_finite_number(x) or is_number(x) do - new(multiply(re, x), multiply(im, x)) - end - - def multiply(%Complex{re: re, im: im}, x) when is_non_finite_number(x) or is_number(x) do - new(multiply(re, x), multiply(im, x)) - end - - def multiply(%Complex{re: re_l, im: im_l}, %Complex{re: re_r, im: im_r}) when im_r == 0 do - new(multiply(re_r, re_l), multiply(re_r, im_l)) - end - - def multiply(%Complex{re: re_l, im: im_l}, %Complex{re: re_r, im: im_r}) when re_r == 0 do - re_result = - case multiply(im_l, im_r) do - result when result == 0 -> 0 - result -> negate(result) - end - - new(re_result, multiply(re_l, im_r)) - end - def multiply(left, right) when is_number(left) and is_number(right), do: left * right def multiply(left, right) do @@ -569,33 +569,43 @@ defmodule Complex do def divide(x, y) when is_non_finite_number(x) and is_non_finite_number(y), do: :nan def divide(x, y) when is_non_finite_number(x) and is_number(y) and y >= 0, do: x def divide(x, y) when x == 0 and y == 0, do: :nan - def divide(:nan, _), do: :nan - def divide(_, :nan), do: :nan + def divide(:nan, a) when is_number(a), do: :nan + def divide(a, :nan) when is_number(a), do: :nan def divide(:infinity, y) when is_number(y) and y < 0, do: :neg_infinity def divide(:neg_infinity, y) when is_number(y) and y < 0, do: :infinity - def divide(_, :infinity), do: 0 - def divide(_, :neg_infinity), do: 0 + def divide(a, :infinity) when is_number(a), do: 0 + def divide(a, :neg_infinity) when is_number(a), do: 0 def divide(x, y) when is_number(x) and is_number(y), do: x / y + def divide(n, b) when is_number(n) and b in [:infinity, :neg_infinity] do + 0 + end + + def divide(n, %Complex{re: re_r, im: im_r}) + when is_number(n) and re_r in [:infinity, :neg_infinity] and im_r == 0 do + new(0, 0) + end + + def divide(%Complex{re: re, im: im}, b) + when is_number(re) and is_number(im) and b in [:infinity, :neg_infinity] do + new(0, 0) + end + + def divide(%Complex{re: re, im: im}, %Complex{re: re_r, im: im_r}) + when is_number(re) and is_number(im) and re_r in [:infinity, :neg_infinity] and im_r == 0 do + new(0, 0) + end + def divide(x, y) do %Complex{re: r1, im: i1} = as_complex(x) %Complex{re: r2, im: i2} = as_complex(y) - cond do - i2 == 0 -> - new(divide(r1, r2), divide(i1, r2)) - - r2 == 0 -> - new(divide(i1, i2), negate(divide(r1, i2))) - - true -> - num_re = add(multiply(r1, r2), multiply(i1, i2)) - num_im = subtract(multiply(i1, r2), multiply(r1, i2)) - den = add(square(r2), square(i2)) + num_re = add(multiply(r1, r2), multiply(i1, i2)) + num_im = subtract(multiply(i1, r2), multiply(r1, i2)) + den = add(square(r2), square(i2)) - new(divide(num_re, den), divide(num_im, den)) - end + new(divide(num_re, den), divide(num_im, den)) end @doc """ @@ -939,13 +949,49 @@ defmodule Complex do def log10(z) def log10(:infinity), do: :infinity - def log10(:neg_infinity), do: divide(log(:neg_infinity), :math.log(10)) + + def log10(:neg_infinity) do + new(:infinity, :math.pi() / :math.log(10)) + end + def log10(:nan), do: :nan def log10(n) when is_number(n) and n == 0, do: :neg_infinity def log10(n) when is_number(n) and n < 0, do: :nan def log10(n) when is_number(n), do: :math.log10(n) + def log10(%Complex{re: :infinity, im: im}) when is_number(im) do + new(:infinity, 0) + end + + def log10(%Complex{re: :neg_infinity, im: im}) when is_number(im) do + new(:infinity, :math.pi() / :math.log(10)) + end + + def log10(%Complex{im: :infinity, re: re}) when is_number(re) do + new(:infinity, :math.pi() / (2 * :math.log(10))) + end + + def log10(%Complex{im: :neg_infinity, re: re}) when is_number(re) do + new(:infinity, -:math.pi() / (2 * :math.log(10))) + end + + def log10(%Complex{re: :infinity, im: :infinity}) do + new(:infinity, :math.pi() / (4 * :math.log(10))) + end + + def log10(%Complex{re: :infinity, im: :neg_infinity}) do + new(:infinity, -:math.pi() / (4 * :math.log(10))) + end + + def log10(%Complex{re: :neg_infinity, im: :neg_infinity}) do + new(:infinity, -3 * :math.pi() / (4 * :math.log(10))) + end + + def log10(%Complex{re: :neg_infinity, im: :infinity}) do + new(:infinity, 3 * :math.pi() / (4 * :math.log(10))) + end + def log10(z = %Complex{}) do divide(log(z), new(:math.log(10.0), 0.0)) end @@ -975,6 +1021,38 @@ defmodule Complex do def log2(n) when is_number(n), do: :math.log2(n) + def log2(%Complex{re: :infinity, im: im}) when is_number(im) do + new(:infinity, 0) + end + + def log2(%Complex{re: :neg_infinity, im: im}) when is_number(im) do + new(:infinity, :math.pi() / :math.log(2)) + end + + def log2(%Complex{im: :infinity, re: re}) when is_number(re) do + new(:infinity, :math.pi() / (2 * :math.log(2))) + end + + def log2(%Complex{im: :neg_infinity, re: re}) when is_number(re) do + new(:infinity, -:math.pi() / (2 * :math.log(2))) + end + + def log2(%Complex{re: :infinity, im: :infinity}) do + new(:infinity, :math.pi() / (4 * :math.log(2))) + end + + def log2(%Complex{re: :infinity, im: :neg_infinity}) do + new(:infinity, -:math.pi() / (4 * :math.log(2))) + end + + def log2(%Complex{re: :neg_infinity, im: :neg_infinity}) do + new(:infinity, -3 * :math.pi() / (4 * :math.log(2))) + end + + def log2(%Complex{re: :neg_infinity, im: :infinity}) do + new(:infinity, 3 * :math.pi() / (4 * :math.log(2))) + end + def log2(z = %Complex{}) do divide(log(z), new(:math.log(2.0), 0.0)) end @@ -996,6 +1074,18 @@ defmodule Complex do @spec pow(t | non_finite_number | number, t | non_finite_number | number) :: t | non_finite_number | number + def pow(%Complex{re: re, im: im}, :infinity) when re == 0 and im == 0, do: new(0, 0) + + def pow(%Complex{re: re, im: im}, %Complex{re: :infinity, im: im_r}) + when re == 0 and im == 0 and im_r == 0, + do: new(0, 0) + + def pow(z, %Complex{}) when is_non_finite_number(z), do: new(:nan, :nan) + def pow(%Complex{}, z) when is_non_finite_number(z), do: new(:nan, :nan) + def pow(%Complex{re: z}, _) when is_non_finite_number(z), do: new(:nan, :nan) + def pow(%Complex{im: z}, _) when is_non_finite_number(z), do: new(:nan, :nan) + def pow(_, %Complex{re: z}) when is_non_finite_number(z), do: new(:nan, :nan) + def pow(_, %Complex{im: z}) when is_non_finite_number(z), do: new(:nan, :nan) def pow(:nan, _), do: :nan def pow(_, :nan), do: :nan @@ -1015,9 +1105,8 @@ defmodule Complex do def pow(:neg_infinity, y) when is_number(y) and y < 0, do: 0 def pow(x, :infinity) when x == 0, do: 0 - def pow(%Complex{re: re, im: im}, :infinity) when re == 0 and im == 0, do: 0 def pow(x, :neg_infinity) when x == 0, do: :infinity - def pow(%Complex{re: re, im: im}, :neg_infinity) when re == 0 and im == 0, do: :infinity + def pow(%Complex{re: re, im: im}, :neg_infinity) when re == 0 and im == 0, do: new(:infinity, 0) def pow(_, :neg_infinity), do: 0 def pow(_, :infinity), do: :infinity @@ -1308,14 +1397,16 @@ defmodule Complex do def atan2(:infinity, :infinity), do: :math.pi() / 4 def atan2(:infinity, :neg_infinity), do: 3 * :math.pi() / 4 def atan2(:infinity, :nan), do: :nan - def atan2(:infinity, _), do: :math.pi() / 2 + def atan2(:infinity, a) when is_number(a), do: :math.pi() / 2 def atan2(:neg_infinity, :infinity), do: -:math.pi() / 4 def atan2(:neg_infinity, :neg_infinity), do: -3 * :math.pi() / 4 def atan2(:neg_infinity, :nan), do: :nan - def atan2(:neg_infinity, _), do: -:math.pi() / 2 - def atan2(:nan, _), do: :nan - def atan2(_, :infinity), do: 0 - def atan2(_, :neg_infinity), do: :math.pi() + def atan2(:neg_infinity, a) when is_number(a), do: -:math.pi() / 2 + def atan2(:nan, a) when is_number(a) or is_non_finite_number(a), do: :nan + def atan2(a, :nan) when is_number(a) or is_non_finite_number(a), do: :nan + def atan2(:nan, :nan), do: :nan + def atan2(a, :infinity) when is_number(a), do: 0 + def atan2(a, :neg_infinity) when is_number(a), do: :math.pi() def atan2(b, a) do a = as_complex(a) @@ -1416,7 +1507,7 @@ defmodule Complex do ### Examples iex> Complex.asec(Complex.from_polar(2,:math.pi)) - %Complex{im: 0.0, re: 2.0943951023931957} + %Complex{im: -0.0, re: 2.0943951023931957} iex> Complex.sec(Complex.asec(Complex.new(2,3))) %Complex{im: 2.9999999999999982, re: 1.9999999999999987} diff --git a/test/complex_test.exs b/test/complex_test.exs index 9e7cd62..5c66c8c 100644 --- a/test/complex_test.exs +++ b/test/complex_test.exs @@ -169,27 +169,22 @@ defmodule ComplexTest do assert Complex.divide(x, 0) == x assert Complex.divide(x, 1) == x - if y == :nan do - assert Complex.divide(Complex.new(x), Complex.new(y)) == Complex.new(:nan, :nan) - else - assert Complex.divide(Complex.new(x), Complex.new(y)) == Complex.new(:nan) - end - - assert Complex.divide(Complex.new(x), 0) == Complex.new(x, :nan) - assert Complex.divide(Complex.new(x), 1) == Complex.new(x) + assert Complex.divide(Complex.new(x), Complex.new(y)) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(x), 0) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(x), 1) == Complex.new(x, :nan) end assert Complex.divide(:nan, 1) == :nan assert Complex.divide(1, :nan) == :nan - assert Complex.divide(Complex.new(:nan), 1) == Complex.new(:nan, 0) + assert Complex.divide(Complex.new(:nan), 1) == Complex.new(:nan, :nan) assert Complex.divide(1, Complex.new(:nan)) == Complex.new(:nan, :nan) assert Complex.divide(:infinity, -1) == :neg_infinity assert Complex.divide(:neg_infinity, -1) == :infinity - assert Complex.divide(Complex.new(:infinity), -1) == Complex.new(:neg_infinity, 0) - assert Complex.divide(Complex.new(:neg_infinity), -1) == Complex.new(:infinity, 0) + assert Complex.divide(Complex.new(:infinity), -1) == Complex.new(:neg_infinity, :nan) + assert Complex.divide(Complex.new(:neg_infinity), -1) == Complex.new(:infinity, :nan) assert Complex.divide(-1, :infinity) == 0 assert Complex.divide(0, :infinity) == 0 @@ -425,8 +420,8 @@ defmodule ComplexTest do assert Complex.pow(:neg_infinity, :neg_infinity) == 0 assert Complex.pow(0, :neg_infinity) == :infinity assert Complex.pow(0, :infinity) == 0 - assert Complex.pow(Complex.new(0, 0), :neg_infinity) == :infinity - assert Complex.pow(Complex.new(0, 0), :infinity) == 0 + assert Complex.pow(Complex.new(0, 0), :neg_infinity) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(0, 0), :infinity) == Complex.new(0, 0) end test "log, log10, log2 (non-finite)" do @@ -499,7 +494,7 @@ defmodule ComplexTest do Complex.new(:infinity, :math.pi() / :math.log(10)) assert Complex.log2(:infinity) == :infinity - assert Complex.log2(:neg_infinity) == Complex.new(:infinity, :math.pi() / :math.log(2)) + assert Complex.log2(:neg_infinity) == Complex.new(:infinity, :nan) assert Complex.log2(:nan) == :nan assert Complex.log2(Complex.new(:infinity, :infinity)) == @@ -783,6 +778,227 @@ defmodule ComplexTest do assert Complex.erf_inv(-1) == :neg_infinity end + test "complex casting - add/2" do + assert Complex.add(:infinity, 1) == :infinity + assert Complex.add(:neg_infinity, 1) == :neg_infinity + + assert Complex.add(:infinity, Complex.new(:neg_infinity, 0)) == Complex.new(:nan, 0) + assert Complex.add(:neg_infinity, Complex.new(:infinity, 0)) == Complex.new(:nan, 0) + assert Complex.add(:infinity, Complex.new(:infinity, 0)) == Complex.new(:infinity, 0) + + assert Complex.add(:neg_infinity, Complex.new(:neg_infinity, 0)) == + Complex.new(:neg_infinity, 0) + + assert Complex.add(Complex.new(:neg_infinity, 0), :infinity) == Complex.new(:nan, 0) + assert Complex.add(Complex.new(:infinity, 0), :neg_infinity) == Complex.new(:nan, 0) + assert Complex.add(Complex.new(:infinity, 0), :infinity) == Complex.new(:infinity, 0) + + assert Complex.add(Complex.new(:neg_infinity, 0), :neg_infinity) == + Complex.new(:neg_infinity, 0) + + assert Complex.add(:infinity, Complex.new(1, 2)) == Complex.new(:infinity, 2) + assert Complex.add(Complex.new(1, 2), :infinity) == Complex.new(:infinity, 2) + end + + test "complex casting - subtract/2" do + assert Complex.subtract(:infinity, 1) == :infinity + assert Complex.subtract(:neg_infinity, 1) == :neg_infinity + + assert Complex.subtract(:infinity, Complex.new(:neg_infinity, 0)) == Complex.new(:infinity, 0) + + assert Complex.subtract(:neg_infinity, Complex.new(:infinity, 0)) == + Complex.new(:neg_infinity, 0) + + assert Complex.subtract(:infinity, Complex.new(:infinity, 0)) == Complex.new(:nan, 0) + + assert Complex.subtract(:neg_infinity, Complex.new(:neg_infinity, 0)) == + Complex.new(:nan, 0) + + assert Complex.subtract(Complex.new(:neg_infinity, 0), :infinity) == + Complex.new(:neg_infinity, 0) + + assert Complex.subtract(Complex.new(:infinity, 0), :neg_infinity) == Complex.new(:infinity, 0) + assert Complex.subtract(Complex.new(:infinity, 0), :infinity) == Complex.new(:nan, 0) + + assert Complex.subtract(Complex.new(:neg_infinity, 0), :neg_infinity) == + Complex.new(:nan, 0) + + assert Complex.subtract(:infinity, Complex.new(1, 2)) == Complex.new(:infinity, -2) + assert Complex.subtract(Complex.new(1, 2), :infinity) == Complex.new(:neg_infinity, 2) + end + + test "complex casting - multiply/2" do + assert Complex.multiply(1, 1) == 1 + assert Complex.multiply(:infinity, Complex.new(1, 1)) == Complex.new(:infinity, :infinity) + + assert Complex.multiply(:neg_infinity, Complex.new(1, 1)) == + Complex.new(:neg_infinity, :neg_infinity) + + assert Complex.multiply(:infinity, :infinity) == :infinity + assert Complex.multiply(:neg_infinity, :infinity) == :neg_infinity + assert Complex.multiply(:infinity, :neg_infinity) == :neg_infinity + assert Complex.multiply(:neg_infinity, :neg_infinity) == :infinity + + # First direction + assert Complex.multiply(Complex.new(:infinity, 1), :infinity) == Complex.new(:infinity, :nan) + + assert Complex.multiply(Complex.new(:neg_infinity, 1), :neg_infinity) == + Complex.new(:infinity, :nan) + + assert Complex.multiply(Complex.new(:infinity, 1), :neg_infinity) == + Complex.new(:neg_infinity, :nan) + + assert Complex.multiply(Complex.new(:neg_infinity, 1), :infinity) == + Complex.new(:neg_infinity, :nan) + + assert Complex.multiply(Complex.new(1, :infinity), :infinity) == Complex.new(:nan, :infinity) + + assert Complex.multiply(Complex.new(1, :infinity), :neg_infinity) == + Complex.new(:nan, :neg_infinity) + + assert Complex.multiply(Complex.new(1, :neg_infinity), :neg_infinity) == + Complex.new(:nan, :infinity) + + assert Complex.multiply(Complex.new(1, :neg_infinity), :infinity) == + Complex.new(:nan, :neg_infinity) + + # Second direction + assert Complex.multiply(:infinity, Complex.new(:infinity, 1)) == Complex.new(:infinity, :nan) + + assert Complex.multiply(:neg_infinity, Complex.new(:neg_infinity, 1)) == + Complex.new(:infinity, :nan) + + assert Complex.multiply(:neg_infinity, Complex.new(:infinity, 1)) == + Complex.new(:neg_infinity, :nan) + + assert Complex.multiply(:infinity, Complex.new(:neg_infinity, 1)) == + Complex.new(:neg_infinity, :nan) + + assert Complex.multiply(:infinity, Complex.new(1, :infinity)) == Complex.new(:nan, :infinity) + + assert Complex.multiply(:neg_infinity, Complex.new(1, :infinity)) == + Complex.new(:nan, :neg_infinity) + + assert Complex.multiply(:neg_infinity, Complex.new(1, :neg_infinity)) == + Complex.new(:nan, :infinity) + + assert Complex.multiply(:infinity, Complex.new(1, :neg_infinity)) == + Complex.new(:nan, :neg_infinity) + + # NaNs + assert Complex.multiply(:nan, 1) == :nan + assert Complex.multiply(1, :nan) == :nan + + ## First direction + assert Complex.multiply(:nan, Complex.new(1, 1)) == Complex.new(:nan, :nan) + assert Complex.multiply(1, Complex.new(:nan, 1)) == Complex.new(:nan, :nan) + assert Complex.multiply(1, Complex.new(1, :nan)) == Complex.new(:nan, :nan) + + ## Second direction + assert Complex.multiply(Complex.new(1, 1), :nan) == Complex.new(:nan, :nan) + assert Complex.multiply(Complex.new(:nan, 1), 1) == Complex.new(:nan, :nan) + assert Complex.multiply(Complex.new(1, :nan), 1) == Complex.new(:nan, :nan) + end + + test "complex casting - divide/2" do + assert Complex.divide(1, 1) == 1 + + assert Complex.divide(:infinity, Complex.new(:infinity, 1)) == Complex.new(:nan, :nan) + assert Complex.divide(:neg_infinity, Complex.new(:neg_infinity, 1)) == Complex.new(:nan, :nan) + + assert Complex.divide(:infinity, Complex.new(1, 1)) == Complex.new(:infinity, :neg_infinity) + + assert Complex.divide(:neg_infinity, Complex.new(1, 1)) == + Complex.new(:neg_infinity, :infinity) + + assert Complex.divide(Complex.new(1, 1), :infinity) == Complex.new(0, 0) + assert Complex.divide(Complex.new(1, 1), :neg_infinity) == Complex.new(0, 0) + + assert Complex.divide(Complex.new(:infinity, 1), :infinity) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(1, :infinity), :infinity) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(:infinity, 1), :neg_infinity) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(1, :infinity), :neg_infinity) == Complex.new(:nan, :nan) + + # NaNs + assert Complex.divide(:nan, 1) == :nan + assert Complex.divide(1, :nan) == :nan + + ## First direction + assert Complex.divide(:nan, Complex.new(1, 1)) == Complex.new(:nan, :nan) + assert Complex.divide(1, Complex.new(:nan, 1)) == Complex.new(:nan, :nan) + assert Complex.divide(1, Complex.new(1, :nan)) == Complex.new(:nan, :nan) + + ## Second direction + assert Complex.divide(Complex.new(1, 1), :nan) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(:nan, 1), 1) == Complex.new(:nan, :nan) + assert Complex.divide(Complex.new(1, :nan), 1) == Complex.new(:nan, :nan) + end + + test "complex casting - pow/2" do + # With NaN, if either argument is complex we return complex NaN + assert Complex.pow(1, :nan) == :nan + assert Complex.pow(:nan, 1) == :nan + assert Complex.pow(Complex.new(1, 1), :nan) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, :nan), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(:nan, 1), 1) == Complex.new(:nan, :nan) + + # Infinities + ## Real + assert Complex.pow(:infinity, 3) == :infinity + assert Complex.pow(3, :infinity) == :infinity + assert Complex.pow(3, :neg_infinity) == 0.0 + assert Complex.pow(:neg_infinity, 3) == :neg_infinity + + assert Complex.pow(0, :infinity) == 0.0 + assert Complex.pow(0, :neg_infinity) == :infinity + assert Complex.pow(:infinity, 0) == 1.0 + assert Complex.pow(:neg_infinity, 0) == 1.0 + + ## Complex + ### If inf or -inf is in any argument, we return complex NaN + assert Complex.pow(Complex.new(:infinity, 1), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, :infinity), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, 1), :infinity) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(:infinity, 1)) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(1, :infinity)) == Complex.new(:nan, :nan) + assert Complex.pow(:infinity, Complex.new(1, 1)) == Complex.new(:nan, :nan) + + assert Complex.pow(Complex.new(:neg_infinity, 1), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, :neg_infinity), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, 1), :neg_infinity) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(:neg_infinity, 1)) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(1, :neg_infinity)) == Complex.new(:nan, :nan) + assert Complex.pow(:neg_infinity, Complex.new(1, 1)) == Complex.new(:nan, :nan) + + assert Complex.pow(Complex.new(:nan, 1), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, :nan), 1) == Complex.new(:nan, :nan) + assert Complex.pow(Complex.new(1, 1), :nan) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(:nan, 1)) == Complex.new(:nan, :nan) + assert Complex.pow(1, Complex.new(1, :nan)) == Complex.new(:nan, :nan) + assert Complex.pow(:nan, Complex.new(1, 1)) == Complex.new(:nan, :nan) + end + + test "complex casting - atan2/2" do + assert Complex.atan2(Complex.new(1, 0), 1) == Complex.new(0.7853981633974483, 0) + assert Complex.atan2(1, Complex.new(1, 0)) == Complex.new(0.7853981633974483, 0) + + assert Complex.atan2(:nan, Complex.new(1, 0)) == Complex.new(:nan, 0) + assert Complex.atan2(Complex.new(1, 0), :nan) == Complex.new(:nan, 0) + assert Complex.atan2(:nan, 1) == :nan + assert Complex.atan2(1, :nan) == :nan + assert Complex.atan2(:nan, :nan) == :nan + + assert Complex.atan2(:infinity, 1) == :math.pi() / 2 + assert Complex.atan2(:infinity, Complex.new(1, 0)) == Complex.new(:math.pi() / 2, 0) + assert Complex.atan2(Complex.new(1, 0), :infinity) == Complex.new(0, 0) + assert Complex.atan2(1, :infinity) == 0 + + assert Complex.atan2(:neg_infinity, 1) == -:math.pi() / 2 + assert Complex.atan2(:neg_infinity, Complex.new(1, 0)) == Complex.new(-:math.pi() / 2, 0) + assert Complex.atan2(Complex.new(1, 0), :neg_infinity) == Complex.new(:math.pi(), 0) + assert Complex.atan2(1, :neg_infinity) == :math.pi() + end + defp assert_close(left, right, opts \\ []) do eps = opts[:eps] || 1.0e-5