One of the more interesting aspects of using iPython is the ability to combine different languages into one notebook. Below is a session that I was doing as part of reddit’s dailyprogrammer challenges. As you can see below, notebooks are a great way to comment and display your code in an informative way to “show all working”.
I believe that this model is best for when you first begin to learn how to code, especially since it is hard to “visualise” the progress of your code. Now of course when programs go beyond trivial implementations and are several hundred lines long, this becomes cumbersome and doesn’t really make too much sense. But nevertheless it is a great way to take a holistic view of your journey.
The goal of this notebook is to demonstrate how we may implement a class in Ruby and Python to represent a complex number
Ruby
Firstly we must create a class that represents our complex number
%%ruby
class Complex
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
end
a = Complex.new(1,2)
puts a
#<Complex:0x3fb1690>
But the output above isn’t particularly helpful. Let us use string interpolation
in Ruby and override the default to_s
method.
%%ruby
class Complex
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def to_s
"#{@real}+#{@imaginary}i"
end
end
a = Complex.new(1,2)
puts a
a = Complex.new(1.5,-2)
puts a
1 + 2i
1.5 + -2i
Lets add GetModulus
which returns the modulus of a complex number
%%ruby
class Complex
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def get_modulus
Math.sqrt(@real**2 + @imaginary**2)
end
def to_s
"#{@real}+#{@imaginary}i"
end
end
a = Complex.new(3,4)
p a.get_modulus()
5.0
Lets now add complex conjugate
%%ruby
class Complex
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def get_modulus
Math.sqrt(@real**2 + @imaginary**2)
end
def get_conjugate
Complex.new(@real, -@imaginary)
end
def to_s
"#{@real}+#{@imaginary}i"
end
end
a = Complex.new(3,4)
p a.get_modulus()
b = a.get_conjugate()
p b.to_s
p b.get_conjugate().to_s
5.0
"3 + -4i"
"3 + 4i"
but now we realise that theres something off in our to_s
method! We could fix
it, however it still does make mathematical sense.
%%ruby
class Complex
attr_reader :real, :imaginary
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def get_modulus
Math.sqrt(@real**2 + @imaginary**2)
end
def get_conjugate
Complex.new(@real, -@imaginary)
end
def to_s
"#{@real}%si" % sprintf("%+d", @imaginary)
end
end
a = Complex.new(3,4)
p a.get_modulus
b = a.get_conjugate
puts b.to_s
puts b.get_conjugate.to_s
p b.real
5.0
3-4i
3+4i
3
%%ruby
class Complex
attr_reader :real, :imaginary
def initialize(real, imaginary)
@real = real
@imaginary = imaginary
end
def get_modulus
Math.sqrt(@real**2 + @imaginary**2)
end
def get_conjugate
Complex.new(@real, -@imaginary)
end
def +(num)
if num.is_a? Complex
Complex.new(@real + num.real, @imaginary + num.imaginary)
elsif num.is_a? Numeric
Complex.new(@real + num, @imaginary)
else
raise TypeError
end
end
def -(num)
if num.is_a? Complex
Complex.new(@real - num.real, @imaginary - num.imaginary)
elsif num.is_a? Numeric
Complex.new(@real - num, @imaginary)
else
raise TypeError
end
end
def *(num)
if num.is_a? Complex
Complex.new(@real*num.real - @imaginary*num.imaginary, @imaginary*num.real + @real*num.imaginary)
elsif num.is_a? Numeric
Complex.new(@real*num, @imaginary*num)
else
raise TypeError
end
end
def to_s
"#{@real}%si" % sprintf("%+d", @imaginary)
end
end
a = Complex.new(1,2)
b = Complex.new(2,3)
p (a+b).to_s
p (a-b).to_s
p (a*b).to_s
"3+5i"
"-1-1i"
"-4+7i"
Python
Below is a similar Python implementation of the same problem
class Complex():
def __init__(self, real, imaginary):
self.real = real
self.imaginary = imaginary
def __str__(self):
return "%.2f%+.2fi" % (self.real, self.imaginary)
str(Complex(1,2.5))
'1.00+2.50i'
We can the add the respective parts of it quite easily
class Complex():
def __init__(self, real, imaginary):
self.real = real
self.imaginary = imaginary
def get_modulus(self):
return self.real**2 + self.imaginary**2
def get_conjugate(self):
return Complex(self.real, - self.imaginary)
def __str__(self):
return "%.2f%+.2fi" % (self.real, self.imaginary)
str(Complex(1,2.5).get_conjugate())
'1.00-2.50i'
Complex(3,4).get_modulus()
25
Now we can add addition, subtraction, multiplication
class Complex():
def __init__(self, real, imaginary):
self.real = real
self.imaginary = imaginary
def get_modulus(self):
return self.real**2 + self.imaginary**2
def get_conjugate(self):
return Complex(self.real, - self.imaginary)
def plus(self, num):
if isinstance(num, Complex):
return Complex(self.real + num.real, self.imaginary + num.imaginary)
elif isinstance(num, (int, long, float)):
return Complex(self.real + num, self.imaginary)
else:
raise TypeError
def minus(self, num):
if isinstance(num, Complex):
return Complex(self.real - num.real, self.imaginary - num.imaginary)
elif isinstance(num, (int, long, float)):
return Complex(self.real - num, self.imaginary)
else:
raise TypeError
def times(self, num):
if isinstance(num, Complex):
return Complex(self.real * num.real - self.imaginary * num.imaginary,
self.imaginary * num.real + self.real * num.imaginary)
elif isinstance(num, (int, long, float)):
return Complex(self.real * num, self.imaginary * num)
else:
raise TypeError
def __str__(self):
return "%.2f%+.2fi" % (self.real, self.imaginary)
print Complex(1,2).plus(Complex(3,4))
print Complex(3,4).minus(Complex(4,5))
print Complex(12,1).times(Complex(1,1))
4.00+6.00i
-1.00-1.00i
11.00+13.00i