vector_number 0.2.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +72 -6
- data/LICENSE.txt +21 -0
- data/README.md +21 -13
- data/lib/vector_number/comparing.rb +55 -2
- data/lib/vector_number/converting.rb +86 -6
- data/lib/vector_number/enumerating.rb +70 -13
- data/lib/vector_number/math_converting.rb +66 -6
- data/lib/vector_number/mathing.rb +215 -35
- data/lib/vector_number/numeric_refinements.rb +33 -9
- data/lib/vector_number/querying.rb +84 -15
- data/lib/vector_number/stringifying.rb +32 -2
- data/lib/vector_number/version.rb +2 -2
- data/lib/vector_number.rb +114 -29
- data/sig/vector_number.rbs +10 -4
- metadata +12 -6
@@ -3,45 +3,105 @@
|
|
3
3
|
class VectorNumber
|
4
4
|
# Various mathematical operations that are also conversions.
|
5
5
|
module MathConverting
|
6
|
-
#
|
6
|
+
# Calculate the absolute value of the vector, i.e. its length.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# VectorNumber[5.3].abs # => 5.3
|
10
|
+
# VectorNumber[-5.3i].magnitude # => 5.3
|
11
|
+
# VectorNumber[-5.3i, "i"].abs # => 5.3935146240647205
|
12
|
+
#
|
7
13
|
# @return [Float]
|
14
|
+
#
|
15
|
+
# @since 0.2.2
|
8
16
|
def abs
|
9
|
-
Math.sqrt(
|
17
|
+
Math.sqrt(abs2)
|
10
18
|
end
|
11
19
|
|
12
20
|
alias magnitude abs
|
13
21
|
|
14
|
-
#
|
22
|
+
# Calculate the square of absolute value.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# VectorNumber[5.3].abs2 # => 5.3
|
26
|
+
# VectorNumber[-5.3i].abs2 # => 5.3
|
27
|
+
# VectorNumber[-5.3i, "i"].abs2 # => 29.09
|
28
|
+
#
|
15
29
|
# @return [Float]
|
16
|
-
|
17
|
-
|
30
|
+
#
|
31
|
+
# @since 0.2.2
|
32
|
+
def abs2
|
33
|
+
coefficients.sum(&:abs2)
|
18
34
|
end
|
19
35
|
|
20
36
|
# Return a new vector with every coefficient truncated using their +#truncate+.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# VectorNumber[5.39].truncate # => (5)
|
40
|
+
# VectorNumber[-5.35i].truncate # => (-5i)
|
41
|
+
# VectorNumber[-5.35i, "i"].truncate # => (-5i + 1⋅'i')
|
42
|
+
# VectorNumber[-5.35i, "i"].truncate(1) # => (-5.3i + 1⋅'i')
|
43
|
+
# VectorNumber[-5.35i, "i"].truncate(-1) # => (0)
|
44
|
+
#
|
21
45
|
# @param digits [Integer]
|
22
46
|
# @return [VectorNumber]
|
47
|
+
#
|
48
|
+
# @since 0.2.1
|
23
49
|
def truncate(digits = 0)
|
24
50
|
new { _1.truncate(digits) }
|
25
51
|
end
|
26
52
|
|
27
53
|
# Return a new vector with every coefficient rounded using their +#ceil+.
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# VectorNumber[5.39].ceil # => (6)
|
57
|
+
# VectorNumber[-5.35i].ceil # => (-5i)
|
58
|
+
# VectorNumber[-5.35i, "i"].ceil # => (-5i + 1⋅'i')
|
59
|
+
# VectorNumber[-5.35i, "i"].ceil(1) # => (-5.3i + 1⋅'i')
|
60
|
+
# VectorNumber[-5.35i, "i"].ceil(-1) # => (10⋅'i')
|
61
|
+
#
|
28
62
|
# @param digits [Integer]
|
29
63
|
# @return [VectorNumber]
|
64
|
+
#
|
65
|
+
# @since 0.2.2
|
30
66
|
def ceil(digits = 0)
|
31
67
|
new { _1.ceil(digits) }
|
32
68
|
end
|
33
69
|
|
34
70
|
# Return a new vector with every coefficient rounded using their +#floor+.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# VectorNumber[5.39].floor # => (5)
|
74
|
+
# VectorNumber[-5.35i].floor # => (-6i)
|
75
|
+
# VectorNumber[-5.35i, "i"].floor # => (-6i + 1⋅'i')
|
76
|
+
# VectorNumber[-5.35i, "i"].floor(1) # => (-5.4i + 1⋅'i')
|
77
|
+
# VectorNumber[-5.35i, "i"].floor(-1) # => (-10i)
|
78
|
+
#
|
35
79
|
# @param digits [Integer]
|
36
80
|
# @return [VectorNumber]
|
81
|
+
#
|
82
|
+
# @since 0.2.2
|
37
83
|
def floor(digits = 0)
|
38
84
|
new { _1.floor(digits) }
|
39
85
|
end
|
40
86
|
|
41
87
|
# Return a new vector with every coefficient rounded using their +#round+.
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# VectorNumber[-4.5i, "i"].round(half: :up) # => (-5i + 1⋅'i')
|
91
|
+
# VectorNumber[-4.5i, "i"].round(half: :even) # => (-4i + 1⋅'i')
|
92
|
+
# VectorNumber[-5.5i, "i"].round(half: :even) # => (-6i + 1⋅'i')
|
93
|
+
# VectorNumber[-5.5i, "i"].round(half: :down) # => (-5i + 1⋅'i')
|
94
|
+
# VectorNumber[-5.35i, "i"].round(1) # => (-5.4i + 1⋅'i')
|
95
|
+
# VectorNumber[-5.35i, "i"].round(-1) # => (-10i)
|
96
|
+
#
|
42
97
|
# @param digits [Integer]
|
43
|
-
# @param half [Symbol, nil] one of +:up+, +:down+ or +:even+,
|
98
|
+
# @param half [Symbol, nil] one of +:up+, +:down+ or +:even+,
|
99
|
+
# see +Float#round+ for meaning
|
44
100
|
# @return [VectorNumber]
|
101
|
+
#
|
102
|
+
# @see Float#round
|
103
|
+
#
|
104
|
+
# @since 0.2.2
|
45
105
|
def round(digits = 0, half: :up)
|
46
106
|
if defined?(BigDecimal)
|
47
107
|
bd_mode =
|
@@ -2,11 +2,26 @@
|
|
2
2
|
|
3
3
|
class VectorNumber
|
4
4
|
# Methods for performing actual math.
|
5
|
+
#
|
6
|
+
# All operators (like +*+) have aliases (like +mult+)
|
7
|
+
# to make method chaining easier and more natural.
|
5
8
|
module Mathing
|
6
9
|
# The coerce method provides support for Ruby type coercion.
|
7
|
-
#
|
10
|
+
#
|
11
|
+
# Unlike other numeric types, VectorNumber can coerce *anything*.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# VectorNumber["a"].coerce(5) # => [(5), (1⋅'a')]
|
15
|
+
# VectorNumber[7].coerce([]) # => [(1⋅[]), (7)]
|
16
|
+
# VectorNumber["a"] + 5 # => (1⋅'a' + 5)
|
17
|
+
# # Direct reverse coercion doesn't work, but Numeric types know how to call #coerce:
|
18
|
+
# 5.coerce(VectorNumber["a"]) # RangeError
|
19
|
+
# 5 + VectorNumber["a"] # => (5 + 1⋅'a')
|
20
|
+
#
|
8
21
|
# @param other [Object]
|
9
22
|
# @return [Array(VectorNumber, VectorNumber)]
|
23
|
+
#
|
24
|
+
# @since 0.2.0
|
10
25
|
def coerce(other)
|
11
26
|
case other
|
12
27
|
when VectorNumber
|
@@ -16,40 +31,87 @@ class VectorNumber
|
|
16
31
|
end
|
17
32
|
end
|
18
33
|
|
19
|
-
# Return
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
#
|
26
|
-
# This preserves order of units.
|
34
|
+
# Return new vector with negated coefficients (additive inverse).
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# -VectorNumber[12, "i"] # => (-12 - 1⋅'i')
|
38
|
+
# VectorNumber["a", "b", "a"].neg # => (-2⋅'a' - 1⋅'b')
|
39
|
+
# -VectorNumber["a"] + VectorNumber["a"] # => (0)
|
40
|
+
#
|
27
41
|
# @return [VectorNumber]
|
42
|
+
#
|
43
|
+
# @since 0.2.0
|
28
44
|
def -@
|
29
45
|
new(&:-@)
|
30
46
|
end
|
31
47
|
|
32
|
-
#
|
48
|
+
# @since 0.3.0
|
49
|
+
alias neg -@
|
50
|
+
|
51
|
+
# Return new vector as a sum of this and +other+ value.
|
33
52
|
# This is analogous to {VectorNumber.[]}.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# VectorNumber[5] + 10 # => (15)
|
56
|
+
# VectorNumber["a"].add(VectorNumber["b"]) # => (1⋅'a' + 1⋅'b')
|
57
|
+
# VectorNumber["a"] + "b" # => (1⋅'a' + 1⋅'b')
|
58
|
+
# @example numeric types can be added in reverse
|
59
|
+
# 10 + VectorNumber[5] # => (15)
|
60
|
+
# 10 + VectorNumber["a"] # => (10 + 1⋅'a')
|
61
|
+
#
|
34
62
|
# @param other [Object]
|
35
63
|
# @return [VectorNumber]
|
64
|
+
#
|
65
|
+
# @since 0.2.0
|
36
66
|
def +(other)
|
37
67
|
new([self, other])
|
38
68
|
end
|
39
69
|
|
40
|
-
#
|
41
|
-
|
70
|
+
# @since 0.3.0
|
71
|
+
alias add +
|
72
|
+
|
73
|
+
# Return new vector as a sum of this and additive inverse of +other+ value.
|
74
|
+
#
|
75
|
+
# This is implemented through {#+} and {#-@}.
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# VectorNumber[5] - 3 # => (2)
|
79
|
+
# VectorNumber["a"].sub(VectorNumber["b"]) # => (1⋅'a' - 1⋅'b')
|
80
|
+
# VectorNumber["a"] - "b" # => (1⋅'a' - 1⋅'b')
|
81
|
+
# @example numeric types can be subtracted in reverse
|
82
|
+
# 3 - VectorNumber[5] # => (-2)
|
83
|
+
# 3 - VectorNumber["a"] # => (3 - 1⋅'a')
|
84
|
+
#
|
42
85
|
# @param other [Object]
|
43
86
|
# @return [VectorNumber]
|
87
|
+
#
|
88
|
+
# @since 0.2.0
|
44
89
|
def -(other)
|
45
90
|
self + new([other], &:-@)
|
46
91
|
end
|
47
92
|
|
48
|
-
#
|
49
|
-
|
93
|
+
# @since 0.3.0
|
94
|
+
alias sub -
|
95
|
+
|
96
|
+
# Multiply all coefficients by a real +other+, returning new vector.
|
97
|
+
#
|
98
|
+
# This effectively multiplies {#magnitude} by +other+.
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# VectorNumber[5] * 2 # => (10)
|
102
|
+
# VectorNumber["a", "b", 6].mult(2) # => (2⋅'a' + 2⋅'b' + 12)
|
103
|
+
# VectorNumber["a"] * VectorNumber[2] # => (2⋅'a')
|
104
|
+
# # Can't multiply by a non-real:
|
105
|
+
# VectorNumber["a"] * VectorNumber["b"] # RangeError
|
106
|
+
# @example numeric types can be multiplied in reverse
|
107
|
+
# 2 * VectorNumber[5] # => (10)
|
108
|
+
# 2 * VectorNumber["a"] # => (2⋅'a')
|
109
|
+
#
|
50
110
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
51
111
|
# @return [VectorNumber]
|
52
112
|
# @raise [RangeError] if +other+ is not a number or +other+ can't be multiplied by this one
|
113
|
+
#
|
114
|
+
# @since 0.2.1
|
53
115
|
def *(other)
|
54
116
|
if real_number?(other)
|
55
117
|
other = other.real
|
@@ -63,30 +125,67 @@ class VectorNumber
|
|
63
125
|
end
|
64
126
|
end
|
65
127
|
|
66
|
-
#
|
67
|
-
|
128
|
+
# @since 0.3.0
|
129
|
+
alias mult *
|
130
|
+
|
131
|
+
# Divide all coefficients by a real +other+, returning new vector.
|
132
|
+
#
|
133
|
+
# This effectively multiplies {#magnitude} by reciprocal of +other+.
|
134
|
+
# @note This method never does integer division.
|
135
|
+
#
|
136
|
+
# @example
|
137
|
+
# VectorNumber[10] / 2 # => (5)
|
138
|
+
# VectorNumber["a", "b", 6].quo(2) # => (1/2⋅'a' + 1/2⋅'b' + 3/1)
|
139
|
+
# VectorNumber["a"] / VectorNumber[2] # => (1/2⋅'a')
|
140
|
+
# # Can't divide by a non-real:
|
141
|
+
# VectorNumber["a"] / VectorNumber["b"] # RangeError
|
142
|
+
# @example numeric types can be divided in reverse
|
143
|
+
# 2 / VectorNumber[10] # => (1/5)
|
144
|
+
# # Can't divide by a non-real:
|
145
|
+
# 2 / VectorNumber["a"] # RangeError
|
146
|
+
#
|
68
147
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
69
148
|
# @return [VectorNumber]
|
70
149
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
71
150
|
# @raise [ZeroDivisionError] if +other+ is zero
|
151
|
+
#
|
152
|
+
# @since 0.2.1
|
72
153
|
def /(other)
|
73
154
|
check_divisibility(other)
|
74
155
|
|
75
156
|
other = other.real
|
76
157
|
# Prevent integer division, but without loss of accuracy.
|
77
|
-
other = Rational(other) if other.
|
158
|
+
other = Rational(other) if other.integer?
|
78
159
|
# @type var other: Float
|
79
160
|
new { _1 / other }
|
80
161
|
end
|
81
162
|
|
163
|
+
# @since 0.2.6
|
82
164
|
alias quo /
|
165
|
+
# to fix syntax highlighting: /
|
83
166
|
|
84
|
-
# Divide all coefficients by a real
|
85
|
-
# with Float coefficients.
|
167
|
+
# Divide all coefficients by a real +other+ using +fdiv+,
|
168
|
+
# returning new vector with Float (or BigDecimal) coefficients.
|
169
|
+
#
|
170
|
+
# There isn't much benefit to this method, as {#/} doesn't do integer division,
|
171
|
+
# but it is provided for consistency.
|
172
|
+
#
|
173
|
+
# @example
|
174
|
+
# VectorNumber[10].fdiv(2) # => (5.0)
|
175
|
+
# VectorNumber["a", "b", 6].fdiv(2) # => (0.5⋅'a' + 0.5⋅'b' + 3.0)
|
176
|
+
# VectorNumber["a"].fdiv(VectorNumber[2]) # => (0.5⋅'a')
|
177
|
+
# # Can't divide by a non-real:
|
178
|
+
# VectorNumber["a"].fdiv(VectorNumber["b"]) # RangeError
|
179
|
+
# @example reverse division may return non-vector results
|
180
|
+
# 2.fdiv(VectorNumber[10]) # => 0.2 (Float)
|
181
|
+
# 2.0.fdiv(VectorNumber[10]) # => (0.2) (VectorNumber)
|
182
|
+
#
|
86
183
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
87
184
|
# @return [VectorNumber]
|
88
185
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
89
186
|
# @raise [ZeroDivisionError] if +other+ is zero
|
187
|
+
#
|
188
|
+
# @since 0.2.1
|
90
189
|
def fdiv(other)
|
91
190
|
check_divisibility(other)
|
92
191
|
|
@@ -94,14 +193,30 @@ class VectorNumber
|
|
94
193
|
new { _1.fdiv(other) }
|
95
194
|
end
|
96
195
|
|
97
|
-
# Divide all coefficients by +other+, rounding results with
|
196
|
+
# Divide all coefficients by a real +other+, rounding results with +#floor+.
|
197
|
+
#
|
98
198
|
# This is requal to +(self / other).floor+.
|
199
|
+
#
|
200
|
+
# @example
|
201
|
+
# VectorNumber[10].div(3) # => (3)
|
202
|
+
# VectorNumber["a"].div(2) # => (0⋅'a')
|
203
|
+
# VectorNumber["a"].div(VectorNumber[2]) # => (0⋅'a')
|
204
|
+
# # Can't divide by a non-real:
|
205
|
+
# VectorNumber["a"].div(VectorNumber["b"]) # RangeError
|
206
|
+
# @example numeric types can be divided in reverse
|
207
|
+
# 2.div(VectorNumber[10]) # => (0)
|
208
|
+
# # Can't divide by a non-real:
|
209
|
+
# 2.div(VectorNumber["a"]) # RangeError
|
210
|
+
#
|
211
|
+
# @see #divmod
|
212
|
+
# @see #%
|
213
|
+
#
|
99
214
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
100
215
|
# @return [VectorNumber]
|
101
216
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
102
217
|
# @raise [ZeroDivisionError] if +other+ is zero
|
103
|
-
#
|
104
|
-
# @
|
218
|
+
#
|
219
|
+
# @since 0.2.6
|
105
220
|
def div(other)
|
106
221
|
check_divisibility(other)
|
107
222
|
|
@@ -109,16 +224,36 @@ class VectorNumber
|
|
109
224
|
new { _1.div(other) }
|
110
225
|
end
|
111
226
|
|
112
|
-
# Return the modulus of dividing self by +other+ as a vector.
|
113
|
-
#
|
227
|
+
# Return the modulus of dividing self by a real +other+ as a vector.
|
228
|
+
#
|
229
|
+
# This is equal to +self - other * (self/other).floor+,
|
230
|
+
# or, alternatively, +self - other * self.div(other)+.
|
231
|
+
#
|
232
|
+
# @example
|
233
|
+
# VectorNumber[10] % 3 # => (1)
|
234
|
+
# VectorNumber["a", "b", 6].modulo(2) # => (1⋅'a' + 1⋅'b')
|
235
|
+
# -VectorNumber["a"] % VectorNumber[2] # => (1⋅'a')
|
236
|
+
# # Can't divide by a non-real:
|
237
|
+
# VectorNumber["a"] % VectorNumber["b"] # RangeError
|
238
|
+
# @example numeric types can be divided in reverse
|
239
|
+
# 3 % VectorNumber[10] # => (3)
|
240
|
+
# # Can't divide by a non-real:
|
241
|
+
# 3 % VectorNumber["a"] # RangeError
|
242
|
+
# @example compare to #remainder
|
243
|
+
# VectorNumber[-5] % 3 # => (1)
|
244
|
+
# VectorNumber[-5].remainder(3) # => (-2)
|
245
|
+
#
|
246
|
+
# @see #divmod
|
247
|
+
# @see #div
|
248
|
+
# @see #remainder
|
249
|
+
# @see Numeric#%
|
250
|
+
#
|
114
251
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
115
252
|
# @return [VectorNumber]
|
116
253
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
117
254
|
# @raise [ZeroDivisionError] if +other+ is zero
|
118
|
-
#
|
119
|
-
# @
|
120
|
-
# @see #remainder for alternative
|
121
|
-
# @see Numeric#% for examples
|
255
|
+
#
|
256
|
+
# @since 0.2.6
|
122
257
|
def %(other)
|
123
258
|
check_divisibility(other)
|
124
259
|
|
@@ -126,28 +261,63 @@ class VectorNumber
|
|
126
261
|
new { _1 % other }
|
127
262
|
end
|
128
263
|
|
264
|
+
# @since 0.2.6
|
129
265
|
alias modulo %
|
130
266
|
|
131
|
-
# Return the quotient and modulus of dividing self by +other+.
|
267
|
+
# Return the quotient and modulus of dividing self by a real +other+.
|
132
268
|
# There is no performance benefit compared to calling {#div} and {#%} separately.
|
269
|
+
#
|
270
|
+
# @example
|
271
|
+
# VectorNumber[10].divmod(3) # => [(3), (1)]
|
272
|
+
# VectorNumber["a"].divmod(2) # => [(0⋅'a'), (1⋅'a')]
|
273
|
+
# VectorNumber["a"].divmod(VectorNumber[2]) # => [(0⋅'a'), (1⋅'a')]
|
274
|
+
# # Can't divide by a non-real:
|
275
|
+
# VectorNumber["a"].divmod(VectorNumber["b"]) # RangeError
|
276
|
+
# @example numeric types can be divided in reverse
|
277
|
+
# 3.divmod(VectorNumber[10]) # => [(0), (3)]
|
278
|
+
# # Can't divide by a non-real:
|
279
|
+
# 3.divmod(VectorNumber["a"]) # RangeError
|
280
|
+
#
|
281
|
+
# @see #div
|
282
|
+
# @see #%
|
283
|
+
#
|
133
284
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
134
285
|
# @return [Array(VectorNumber, VectorNumber)]
|
135
286
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
136
287
|
# @raise [ZeroDivisionError] if +other+ is zero
|
137
|
-
#
|
138
|
-
# @
|
288
|
+
#
|
289
|
+
# @since 0.2.6
|
139
290
|
def divmod(other)
|
140
291
|
[div(other), modulo(other)]
|
141
292
|
end
|
142
293
|
|
143
|
-
# Return the remainder of dividing self by +other+ as a vector.
|
294
|
+
# Return the remainder of dividing self by a real +other+ as a vector.
|
295
|
+
#
|
144
296
|
# This is equal to +self - other * (self/other).truncate+.
|
297
|
+
#
|
298
|
+
# @example
|
299
|
+
# VectorNumber[10].remainder(3) # => (1)
|
300
|
+
# VectorNumber["a"].remainder(2) # => (1⋅'a')
|
301
|
+
# -VectorNumber["a"].remainder(VectorNumber[2]) # => (-1⋅'a')
|
302
|
+
# # Can't divide by a non-real:
|
303
|
+
# VectorNumber["a"].remainder(VectorNumber["b"]) # RangeError
|
304
|
+
# @example numeric types can be divided in reverse
|
305
|
+
# 3.remainder(VectorNumber[10]) # => (3)
|
306
|
+
# # Can't divide by a non-real:
|
307
|
+
# 3.remainder(VectorNumber["a"]) # RangeError
|
308
|
+
# @example compare to #%
|
309
|
+
# VectorNumber[-5] % 3 # => (1)
|
310
|
+
# VectorNumber[-5].remainder(3) # => (-2)
|
311
|
+
#
|
312
|
+
# @see #%
|
313
|
+
# @see Numeric#remainder
|
314
|
+
#
|
145
315
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
146
316
|
# @return [VectorNumber]
|
147
317
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
148
318
|
# @raise [ZeroDivisionError] if +other+ is zero
|
149
|
-
#
|
150
|
-
# @
|
319
|
+
#
|
320
|
+
# @since 0.2.6
|
151
321
|
def remainder(other)
|
152
322
|
check_divisibility(other)
|
153
323
|
|
@@ -157,8 +327,18 @@ class VectorNumber
|
|
157
327
|
|
158
328
|
private
|
159
329
|
|
330
|
+
# @param other [Object]
|
331
|
+
# @return [void]
|
332
|
+
# @raise [RangeError] unless +other+ is a real number
|
333
|
+
# @raise [ZeroDivisionError]
|
334
|
+
#
|
335
|
+
# @see real_number?
|
336
|
+
#
|
337
|
+
# @since 0.2.6
|
160
338
|
def check_divisibility(other)
|
161
|
-
|
339
|
+
unless real_number?(other)
|
340
|
+
raise RangeError, "can't divide #{self} by #{other.inspect}", caller
|
341
|
+
end
|
162
342
|
raise ZeroDivisionError, "divided by 0", caller if other.zero?
|
163
343
|
end
|
164
344
|
end
|
@@ -1,21 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class VectorNumber
|
4
|
-
# Refinements of Numeric classes to better work with VectorNumber and similar classes.
|
4
|
+
# Refinements of Numeric classes and Kernel to better work with VectorNumber and similar classes.
|
5
|
+
#
|
6
|
+
# These do not depend on +VectorNumber+ and can technically be used separately.
|
7
|
+
# Currently includes:
|
8
|
+
# - refinement for +Complex#<=>+ to work with classes implementing +<=>+;
|
9
|
+
# - refinement for +Kernel#BigDecimal+ to work with classes implementing +to_d+.
|
10
|
+
#
|
11
|
+
# @example activating refinements
|
12
|
+
# require "vector_number/numeric_refinements"
|
13
|
+
# using VectorNumber::NumericRefinements
|
14
|
+
#
|
15
|
+
# @since 0.2.0
|
5
16
|
module NumericRefinements
|
6
17
|
# Refinement module to provide a +#<=>+ method that can work backwards.
|
18
|
+
#
|
7
19
|
# @note Currently only applies to Complex on *3.1*,
|
8
20
|
# as other numeric classes rely on +#coerce+.
|
21
|
+
# @example without refinements
|
22
|
+
# VectorNumber[2] <=> Complex(1, 0) #=> 1
|
23
|
+
# Complex(1, 0) <=> VectorNumber[2] #=> nil
|
24
|
+
# @example with refinements
|
25
|
+
# require "vector_number/numeric_refinements"
|
26
|
+
# using VectorNumber::NumericRefinements
|
27
|
+
# VectorNumber[2] <=> Complex(1, 0) #=> 1
|
28
|
+
# Complex(1, 0) <=> VectorNumber[2] #=> -1
|
29
|
+
#
|
30
|
+
# @since 0.2.1
|
9
31
|
module CommutativeShuttle
|
10
32
|
# Commutative +#<=>+.
|
11
|
-
#
|
12
|
-
# Complex(1, 0) <=> VectorNumber[2] # => nil
|
13
|
-
# VectorNumber[2] <=> Complex(1, 0) # => 1
|
14
|
-
# @example with refinements
|
15
|
-
# require "vector_number/numeric_refinements"
|
16
|
-
# using VectorNumber::NumericRefinements
|
17
|
-
# Complex(1, 0) <=> VectorNumber[2] # => -1
|
18
|
-
# VectorNumber[2] <=> Complex(1, 0) # => 1
|
33
|
+
# Tries to call +other <=> self+ if +self <=> other+ returns +nil+.
|
19
34
|
def <=>(other)
|
20
35
|
comparison = super
|
21
36
|
return comparison if comparison || !other.respond_to?(:<=>)
|
@@ -30,7 +45,16 @@ class VectorNumber
|
|
30
45
|
end
|
31
46
|
|
32
47
|
# Refinement module to change Kernel#BigDecimal so it works with +#to_d+.
|
48
|
+
#
|
33
49
|
# @note `BigDecimal` needs to be defined for this refinement to activate.
|
50
|
+
# @example without refinements
|
51
|
+
# BigDecimal(VectorNumber[2]) # can't convert VectorNumber into BigDecimal (TypeError)
|
52
|
+
# @example with refinements
|
53
|
+
# require "vector_number/numeric_refinements"
|
54
|
+
# using VectorNumber::NumericRefinements
|
55
|
+
# BigDecimal(VectorNumber[2]) #=> 0.2e1
|
56
|
+
#
|
57
|
+
# @since 0.2.1
|
34
58
|
module BigDecimalToD
|
35
59
|
# BigDecimal() that first tries to use #to_d.
|
36
60
|
# @param value [Object]
|