Skip to content

Commit 102089e

Browse files
committed
Merge pull request #1 from daigaku-ruby/add-chapter-numbers
Add chapter numbers
2 parents 5f151d3 + 755e26c commit 102089e

13 files changed

Lines changed: 383 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# e.g.:
2+
fixnum = 5
3+
bignum = 100_000_000_000_000_000_000
4+
rational = Rational(2, 7)
5+
complex = Complex(0.1, 2.5)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'rspec'
2+
3+
describe "Your code" do
4+
[['solution::code']]
5+
6+
{
7+
fixnum: Fixnum,
8+
bignum: Bignum,
9+
rational: Rational,
10+
complex: Complex
11+
}.each do |variable, class_name|
12+
it "defines a variable with name \"#{variable}\"" do
13+
expect(local_variables.include?(variable)).to be true
14+
end
15+
16+
if local_variables.include?(variable)
17+
it "defines a variable \"#{variable}\" which is a #{class_name}" do
18+
expect(eval(variable.to_s).class).to eq class_name
19+
end
20+
end
21+
end
22+
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Types of numbers
2+
3+
---
4+
5+
*You will learn:*
6+
- which types of numbers are available in Ruby
7+
- how to create a certain type of number
8+
- different ways to create a number
9+
10+
---
11+
12+
Ruby has following types of numbers: *Integer*, *Float*, *Rational*, and *Complex*.
13+
14+
## Integers
15+
16+
An *Integer* represents a *whole number*.
17+
You can create an Integer by declaring the number, like `2000` or `-42`.
18+
Ruby allows you to write more readable numbers by using underscores, e.g. `1_000_000`.
19+
Using the underscore style does not change the value of an integer, so `2_000` is
20+
perfectly the same as `2000`.
21+
22+
Another way to create an Integer is by calling `Integer()` with a parameter, e.g.:
23+
24+
` Integer(3)` *# => 3*
25+
` Integer('3')` *# => 3*
26+
27+
Internally, Ruby uses two different classes for Integers. Dependent on how big the
28+
Integer is it uses a *Fixnum* or a *Bignum*. You don't have to worry about which class to
29+
use, Ruby is taking care of this for you!
30+
31+
However, you can check which class Ruby uses for your number by calling the `class`
32+
method on your number. Open a new terminal tab and open the interactive Ruby console
33+
with `irb`. Then check the class of different numbers:
34+
35+
` 1000.class` *# => Fixnum*
36+
` 4_611_686_018_427_387_904.class` *# => Bignum*
37+
38+
If you want to learn more, read about Fixnum and Bignum here:
39+
- http://patshaughnessy.net/2014/1/9/how-big-is-a-bignum
40+
- (ruby-doc core: Integer)
41+
42+
## Floats
43+
44+
A *Float* represents an *inexact real number*.
45+
You can create a Float by declaring a number with a decimal place, like `3.0`
46+
or `-2_000.25`.
47+
Another way to create a Float is to call `Float()` with a parameter, e.g.:
48+
49+
` Float(3)` *# => 3.0*
50+
` Float('3')` *# => 3.0*
51+
52+
Read more about Float here: (ruby-doc core: Float).
53+
54+
## Rationals
55+
56+
A *Rational* represents a rational number (a paired integer number a/b, where b > 0).
57+
You can create a Rational by calling `Rational()` with one or two parameters, e.g.:
58+
59+
` Rational(2)` *# => (2/1)*
60+
` Rational(2, 3)` *# => (2/3)*
61+
` Rarional('2/3')` *# => (2/3)*
62+
63+
Read more about Rational here: (ruby-doc core: Rational).
64+
65+
## Complex numbers
66+
67+
A *Complex* represents a complex number.
68+
You can create a complex number by calling `Complex()` with one or two parameters, e.g.:
69+
70+
` Complex(2)` *# => (2+0i)*
71+
` Complex(2.1, 0.2)` *# => (2.1+0.2i)*
72+
` Complex('2.1+0.2i')` *# => (2.1+0.2i)*
73+
` Complex('2.1@0.2')` *# => (2.0581398134666076+0.4172055946696286i)* - polar form
74+
75+
Read more about Complex here: (ruby-doc core: Complex).
76+
77+
---
78+
79+
Create a number of each described type and store it into a variable with the
80+
lowercased name of the number's class (e.g. *rational* for Rational).
81+
Create both types of Integers (*Fixnum* and *Bignum*)!
82+
83+
---
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# e.g.:
2+
sum = Rational(1, 3) + Rational(2)
3+
difference = 1_000_000_000_000_000_000_000_000 - 1.9
4+
product = 2.4 * 5.6 * 2.3
5+
quotient = Complex(1) / 3.4
6+
power = Rational(2, 3) ** 3.5
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
require 'rspec'
2+
require 'rspec/expectations'
3+
require 'code_breaker'
4+
5+
RSpec::Matchers.define :run_number_operations do |expected|
6+
match do |actual|
7+
CodeBreaker.parse(actual).include?(expected)
8+
end
9+
10+
failure_message do |actual|
11+
expected_operants = expected.values.first
12+
variable_name = expected_operants[0]
13+
expected_operation = "#{variable_name} = #{expected_operants[1].join(' ')}"
14+
15+
actual_line = actual.split("\n").select do |output|
16+
output.match(/#{variable_name} =.+/)
17+
end
18+
19+
actual_parsed = CodeBreaker.parse(actual_line.join)
20+
actual_operants = actual_parsed.values.first
21+
actual_operation = "#{variable_name} = #{actual_operants[1].join(' ')}"
22+
23+
%Q{Your code doesn't run the number operation "#{expected_operation}".
24+
------- Instead you calculated "#{actual_operation}".}
25+
end
26+
end
27+
28+
# code_breaker outputs
29+
OPERATIONS = [
30+
{ lvasgn: [:sum, [Rational, :+, Rational]] },
31+
{ lvasgn: [:difference, [Bignum, :-, Float]] },
32+
{ lvasgn: [:product, [Float, :*, Float, :*, Float]] },
33+
{ lvasgn: [:quotient, [Complex, :/, Float]] },
34+
{ lvasgn: [:power, [Rational, :**, Float]] }
35+
].freeze
36+
37+
describe "Your code" do
38+
[['solution::code']]
39+
40+
OPERATIONS.each do |operation|
41+
variable_name = operation.first.last.first
42+
values = operation.values.first.last
43+
44+
it "defines a variable with name \"#{variable_name}\"" do
45+
expect(local_variables.include?(variable_name)).to be true
46+
end
47+
48+
if local_variables.include?(variable_name)
49+
operants = values.select.each_with_index { |_, i| i.even? }
50+
same_operants = (operants.uniq.count == 1)
51+
52+
numbers = if same_operants
53+
"#{operants.count} #{values.first} numbers"
54+
else
55+
operants.join(' and a ')
56+
end
57+
58+
it "calculates the #{variable_name} of #{numbers}" do
59+
code_lines = %Q{ [['solution::code']] }
60+
expect(code_lines).to run_number_operations(operation)
61+
end
62+
end
63+
end
64+
end
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Basic operators
2+
3+
---
4+
5+
*You will learn:*
6+
- how to use basic arithmetic operators on numbers
7+
- about the inaccuracy of *Float* values
8+
9+
---
10+
11+
All the numbers shown so far (*Fixnum*, *Bignum*, *Float*, *Rational*, and *Complex*)
12+
share the following basic operator methods:
13+
14+
` +` (addition)
15+
` -` (subtraction)
16+
` \*` (multiplication)
17+
` /` (division)
18+
` \*\*` (exponentiation)
19+
20+
You can apply these arithmetic operators by writing one of them between two
21+
numbers, e.g.:
22+
23+
` 3.2 + 7` *# => 10.2*
24+
` Rational(2, 3) - Rational(1, 2)` *# => (1/6)*
25+
` 3 \* 5` *# => 15*
26+
` Complex(2.0, 4) / Complex(4.0, 2.0)` *# => (0.8+0.6000000000000001i)*
27+
` 2 \*\* 3` *# => 8*
28+
29+
## "Strange" behaviours
30+
31+
When you try some combinations of numbers and operators in the interactive Ruby
32+
console (irb), you might think that sometimes strange things are going on.
33+
34+
For instance, why will `3 / 7` always equal *0*? And why does `0.6 + 0.3 + 0.1` equal
35+
*0.9999999999999999* and not *1.0*? (Try it, if you don't believe it!)
36+
37+
The explanation can be found in how Ruby handles numbers.
38+
If you divide an *Integer* by another *Integer*, then the result will be the rounded
39+
down *Integer* value (`5 / 2` equals *2*, `7 / 2` equals *3*).
40+
To get a floating point number you have to use a *Float* for either the numerator
41+
or the denominator or for both of them, i.e.:
42+
43+
` 3.0 / 7` *# => 0.42857142857142855*
44+
` 3 / 7.0` *# => 0.42857142857142855*
45+
` 3.0 / 7.0` *# => 0.42857142857142855*
46+
47+
The inaccuracy when summing up *Floats* appears beacause a *Float* is an approximation
48+
of a decimal number. Since floating point numbers are stored in binary in your
49+
computer, small rounding errors are likely to occur.
50+
51+
(if you really want to know what's going on here, you can read more about it on
52+
http://docs.sun.com/source/806-3568/ncg_goldberg.html!)
53+
54+
This binary representation of *Floats* is also the explanation for the inaccuracy
55+
when calculating the division of two *Complex* numbers (as in the example above,
56+
where the imaginary part is *0.6000000000000001* instead of *0.6*).
57+
58+
---
59+
60+
Connect numbers by each of the learned operators:
61+
62+
1. Sum up two *Rational* numbers
63+
2. Subtract a *Float* from a *Bignum*
64+
3. Build the product of three *Float* numbers
65+
4. Divide a *Complex* number by a *Fixnum*
66+
5. Calculate a *Rational* to the power of a *Float*
67+
68+
Store each result in a variable that is named like the result of the operation, e.g.
69+
for 1. *sum*,
70+
for 2. *difference*,
71+
and so on.
72+
73+
---
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# e.g.:
2+
integer = Complex(2.5).to_i
3+
float = 42.to_f
4+
rational = 10.25.to_r
5+
complex = Rational(1.1, 3.3).to_c
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require 'rspec'
2+
require 'rspec/expectations'
3+
require 'code_breaker'
4+
5+
RSpec::Matchers.define :run_number_conversions do |expected|
6+
METHODS = {
7+
to_i: 'to integer',
8+
to_f: 'to float',
9+
to_r: 'to Rational number',
10+
to_c: 'to Complex number'
11+
}
12+
13+
match do |actual|
14+
CodeBreaker.parse(actual).include?(expected)
15+
end
16+
17+
failure_message do |actual|
18+
expected_operants = expected.values.first
19+
variable_name = expected_operants[0]
20+
21+
expected_method = METHODS[expected_operants[1][1]]
22+
expected_conversion = "#{variable_name} = #{expected_operants[1][0]} #{expected_method}"
23+
24+
actual_line = actual.split("\n").select do |output|
25+
output.match(/#{variable_name} =.+/)
26+
end
27+
28+
actual_parsed = CodeBreaker.parse(actual_line.join)
29+
actual_operants = actual_parsed.values.first
30+
actual_conversion = "#{variable_name} = #{[actual_operants[1]].flatten.join(' ')}"
31+
32+
%Q{Your code doesn't run the number conversion "#{expected_conversion}".
33+
------- Instead you defined "#{actual_conversion}".}
34+
end
35+
end
36+
37+
# code_breaker outputs
38+
CONVERSIONS = [
39+
{ lvasgn: [:integer, [Complex, :to_i]] },
40+
{ lvasgn: [:float, [Fixnum, :to_f]] },
41+
{ lvasgn: [:rational, [Float, :to_r]] },
42+
{ lvasgn: [:complex, [Rational, :to_c]] }
43+
].freeze
44+
45+
describe "Your code" do
46+
[['solution::code']]
47+
48+
CONVERSIONS.each do |conversion|
49+
variable_name = conversion.first.last.first
50+
values = conversion.values.first.last
51+
52+
it "defines a variable with name \"#{variable_name}\"" do
53+
expect(local_variables.include?(variable_name)).to be true
54+
end
55+
56+
if local_variables.include?(variable_name)
57+
article = !!variable_name.match(/^[eioa]/) ? 'an' : 'a'
58+
59+
it "converts a #{values.first} number to #{article} #{variable_name}" do
60+
code_lines = %Q{ [['solution::code']] }
61+
expect(code_lines).to run_number_conversions(conversion)
62+
end
63+
end
64+
end
65+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Converting numbers
2+
3+
---
4+
5+
*You will learn:*
6+
- how to convert numbers to other number formats
7+
8+
---
9+
10+
There are several methods you can apply on numbers to explicitly convert a number
11+
to another number format:
12+
13+
` to_i` converts to an *Integer* number
14+
` to_f` converts to a *Float* number
15+
` to_r` converts to a *Rational* values
16+
` to_c` converts to a *Complex* number
17+
18+
Converting a number to its own type will just return the number, e.g.:
19+
20+
` 123.to_i` *# => 123*
21+
` 4.75.to_f` *# => 4.75*
22+
` Rational(3, 7).to_r` *# => (3,7)*
23+
` Complex(2.1, 3.2).to_c` *# => (2.1+3.2i)*
24+
25+
If you convert a Float, a Rational or a Complex number to an Integer by calling
26+
the `to_i` method then the digits after the decimal point are just cut off.
27+
Note that the size of the fraction doesn't matter:
28+
29+
` 2.01.to_i` and `2.95.to_i` will both return *2*.
30+
31+
If you want to convert a float to an integer based on its digits after the decimal point,
32+
you should have a look at the following methods of a Numeric:
33+
34+
` #ceils`: (ruby-doc core: Numeric#ceil)
35+
` #floor`: (ruby-doc core: Numeric#floor)
36+
` #round`: (ruby-doc core: Numeric#round)
37+
38+
One thing you can't do is converting a Complex number with an imaginary part other
39+
than `0` to an integer, float, or rational number.
40+
41+
For instance `Complex(5.3, 0.5).to_i` will throw an Error (*RangeError: can't convert 5.3+0.5i into Integer*),
42+
whereas `Complex(5.3).to_i` will give you a *5*.
43+
44+
---
45+
46+
Convert numbers into other formats:
47+
48+
1. Convert a *Complex* number into an *Integer*
49+
2. Convert a *Fixnum* integer into a *Float*
50+
3. Convert a *Float* into a *Rational* number
51+
4. Convert a *Rational* number into an *Complex* number
52+
53+
Store each result in a variable that is named like the resulting type of the conversion, e.g.
54+
for 1. *integer*,
55+
for 2. *float*,
56+
and so on.
57+
58+
---

0 commit comments

Comments
 (0)