Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complex enhancements #5440

Merged
merged 6 commits into from
Dec 1, 2018
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
4 changes: 4 additions & 0 deletions spec/std/complex_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ describe "Complex" do
end

describe "+" do
it "+ complex" do
(+Complex.new(-5.43, -27.12)).should eq(Complex.new(5.43, 27.12))
end

it "complex + complex" do
(Complex.new(2.2, 7) + Complex.new(10.1, 1.34)).should eq(Complex.new(12.3, 8.34))
end
Expand Down
80 changes: 63 additions & 17 deletions src/complex.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
#
# Complex.new(1, 0) # => 1.0 + 0.0i
# Complex.new(5, -12) # => 5.0 - 12.0i
#
# 1.to_c # => 1.0 + 0.0i
# 1.i # => 0.0 + 1.0i
# ```
struct Complex
# Returns the real part of self.
# Returns the real part.
getter real : Float64

# Returns the image part of self.
# Returns the imaginary part.
getter imag : Float64

def initialize(real : Number, imag : Number)
Expand All @@ -36,6 +39,48 @@ struct Complex
false
end

# Returns `self`.
def to_c
self
end

# Returns the value as a `Float64` if possible (the imaginary part should be exactly zero),
# raises otherwise.
def to_f64
unless @imag.zero?
raise Exception.new "Complex number with non-zero imaginary part can't be converted to real number"
Copy link
Contributor

Choose a reason for hiding this comment

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

But what's the point of these methods then? Why not just provide an assert_real! and an assert_imaginary! method and let people use c.real? What's the usecase of a number conversion method that raises all the time?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But what's the point of these methods then? Why not just provide an assert_real! and an assert_imaginary! method and let people use c.real? What's the usecase of a number conversion method that raises all the time?

Somehow that's what Ruby does, so I guess all of your questions should be directly answered by digging into the Ruby land, their decision making and API designing process.

I seriously think this is a badly thought out PR trying to shoehorn a Complex into being something it's not: a single-dimensional dumber.

And what's the point of of your criticism? I don't see any constructive arguments, only your personal opinions which you hold dearly to the point of putting yourself on airs.

If it doesn't fit in the interface for Number, it's not a Number regardless of if it's a number. Yes that points to our number hierarchy being inconsistent with pure mathematics but i'm not sure how important that is in the real world, or if it's worth adding many new interfaces for it like I think Rust has done.

AFAIK the only thing from Number API it doesn't fit is <=> operator which IMO shouldn't be included there from default.

end
@real
end

# Returns the value as a `Float32` if possible (the imaginary part should be exactly zero),
# raises otherwise.
def to_f32
to_f64.to_f32
end

# See `#to_f64`.
def to_f
to_f64
end

# Returns the value as an `Int64` if possible (the imaginary part should be exactly zero),
# raises otherwise.
def to_i64
to_f64.to_i64
end

# Returns the value as a `Int32` if possible (the imaginary part should be exactly zero),
# raises otherwise.
def to_i32
to_i64.to_i32
end

# See `#to_i32`.
def to_i
to_i32
end

# Writes this complex object to an *io*.
#
# ```
Expand Down Expand Up @@ -83,12 +128,12 @@ struct Complex
self / abs
end

# Returns the phase of self.
# Returns the phase of `self`.
def phase
Math.atan2(@imag, @real)
end

# Returns a tuple with the abs value and the phase.
# Returns a `Tuple` with the `abs` value and the `phase`.
#
# ```
# Complex.new(42, 2).polar # => {42.047592083257278, 0.047583103276983396}
Expand All @@ -97,7 +142,7 @@ struct Complex
{abs, phase}
end

# Returns the conjugate of self.
# Returns the conjugate of `self`.
#
# ```
# Complex.new(42, 2).conj # => 42.0 - 2.0i
Expand All @@ -107,7 +152,7 @@ struct Complex
Complex.new(@real, -@imag)
end

# Returns the inverse of self.
# Returns the inverse of `self`.
def inv
conj / abs2
end
Expand All @@ -130,14 +175,10 @@ struct Complex
@imag.abs / Math.sqrt(2 * (r + @real))
end

if @imag >= 0
Complex.new(re, im)
else
Complex.new(re, -im)
end
Complex.new(re, @imag >= 0 ? im : -im)
RX14 marked this conversation as resolved.
Show resolved Hide resolved
end

# Calculates the exp of self.
# Calculates the exp of `self`.
#
# ```
# Complex.new(4, 2).exp # => -22.720847417619233 + 49.645957334580565i
Expand All @@ -147,21 +188,26 @@ struct Complex
Complex.new(r * Math.cos(@imag), r * Math.sin(@imag))
end

# Calculates the log of self.
# Calculates the log of `self`.
def log
Complex.new(Math.log(abs), phase)
end

# Calculates the log2 of self.
# Calculates the log2 of `self`.
def log2
log / Math::LOG2
end

# Calculates the log10 of self.
# Calculates the log10 of `self`.
def log10
log / Math::LOG10
end

# Returns absolute value of `self`.
def +
Complex.new(@real.abs, @imag.abs)
end

# Adds the value of `self` to *other*.
def +(other : Complex)
Complex.new(@real + other.real, @imag + other.imag)
Expand All @@ -172,12 +218,12 @@ struct Complex
Complex.new(@real + other, @imag)
end

# Returns the opposite of self.
# Returns the opposite of `self`.
def -
Complex.new(-@real, -@imag)
end

# Removes the value from *other* to self.
# Removes the value of *other* from `self`.
def -(other : Complex)
Complex.new(@real - other.real, @imag - other.imag)
end
Expand Down