-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Implement exercise complex-numbers #523
Changes from 4 commits
ab2e37a
aaefaa0
4cea929
b462a91
dca0127
155331f
cfd8e5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -823,6 +823,17 @@ | |
"control-flow (loops)" | ||
] | ||
}, | ||
{ | ||
"uuid": "7f4d5743-7ab8-42ca-b393-767f7e9a4e97", | ||
"slug": "complex-numbers", | ||
"core": false, | ||
"unlocked_by": "leap", | ||
"difficulty": 6, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same for difficulty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, same hear. Took it from C# track. As I understood, difficulty grade is kinda... subjective. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Maybe we can come with some sort of formula to compute it, what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this question maybe hurried somewhere in general discussions repo. Btw, will difficulty be used at all in version 2, or there would be relying on "unlocked_by" prerequisites? In general, it could be done, of course, simplest heuristic would be to split topics that we have in to tiers, from simplest to hardest and add the difficulty level for each additional topic for exercise. So if basically tier_level1+....tier_level2 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lilislilit, hm, this a really good point, thanks! I haven't thought about it this way |
||
"topics": [ | ||
"Tuples", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good choice. We are trying to standardize topics across all tracks and decided to use |
||
"Mathematics" | ||
] | ||
}, | ||
{ | ||
"uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", | ||
"slug": "accumulate", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Complex Numbers | ||
|
||
A complex number is a number in the form `a + b * i` where `a` and `b` are real and `i` satisfies `i^2 = -1`. | ||
|
||
Assume the programming language you are using does not have an implementation of complex numbers. | ||
|
||
### Submitting Exercises | ||
|
||
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory. | ||
|
||
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`. | ||
|
||
|
||
For more detailed information about running tests, code style and linting, | ||
please see the [help page](http://exercism.io/languages/python). | ||
|
||
## Source | ||
|
||
Wikipedia [https://en.wikipedia.org/wiki/Complex_number](https://en.wikipedia.org/wiki/Complex_number) | ||
|
||
## Submitting Incomplete Solutions | ||
It's possible to submit an incomplete solution so you can see how others have completed the exercise. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class ComplexNumber(object): | ||
def __init__(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it was discussed in #509 it would be a good idea to include expected parameters to not force the user to go through a test class What are your thoughts on this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think it is a wise thing to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although, should I also include method signatures? Or only params for constructor? If we don't want people to go through test suite too much, including method signatures makes sense, some tracks here do this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it makes sense to include method signatures since the user uses the provided test suite anyway. I don't see how providing method signatures can influence the user's overall implementation. The most important thing for me is convenience |
||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import unittest | ||
|
||
import math | ||
|
||
from complex_numbers import ComplexNumber | ||
|
||
|
||
class ComplexNumbersTest(unittest.TestCase): | ||
|
||
def test_real_part_of_a_purely_real_number(self): | ||
input_number = ComplexNumber(1, 0) | ||
self.assertEqual(input_number.real, 1) | ||
|
||
def test_real_part_of_a_purely_imaginary_number(self): | ||
input_number = ComplexNumber(0, 1) | ||
self.assertEqual(input_number.real, 0) | ||
|
||
def test_real_part_of_a_number_with_real_and_imaginary_part(self): | ||
input_number = ComplexNumber(1, 2) | ||
self.assertEqual(input_number.real, 1) | ||
|
||
def test_imaginary_part_of_a_purely_real_number(self): | ||
input_number = ComplexNumber(1, 0) | ||
self.assertEqual(input_number.imaginary, 0) | ||
|
||
def test_imaginary_part_of_a_purely_imaginary_number(self): | ||
input_number = ComplexNumber(0, 1) | ||
self.assertEqual(input_number.imaginary, 1) | ||
|
||
def test_maginary_part_of_a_number_with_real_and_imaginary_part(self): | ||
input_number = ComplexNumber(1, 2) | ||
self.assertEqual(input_number.imaginary, 2) | ||
|
||
def test_add_purely_real_numbers(self): | ||
first_input = ComplexNumber(1, 0) | ||
second_input = ComplexNumber(3, 0) | ||
self.assertEqual(first_input.add(second_input).real, 4) | ||
self.assertEqual(first_input.add(second_input).imaginary, 0) | ||
|
||
def test_add_purely_imaginary_numbers(self): | ||
first_input = ComplexNumber(0, 1) | ||
second_input = ComplexNumber(0, 3) | ||
self.assertEqual(first_input.add(second_input).real, 0) | ||
self.assertEqual(first_input.add(second_input).imaginary, 4) | ||
|
||
def test_add_numbers_with_real_and_imaginary_part(self): | ||
first_input = ComplexNumber(1, 2) | ||
second_input = ComplexNumber(4, 6) | ||
self.assertEqual(first_input.add(second_input).real, 5) | ||
self.assertEqual(first_input.add(second_input).imaginary, 8) | ||
|
||
def test_subtract_purely_real_numbers(self): | ||
first_input = ComplexNumber(1, 0) | ||
second_input = ComplexNumber(-1, 0) | ||
self.assertEqual(first_input.sub(second_input).real, 2) | ||
self.assertEqual(first_input.sub(second_input).imaginary, 0) | ||
|
||
def test_substract_numbers_with_real_and_imaginary_part(self): | ||
first_input = ComplexNumber(1, 2) | ||
second_input = ComplexNumber(-2, -2) | ||
self.assertEqual(first_input.sub(second_input).real, 3) | ||
self.assertEqual(first_input.sub(second_input).imaginary, 4) | ||
|
||
def test_multiply_purely_real_numbers(self): | ||
first_input = ComplexNumber(1, 0) | ||
second_input = ComplexNumber(2, 0) | ||
self.assertEqual(first_input.mul(second_input).real, 2) | ||
self.assertEqual(first_input.mul(second_input).imaginary, 0) | ||
|
||
def test_multiply_numbers_with_real_and_imaginary_part(self): | ||
first_input = ComplexNumber(1, 2) | ||
second_input = ComplexNumber(-5, 10) | ||
self.assertEqual(first_input.mul(second_input).real, -5) | ||
self.assertEqual(first_input.mul(second_input).imaginary, 20) | ||
|
||
def test_divide_purely_real_numbers(self): | ||
input_number = ComplexNumber(1.0, 0.0) | ||
expected = ComplexNumber(0.5, 0.0) | ||
divider = ComplexNumber(2.0, 0.0) | ||
self.assertEqual(expected.real, input_number.div(divider).real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.div(divider).imaginary) | ||
|
||
def test_divide_purely_imaginary_numbers(self): | ||
input_number = ComplexNumber(0, 1) | ||
expected = ComplexNumber(0.5, 0) | ||
divider = ComplexNumber(0, 2) | ||
self.assertEqual(expected.real, input_number.div(divider).real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.div(divider).imaginary) | ||
|
||
def test_divide_numbers_with_real_and_imaginary_part(self): | ||
input_number = ComplexNumber(1, 2) | ||
expected = ComplexNumber(0.44, 0.08) | ||
divider = ComplexNumber(3, 4) | ||
self.assertEqual(expected.real, input_number.div(divider).real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.div(divider).imaginary) | ||
|
||
def test_absolute_value_of_a_positive_purely_real_number(self): | ||
self.assertEqual(ComplexNumber(5, 0).abs(), 5) | ||
|
||
def test_absolute_value_of_a_negative_purely_real_number(self): | ||
self.assertEqual(ComplexNumber(-5, 0).abs(), 5) | ||
|
||
def test_absolute_value_of_imaginary_number_negative_imaginary_part(self): | ||
self.assertEqual(ComplexNumber(0, -5).abs(), 5) | ||
|
||
def test_absolute_value_of_imaginary_number_positive_imaginary_part(self): | ||
self.assertEqual(ComplexNumber(0, 5).abs(), 5) | ||
|
||
def test_absolute_value_of_a_number_with_real_and_imaginary_part(self): | ||
self.assertEqual(ComplexNumber(3, 4).abs(), 5) | ||
|
||
def test_conjugate_a_purely_real_number(self): | ||
input_number = ComplexNumber(5, 0) | ||
expected = ComplexNumber(5, 0) | ||
self.assertEqual(expected.real, input_number.conjugate().real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.conjugate().imaginary) | ||
|
||
def test_conjugate_a_purely_imaginary_number(self): | ||
input_number = ComplexNumber(0, 5) | ||
expected = ComplexNumber(0, -5) | ||
self.assertEqual(expected.real, input_number.conjugate().real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.conjugate().imaginary) | ||
|
||
def conjugate_a_number_with_real_and_imaginary_part(self): | ||
input_number = ComplexNumber(1, 1) | ||
expected = ComplexNumber(1, -1) | ||
self.assertEqual(expected.real, input_number.conjugate().real) | ||
self.assertEqual(expected.imaginary, | ||
input_number.conjugate().imaginary) | ||
|
||
def test_eulers_identity_formula(self): | ||
input_number = ComplexNumber(0, math.pi) | ||
expected = ComplexNumber(-1, 0) | ||
self.assertEqual(expected.real, input_number.exp().real) | ||
self.assertEqual(expected.imaginary, input_number.exp().imaginary) | ||
|
||
def test_exponential_of_0(self): | ||
input_number = ComplexNumber(0, 0) | ||
expected = ComplexNumber(1, 0) | ||
self.assertEqual(expected.real, input_number.exp().real) | ||
self.assertEqual(expected.imaginary, input_number.exp().imaginary) | ||
|
||
def test_exponential_of_a_purely_real_number(self): | ||
input_number = ComplexNumber(1, 0) | ||
expected = ComplexNumber(math.e, 0) | ||
self.assertEqual(expected.real, input_number.exp().real) | ||
self.assertEqual(expected.imaginary, input_number.exp().imaginary) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import math | ||
|
||
|
||
class ComplexNumber(object): | ||
def __init__(self, real, imaginary): | ||
self.real = real | ||
self.imaginary = imaginary | ||
|
||
def add(self, other): | ||
r = self.real + other.real | ||
i = self.imaginary + other.imaginary | ||
return ComplexNumber(r, i) | ||
|
||
def mul(self, other): | ||
r = self.real * other.real | ||
i = self.imaginary * other.imaginary | ||
return ComplexNumber(r, i) | ||
|
||
def sub(self, other): | ||
r = self.real - other.real | ||
i = self.imaginary - other.imaginary | ||
return ComplexNumber(r, i) | ||
|
||
def div(self, other): | ||
d = other.real * other.real + other.imaginary * other.imaginary | ||
r = (self.real * other.real + self.imaginary * | ||
other.imaginary) / float(d) | ||
i = (self.imaginary * other.real - self.real * | ||
self.real * other.imaginary) / float(d) | ||
return ComplexNumber(r, i) | ||
|
||
def abs(self): | ||
square_sum = self.real * self.real + self.imaginary * self.imaginary | ||
return math.sqrt(square_sum) | ||
|
||
def conjugate(self): | ||
return ComplexNumber(self.real, -1 * self.imaginary) | ||
|
||
def exp(self): | ||
r = round(math.cos(self.imaginary), 8) * math.exp(self.real) | ||
i = round(math.sin(self.imaginary), 8) * math.exp(self.real) | ||
return ComplexNumber(r, i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please share with us the reasoning behind this decision?
Don't get me wrong, I am not against it, just curios
And it turned out (while testing a new version of Exercism) that non-core exercise should be unlocked by only a core one.
We should revisit the whole track curriculum, perhaps you can help with a fresh view
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be completely honest, I was looking at a c# track, it looks somewhat finished, so I figured that their unlocking graph is finished too. If we will be redoing the whole of dependency graph, maybe it warrants separate issue and separate PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this should be addressed in a separate issue\PR.
I didn't have a chance to create it, I'll create it later today
But still, it's better to leave
unlocked_by
empty for now (until we'll figure out a list ofcore
exercises)