Skip to content

Commit 246f573

Browse files
authored
fix: minor fixes to multiply, phase and parse (#20)
* fix: handle number * complex case for non-finite * fix: complex phase and parse * fix: handle more multiply edge-cases * fix: only negate when necessary * chore: format
1 parent c16da25 commit 246f573

File tree

2 files changed

+65
-15
lines changed

2 files changed

+65
-15
lines changed

lib/complex.ex

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,22 @@ defmodule Complex do
173173
174174
iex> Complex.parse("Inf-NaNi")
175175
{%Complex{im: :nan, re: :infinity}, ""}
176+
177+
iex> Complex.parse("Inf")
178+
{%Complex{im: 0.0, re: :infinity}, ""}
176179
"""
177180
@spec parse(String.t()) :: {t, String.t()} | :error
178181
def parse(str) do
179182
with {real_part, sign_multiplier, tail} <- parse_real(str),
180183
{imag_part, tail} <- parse_imag(tail) do
181184
{new(real_part, multiply(sign_multiplier, imag_part)), tail}
182185
else
186+
{:imag_non_finite, {imag_part, tail}} ->
187+
{new(0, imag_part), tail}
188+
189+
{:real_non_finite, {real_part, tail}} ->
190+
{new(real_part, 0), tail}
191+
183192
_ ->
184193
case parse_imag(str) do
185194
:error -> :error
@@ -201,6 +210,14 @@ defmodule Complex do
201210
defp parse_real("+NaN-" <> tail), do: {:nan, -1, tail}
202211
defp parse_real("-NaN-" <> tail), do: {:nan, -1, tail}
203212

213+
defp parse_real("Infi" <> tail), do: {:imag_non_finite, {:infinity, tail}}
214+
defp parse_real("-Infi" <> tail), do: {:imag_non_finite, {:neg_infinity, tail}}
215+
defp parse_real("NaNi" <> tail), do: {:imag_non_finite, {:nan, tail}}
216+
217+
defp parse_real("Inf" <> tail), do: {:real_non_finite, {:infinity, tail}}
218+
defp parse_real("-Inf" <> tail), do: {:real_non_finite, {:neg_infinity, tail}}
219+
defp parse_real("NaN" <> tail), do: {:real_non_finite, {:nan, tail}}
220+
204221
defp parse_real(str) do
205222
case Float.parse(str) do
206223
{val, ".+" <> tail} -> {val, 1, tail}
@@ -291,9 +308,14 @@ defmodule Complex do
291308
def phase(:infinity), do: 0
292309
def phase(:neg_infinity), do: :math.pi()
293310

294-
def phase(%Complex{re: :nan, im: im}) when im == 0, do: :nan
295-
def phase(%Complex{re: :infinity, im: im}) when im == 0, do: 0
296-
def phase(%Complex{re: :neg_infinity, im: im}) when im == 0, do: :math.pi()
311+
def phase(%Complex{re: :nan, im: im}) when is_number(im), do: :nan
312+
def phase(%Complex{re: :infinity, im: im}) when is_number(im), do: 0
313+
def phase(%Complex{re: :neg_infinity, im: im}) when is_number(im), do: :math.pi()
314+
315+
def phase(%Complex{re: :infinity, im: :infinity}), do: :math.pi() / 4
316+
def phase(%Complex{re: :infinity, im: :neg_infinity}), do: -:math.pi() / 4
317+
def phase(%Complex{re: :neg_infinity, im: :infinity}), do: 3 * :math.pi() / 4
318+
def phase(%Complex{re: :neg_infinity, im: :neg_infinity}), do: 5 * :math.pi() / 4
297319

298320
def phase(%Complex{re: :infinity}), do: :nan
299321
def phase(%Complex{re: :neg_infinity}), do: :nan
@@ -449,6 +471,9 @@ defmodule Complex do
449471
iex> Complex.multiply(3, Complex.new(1, 2))
450472
%Complex{im: 6.0, re: 3.0}
451473
474+
iex> Complex.multiply(-2, Complex.new(:infinity, :neg_infinity))
475+
%Complex{im: :infinity, re: :neg_infinity}
476+
452477
"""
453478
@spec multiply(t | number | non_finite_number, t | number | non_finite_number) ::
454479
t | number | non_finite_number
@@ -475,10 +500,28 @@ defmodule Complex do
475500
def multiply(:infinity, :neg_infinity), do: :neg_infinity
476501
def multiply(:infinity, :infinity), do: :infinity
477502

478-
def multiply(x, %Complex{re: re, im: im}) when is_non_finite_number(x) do
503+
def multiply(x, %Complex{re: re, im: im}) when is_non_finite_number(x) or is_number(x) do
504+
new(multiply(re, x), multiply(im, x))
505+
end
506+
507+
def multiply(%Complex{re: re, im: im}, x) when is_non_finite_number(x) or is_number(x) do
479508
new(multiply(re, x), multiply(im, x))
480509
end
481510

511+
def multiply(%Complex{re: re_l, im: im_l}, %Complex{re: re_r, im: im_r}) when im_r == 0 do
512+
new(multiply(re_r, re_l), multiply(re_r, im_l))
513+
end
514+
515+
def multiply(%Complex{re: re_l, im: im_l}, %Complex{re: re_r, im: im_r}) when re_r == 0 do
516+
re_result =
517+
case multiply(im_l, im_r) do
518+
result when result == 0 -> 0
519+
result -> negate(result)
520+
end
521+
522+
new(re_result, multiply(re_l, im_r))
523+
end
524+
482525
def multiply(left, right) when is_number(left) and is_number(right), do: left * right
483526

484527
def multiply(left, right) do
@@ -946,11 +989,11 @@ defmodule Complex do
946989
divide(new(1.0, 0.0), x)
947990

948991
true ->
949-
rho = :math.sqrt(x.re * x.re + x.im * x.im)
950-
theta = :math.atan2(x.im, x.re)
951-
s = :math.pow(rho, y.re) * :math.exp(-y.im * theta)
952-
r = y.re * theta + y.im * :math.log(rho)
953-
new(s * :math.cos(r), s * :math.sin(r))
992+
rho = abs(x)
993+
theta = phase(x)
994+
s = multiply(power(rho, y.re), exp(multiply(negate(y.im), theta)))
995+
r = add(multiply(y.re, theta), multiply(y.im, ln(rho)))
996+
new(multiply(s, cos(r)), multiply(s, sin(r)))
954997
end
955998
end
956999

test/complex_test.exs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ defmodule ComplexTest do
4545
assert {%Complex{re: :infinity, im: :neg_infinity}, tail} == Complex.parse("Inf-Infi" <> tail)
4646
assert {%Complex{re: :nan, im: :nan}, tail} == Complex.parse("NaN+NaNi" <> tail)
4747

48-
assert :error == Complex.parse("Inf")
49-
assert :error == Complex.parse("-Inf")
50-
assert :error == Complex.parse("NaN")
48+
assert {%Complex{re: :infinity, im: 0}, tail} == Complex.parse("Inf" <> tail)
49+
assert {%Complex{re: :neg_infinity, im: 0}, tail} == Complex.parse("-Inf" <> tail)
50+
assert {%Complex{re: :nan, im: 0}, tail} == Complex.parse("NaN" <> tail)
5151

5252
assert {%Complex{re: 0, im: :infinity}, ""} == Complex.parse("Infi")
5353
assert {%Complex{re: 0, im: :infinity}, ""} == Complex.parse("+Infi")
@@ -327,9 +327,16 @@ defmodule ComplexTest do
327327
assert Complex.phase(Complex.new(re, im)) == phase
328328
end
329329

330-
for re <- [:infinity, :neg_infinity], im <- [:infinity, :nan, :neg_infinity, -1, 1] do
331-
assert Complex.phase(Complex.new(re, im)) == :nan
332-
end
330+
assert Complex.phase(Complex.new(:infinity, :infinity)) == :math.pi() / 4
331+
assert Complex.phase(Complex.new(:infinity, :nan)) == :nan
332+
assert Complex.phase(Complex.new(:infinity, :neg_infinity)) == -:math.pi() / 4
333+
assert Complex.phase(Complex.new(:infinity, -1)) == 0
334+
assert Complex.phase(Complex.new(:infinity, 1)) == 0
335+
assert Complex.phase(Complex.new(:neg_infinity, :infinity)) == 3 * :math.pi() / 4
336+
assert Complex.phase(Complex.new(:neg_infinity, :nan)) == :nan
337+
assert Complex.phase(Complex.new(:neg_infinity, :neg_infinity)) == 5 * :math.pi() / 4
338+
assert Complex.phase(Complex.new(:neg_infinity, -1)) == :math.pi()
339+
assert Complex.phase(Complex.new(:neg_infinity, 1)) == :math.pi()
333340

334341
assert Complex.phase(Complex.new(1, :infinity)) == :math.pi() / 2
335342
assert Complex.phase(Complex.new(1, :neg_infinity)) == -:math.pi() / 2

0 commit comments

Comments
 (0)