Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions lib/complex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,11 @@ defmodule Complex do
def add(:neg_infinity, _), do: :neg_infinity
def add(_, :neg_infinity), do: :neg_infinity

def add(left, right) when is_number(left) and is_number(right), do: left + right
def add(left, right) when is_number(left) and is_number(right) do
left + right
rescue
Comment thread
blasphemetheus marked this conversation as resolved.
ArithmeticError -> if left > 0, do: :infinity, else: :neg_infinity
end
Comment on lines -409 to +413

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be a contribution to :complex yet again

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I changed tabs too much. This is :complex hahhaha


def add(left, right) do
%Complex{re: re_left, im: im_left} = as_complex(left)
Expand Down Expand Up @@ -453,7 +457,11 @@ defmodule Complex do
def subtract(:neg_infinity, _), do: :neg_infinity
def subtract(_, :neg_infinity), do: :infinity

def subtract(left, right) when is_number(left) and is_number(right), do: left - right
def subtract(left, right) when is_number(left) and is_number(right) do
left - right
rescue
ArithmeticError -> if left > 0, do: :infinity, else: :neg_infinity
end

def subtract(left, right) do
%Complex{re: re_left, im: im_left} = as_complex(left)
Expand Down Expand Up @@ -522,7 +530,11 @@ defmodule Complex do
def multiply(:infinity, :neg_infinity), do: :neg_infinity
def multiply(:infinity, :infinity), do: :infinity

def multiply(left, right) when is_number(left) and is_number(right), do: left * right
def multiply(left, right) when is_number(left) and is_number(right) do
left * right
rescue
ArithmeticError -> if left > 0 == right > 0, do: :infinity, else: :neg_infinity
end

def multiply(left, right) do
%Complex{re: r1, im: i1} = as_complex(left)
Expand Down Expand Up @@ -585,7 +597,12 @@ defmodule Complex do
def divide(x, 0) when is_number(x) and x > 0, do: :infinity
def divide(x, 0) when is_number(x) and x < 0, do: :neg_infinity
def divide(x, 0) when is_number(x), do: :nan
def divide(x, y) when is_number(x) and is_number(y), do: x / y

def divide(x, y) when is_number(x) and is_number(y) do
x / y
rescue
ArithmeticError -> if x > 0 == y > 0, do: :infinity, else: :neg_infinity
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
Expand Down Expand Up @@ -1145,7 +1162,9 @@ defmodule Complex do
ArithmeticError ->
cond do
x == 0 and y < 0 -> :infinity
true -> :nan
x < 0 and y != trunc(y) -> :nan
x < 0 and rem(trunc(y), 2) != 0 -> :neg_infinity
true -> :infinity
end
end

Expand Down
46 changes: 46 additions & 0 deletions test/complex_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,52 @@ defmodule ComplexTest do
end
end

describe "IEEE 754: binary operation overflow returns Inf instead of crashing" do
@max_float 1.7976931348623157e308

test "add overflow" do
assert Complex.add(@max_float, @max_float) == :infinity
assert Complex.add(-@max_float, -@max_float) == :neg_infinity
end

test "subtract overflow" do
assert Complex.subtract(@max_float, -@max_float) == :infinity
assert Complex.subtract(-@max_float, @max_float) == :neg_infinity
end

test "multiply overflow" do
assert Complex.multiply(@max_float, 2.0) == :infinity
assert Complex.multiply(@max_float, -2.0) == :neg_infinity
assert Complex.multiply(-@max_float, -2.0) == :infinity
assert Complex.multiply(@max_float, @max_float) == :infinity
end

test "divide overflow" do
assert Complex.divide(@max_float, 0.5) == :infinity
assert Complex.divide(@max_float, -0.5) == :neg_infinity
assert Complex.divide(-@max_float, 0.5) == :neg_infinity
end

test "pow overflow" do
assert Complex.pow(@max_float, 2) == :infinity
assert Complex.pow(@max_float, 2.0) == :infinity
assert Complex.pow(-@max_float, 3) == :neg_infinity
assert Complex.pow(-@max_float, 2) == :infinity
end

test "pow domain errors still return :nan" do
assert Complex.pow(-8.0, 0.5) == :nan
end

test "complex components overflow" do
assert Complex.add(Complex.new(@max_float, 1.0), Complex.new(@max_float, 1.0)) ==
Complex.new(:infinity, 2.0)

assert Complex.multiply(Complex.new(@max_float, 0.0), Complex.new(2.0, 0.0)) ==
Complex.new(:infinity, 0.0)
end
end

describe "IEEE 754: domain errors return NaN instead of crashing" do
test "asin outside [-1, 1]" do
assert Complex.asin(2.0) == :nan
Expand Down
Loading