vector_number 0.3.0 → 0.4.0
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 +61 -3
- data/LICENSE.txt +21 -0
- data/README.md +19 -10
- 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 +207 -33
- data/lib/vector_number/numeric_refinements.rb +33 -9
- data/lib/vector_number/querying.rb +84 -15
- data/lib/vector_number/stringifying.rb +31 -2
- data/lib/vector_number/version.rb +2 -2
- data/lib/vector_number.rb +114 -45
- data/sig/vector_number.rbs +3 -3
- metadata +16 -5
@@ -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,44 +31,87 @@ class VectorNumber
|
|
16
31
|
end
|
17
32
|
end
|
18
33
|
|
19
|
-
# Return
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
#
|
24
|
-
#
|
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
|
+
#
|
25
41
|
# @return [VectorNumber]
|
42
|
+
#
|
43
|
+
# @since 0.2.0
|
26
44
|
def -@
|
27
45
|
new(&:-@)
|
28
46
|
end
|
29
47
|
|
48
|
+
# @since 0.3.0
|
30
49
|
alias neg -@
|
31
50
|
|
32
|
-
# Return new vector as a sum of this and other value.
|
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
|
|
70
|
+
# @since 0.3.0
|
40
71
|
alias add +
|
41
72
|
|
42
|
-
# Return new vector as a sum of this and
|
43
|
-
#
|
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
|
+
#
|
44
85
|
# @param other [Object]
|
45
86
|
# @return [VectorNumber]
|
87
|
+
#
|
88
|
+
# @since 0.2.0
|
46
89
|
def -(other)
|
47
90
|
self + new([other], &:-@)
|
48
91
|
end
|
49
92
|
|
93
|
+
# @since 0.3.0
|
50
94
|
alias sub -
|
51
95
|
|
52
|
-
# Multiply all coefficients by a real
|
53
|
-
#
|
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
|
+
#
|
54
110
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
55
111
|
# @return [VectorNumber]
|
56
112
|
# @raise [RangeError] if +other+ is not a number or +other+ can't be multiplied by this one
|
113
|
+
#
|
114
|
+
# @since 0.2.1
|
57
115
|
def *(other)
|
58
116
|
if real_number?(other)
|
59
117
|
other = other.real
|
@@ -67,32 +125,67 @@ class VectorNumber
|
|
67
125
|
end
|
68
126
|
end
|
69
127
|
|
128
|
+
# @since 0.3.0
|
70
129
|
alias mult *
|
71
130
|
|
72
|
-
# Divide all coefficients by a real
|
73
|
-
#
|
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
|
+
#
|
74
147
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
75
148
|
# @return [VectorNumber]
|
76
149
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
77
150
|
# @raise [ZeroDivisionError] if +other+ is zero
|
151
|
+
#
|
152
|
+
# @since 0.2.1
|
78
153
|
def /(other)
|
79
154
|
check_divisibility(other)
|
80
155
|
|
81
156
|
other = other.real
|
82
157
|
# Prevent integer division, but without loss of accuracy.
|
83
|
-
other = Rational(other) if other.
|
158
|
+
other = Rational(other) if other.integer?
|
84
159
|
# @type var other: Float
|
85
160
|
new { _1 / other }
|
86
161
|
end
|
87
162
|
|
163
|
+
# @since 0.2.6
|
88
164
|
alias quo /
|
165
|
+
# to fix syntax highlighting: /
|
89
166
|
|
90
|
-
# Divide all coefficients by a real
|
91
|
-
# 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
|
+
#
|
92
183
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
93
184
|
# @return [VectorNumber]
|
94
185
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
95
186
|
# @raise [ZeroDivisionError] if +other+ is zero
|
187
|
+
#
|
188
|
+
# @since 0.2.1
|
96
189
|
def fdiv(other)
|
97
190
|
check_divisibility(other)
|
98
191
|
|
@@ -100,14 +193,30 @@ class VectorNumber
|
|
100
193
|
new { _1.fdiv(other) }
|
101
194
|
end
|
102
195
|
|
103
|
-
# Divide all coefficients by +other+, rounding results with
|
196
|
+
# Divide all coefficients by a real +other+, rounding results with +#floor+.
|
197
|
+
#
|
104
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
|
+
#
|
105
214
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
106
215
|
# @return [VectorNumber]
|
107
216
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
108
217
|
# @raise [ZeroDivisionError] if +other+ is zero
|
109
|
-
#
|
110
|
-
# @
|
218
|
+
#
|
219
|
+
# @since 0.2.6
|
111
220
|
def div(other)
|
112
221
|
check_divisibility(other)
|
113
222
|
|
@@ -115,16 +224,36 @@ class VectorNumber
|
|
115
224
|
new { _1.div(other) }
|
116
225
|
end
|
117
226
|
|
118
|
-
# Return the modulus of dividing self by +other+ as a vector.
|
119
|
-
#
|
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
|
+
#
|
120
251
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
121
252
|
# @return [VectorNumber]
|
122
253
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
123
254
|
# @raise [ZeroDivisionError] if +other+ is zero
|
124
|
-
#
|
125
|
-
# @
|
126
|
-
# @see #remainder for alternative
|
127
|
-
# @see Numeric#% for examples
|
255
|
+
#
|
256
|
+
# @since 0.2.6
|
128
257
|
def %(other)
|
129
258
|
check_divisibility(other)
|
130
259
|
|
@@ -132,28 +261,63 @@ class VectorNumber
|
|
132
261
|
new { _1 % other }
|
133
262
|
end
|
134
263
|
|
264
|
+
# @since 0.2.6
|
135
265
|
alias modulo %
|
136
266
|
|
137
|
-
# Return the quotient and modulus of dividing self by +other+.
|
267
|
+
# Return the quotient and modulus of dividing self by a real +other+.
|
138
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
|
+
#
|
139
284
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
140
285
|
# @return [Array(VectorNumber, VectorNumber)]
|
141
286
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
142
287
|
# @raise [ZeroDivisionError] if +other+ is zero
|
143
|
-
#
|
144
|
-
# @
|
288
|
+
#
|
289
|
+
# @since 0.2.6
|
145
290
|
def divmod(other)
|
146
291
|
[div(other), modulo(other)]
|
147
292
|
end
|
148
293
|
|
149
|
-
# 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
|
+
#
|
150
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
|
+
#
|
151
315
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
152
316
|
# @return [VectorNumber]
|
153
317
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
154
318
|
# @raise [ZeroDivisionError] if +other+ is zero
|
155
|
-
#
|
156
|
-
# @
|
319
|
+
#
|
320
|
+
# @since 0.2.6
|
157
321
|
def remainder(other)
|
158
322
|
check_divisibility(other)
|
159
323
|
|
@@ -163,8 +327,18 @@ class VectorNumber
|
|
163
327
|
|
164
328
|
private
|
165
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
|
166
338
|
def check_divisibility(other)
|
167
|
-
|
339
|
+
unless real_number?(other)
|
340
|
+
raise RangeError, "can't divide #{self} by #{other.inspect}", caller
|
341
|
+
end
|
168
342
|
raise ZeroDivisionError, "divided by 0", caller if other.zero?
|
169
343
|
end
|
170
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]
|