vector_number 0.4.2 → 0.5.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.
@@ -1,345 +1,338 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class VectorNumber
4
- # Methods for performing actual math.
4
+ # @group Mathematical operations
5
5
  #
6
6
  # All operators (like +*+) have aliases (like +mult+)
7
7
  # to make method chaining easier and more natural.
8
- module Mathing
9
- # The coerce method provides support for Ruby type coercion.
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
- #
21
- # @param other [Object]
22
- # @return [Array(VectorNumber, VectorNumber)]
23
- #
24
- # @since 0.2.0
25
- def coerce(other)
26
- case other
27
- when VectorNumber
28
- [other, self]
29
- else
30
- [new([other]), self]
31
- end
32
- end
33
-
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
- #
41
- # @return [VectorNumber]
42
- #
43
- # @since 0.2.0
44
- def -@
45
- new(&:-@)
46
- end
47
8
 
48
- # @since 0.3.0
49
- alias neg -@
50
-
51
- # Return new vector as a sum of this and +other+ value.
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
- #
62
- # @param other [Object]
63
- # @return [VectorNumber]
64
- #
65
- # @since 0.2.0
66
- def +(other)
67
- new([self, other])
9
+ # The coerce method provides support for Ruby type coercion.
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
+ #
21
+ # @param other [Object]
22
+ # @return [Array(VectorNumber, VectorNumber)]
23
+ #
24
+ # @since 0.2.0
25
+ def coerce(other)
26
+ case other
27
+ when VectorNumber
28
+ [other, self]
29
+ else
30
+ [new([other]), self]
68
31
  end
32
+ end
69
33
 
70
- # @since 0.3.0
71
- alias add +
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
+ #
41
+ # @return [VectorNumber]
42
+ #
43
+ # @since 0.2.0
44
+ def -@
45
+ new(&:-@)
46
+ end
72
47
 
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
- #
85
- # @param other [Object]
86
- # @return [VectorNumber]
87
- #
88
- # @since 0.2.0
89
- def -(other)
90
- self + new([other], &:-@)
91
- end
48
+ # @since 0.3.0
49
+ alias neg -@
92
50
 
93
- # @since 0.3.0
94
- alias sub -
51
+ # Return new vector as a sum of this and +other+ value.
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
+ #
62
+ # @param other [Object]
63
+ # @return [VectorNumber]
64
+ #
65
+ # @since 0.2.0
66
+ def +(other)
67
+ new([self, other])
68
+ end
95
69
 
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
- #
110
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
111
- # @return [VectorNumber]
112
- # @raise [RangeError] if +other+ is not a number or +other+ can't be multiplied by this one
113
- #
114
- # @since 0.2.1
115
- def *(other)
116
- if real_number?(other)
117
- other = other.real
118
- # @type var other: Float
119
- new { _1 * other }
120
- elsif real_number?(self) && other.is_a?(self.class)
121
- # @type var other: untyped
122
- other * self
123
- else
124
- raise RangeError, "can't multiply #{self} and #{other}"
125
- end
126
- end
70
+ # @since 0.3.0
71
+ alias add +
127
72
 
128
- # @since 0.3.0
129
- alias mult *
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
+ #
85
+ # @param other [Object]
86
+ # @return [VectorNumber]
87
+ #
88
+ # @since 0.2.0
89
+ def -(other)
90
+ self + new([other], &:-@)
91
+ end
130
92
 
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
- #
147
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
148
- # @return [VectorNumber]
149
- # @raise [RangeError] if +other+ is not a number or is not a real number
150
- # @raise [ZeroDivisionError] if +other+ is zero
151
- #
152
- # @since 0.2.1
153
- def /(other)
154
- check_divisibility(other)
93
+ # @since 0.3.0
94
+ alias sub -
155
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
+ #
110
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
111
+ # @return [VectorNumber]
112
+ # @raise [RangeError] if +other+ is not a number or +other+ can't be multiplied by this one
113
+ #
114
+ # @since 0.2.1
115
+ def *(other)
116
+ if real_number?(other)
156
117
  other = other.real
157
- # Prevent integer division, but without loss of accuracy.
158
- other = Rational(other) if other.integer?
159
118
  # @type var other: Float
160
- new { _1 / other }
119
+ new { _1 * other }
120
+ elsif real_number?(self) && other.is_a?(self.class)
121
+ # @type var other: untyped
122
+ other * self
123
+ else
124
+ raise RangeError, "can't multiply #{self} and #{other}"
161
125
  end
126
+ end
162
127
 
163
- # @since 0.2.6
164
- alias quo /
165
- # to fix syntax highlighting: /
128
+ # @since 0.3.0
129
+ alias mult *
166
130
 
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
- #
183
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
184
- # @return [VectorNumber]
185
- # @raise [RangeError] if +other+ is not a number or is not a real number
186
- # @raise [ZeroDivisionError] if +other+ is zero
187
- #
188
- # @since 0.2.1
189
- def fdiv(other)
190
- check_divisibility(other)
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
+ #
147
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
148
+ # @return [VectorNumber]
149
+ # @raise [RangeError] if +other+ is not a number or is not a real number
150
+ # @raise [ZeroDivisionError] if +other+ is zero
151
+ #
152
+ # @since 0.2.1
153
+ def /(other)
154
+ check_divisibility(other)
191
155
 
192
- other = other.real
193
- new { _1.fdiv(other) }
194
- end
156
+ other = other.real
157
+ # Prevent integer division, but without loss of accuracy.
158
+ other = Rational(other) if other.integer?
159
+ # @type var other: Float
160
+ new { _1 / other }
161
+ end
195
162
 
196
- # Divide all coefficients by a real +other+, rounding results with +#floor+.
197
- #
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
- #
214
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
215
- # @return [VectorNumber]
216
- # @raise [RangeError] if +other+ is not a number or is not a real number
217
- # @raise [ZeroDivisionError] if +other+ is zero
218
- #
219
- # @since 0.2.6
220
- def div(other)
221
- check_divisibility(other)
163
+ # @since 0.2.6
164
+ alias quo /
165
+ # to fix syntax highlighting: /
222
166
 
223
- other = other.real
224
- new { _1.div(other) }
225
- end
167
+ # Divide all coefficients by a real +other+ using +fdiv+,
168
+ # returning new vector with decimal 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
+ #
183
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
184
+ # @return [VectorNumber]
185
+ # @raise [RangeError] if +other+ is not a number or is not a real number
186
+ # @raise [ZeroDivisionError] if +other+ is zero
187
+ #
188
+ # @since 0.2.1
189
+ def fdiv(other)
190
+ check_divisibility(other)
226
191
 
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
- #
251
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
252
- # @return [VectorNumber]
253
- # @raise [RangeError] if +other+ is not a number or is not a real number
254
- # @raise [ZeroDivisionError] if +other+ is zero
255
- #
256
- # @since 0.2.6
257
- def %(other)
258
- check_divisibility(other)
192
+ other = other.real
193
+ new { _1.fdiv(other) }
194
+ end
259
195
 
260
- other = other.real
261
- new { _1 % other }
262
- end
196
+ # Divide all coefficients by a real +other+,
197
+ # converting results to integers using +#floor+.
198
+ #
199
+ # This is requal to +(self / other).floor+.
200
+ #
201
+ # @example
202
+ # VectorNumber[10].div(3) # => (3)
203
+ # VectorNumber["a"].div(2) # => (0⋅'a')
204
+ # VectorNumber["a"].div(VectorNumber[2]) # => (0⋅'a')
205
+ # # Can't divide by a non-real:
206
+ # VectorNumber["a"].div(VectorNumber["b"]) # RangeError
207
+ # @example numeric types can be divided in reverse
208
+ # 2.div(VectorNumber[10]) # => (0)
209
+ # # Can't divide by a non-real:
210
+ # 2.div(VectorNumber["a"]) # RangeError
211
+ #
212
+ # @see #divmod
213
+ # @see #%
214
+ # @see #floor
215
+ #
216
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
217
+ # @return [VectorNumber]
218
+ # @raise [RangeError] if +other+ is not a number or is not a real number
219
+ # @raise [ZeroDivisionError] if +other+ is zero
220
+ #
221
+ # @since 0.2.6
222
+ def div(other)
223
+ check_divisibility(other)
263
224
 
264
- # @since 0.2.6
265
- alias modulo %
225
+ other = other.real
226
+ new { _1.div(other) }
227
+ end
266
228
 
267
- # Return the quotient and modulus of dividing self by a real +other+.
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
- #
284
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
285
- # @return [Array(VectorNumber, VectorNumber)]
286
- # @raise [RangeError] if +other+ is not a number or is not a real number
287
- # @raise [ZeroDivisionError] if +other+ is zero
288
- #
289
- # @since 0.2.6
290
- def divmod(other)
291
- [div(other), modulo(other)]
292
- end
229
+ # Return the modulus of dividing self by a real +other+ as a vector.
230
+ #
231
+ # This is equal to +self - other * (self/other).floor+,
232
+ # or, alternatively, +self - other * self.div(other)+.
233
+ #
234
+ # @example
235
+ # VectorNumber[10] % 3 # => (1)
236
+ # VectorNumber["a", "b", 6].modulo(2) # => (1⋅'a' + 1⋅'b')
237
+ # -VectorNumber["a"] % VectorNumber[2] # => (1⋅'a')
238
+ # # Can't divide by a non-real:
239
+ # VectorNumber["a"] % VectorNumber["b"] # RangeError
240
+ # @example numeric types can be divided in reverse
241
+ # 3 % VectorNumber[10] # => (3)
242
+ # # Can't divide by a non-real:
243
+ # 3 % VectorNumber["a"] # RangeError
244
+ # @example compare to #remainder
245
+ # VectorNumber[-5] % 3 # => (1)
246
+ # VectorNumber[-5].remainder(3) # => (-2)
247
+ #
248
+ # @see #divmod
249
+ # @see #div
250
+ # @see #remainder
251
+ # @see Numeric#%
252
+ #
253
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
254
+ # @return [VectorNumber]
255
+ # @raise [RangeError] if +other+ is not a number or is not a real number
256
+ # @raise [ZeroDivisionError] if +other+ is zero
257
+ #
258
+ # @since 0.2.6
259
+ def %(other)
260
+ check_divisibility(other)
293
261
 
294
- # Return the remainder of dividing self by a real +other+ as a vector.
295
- #
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
- #
315
- # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
316
- # @return [VectorNumber]
317
- # @raise [RangeError] if +other+ is not a number or is not a real number
318
- # @raise [ZeroDivisionError] if +other+ is zero
319
- #
320
- # @since 0.2.6
321
- def remainder(other)
322
- check_divisibility(other)
262
+ other = other.real
263
+ new { _1 % other }
264
+ end
323
265
 
324
- other = other.real
325
- new { _1.remainder(other) }
326
- end
266
+ # @since 0.2.6
267
+ alias modulo %
327
268
 
328
- private
269
+ # Return the quotient and modulus of dividing self by a real +other+.
270
+ # There is no performance benefit compared to calling {#div} and {#%} separately.
271
+ #
272
+ # @example
273
+ # VectorNumber[10].divmod(3) # => [(3), (1)]
274
+ # VectorNumber["a"].divmod(2) # => [(0⋅'a'), (1⋅'a')]
275
+ # VectorNumber["a"].divmod(VectorNumber[2]) # => [(0⋅'a'), (1⋅'a')]
276
+ # # Can't divide by a non-real:
277
+ # VectorNumber["a"].divmod(VectorNumber["b"]) # RangeError
278
+ # @example numeric types can be divided in reverse
279
+ # 3.divmod(VectorNumber[10]) # => [(0), (3)]
280
+ # # Can't divide by a non-real:
281
+ # 3.divmod(VectorNumber["a"]) # RangeError
282
+ #
283
+ # @see #div
284
+ # @see #%
285
+ #
286
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
287
+ # @return [Array(VectorNumber, VectorNumber)]
288
+ # @raise [RangeError] if +other+ is not a number or is not a real number
289
+ # @raise [ZeroDivisionError] if +other+ is zero
290
+ #
291
+ # @since 0.2.6
292
+ def divmod(other)
293
+ [div(other), modulo(other)]
294
+ end
329
295
 
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
338
- def check_divisibility(other)
339
- unless real_number?(other)
340
- raise RangeError, "can't divide #{self} by #{other.inspect}", caller
341
- end
342
- raise ZeroDivisionError, "divided by 0", caller if other.zero?
343
- end
296
+ # Return the remainder of dividing self by a real +other+ as a vector.
297
+ #
298
+ # This is equal to +self - other * (self/other).truncate+.
299
+ #
300
+ # @example
301
+ # VectorNumber[10].remainder(3) # => (1)
302
+ # VectorNumber["a"].remainder(2) # => (1⋅'a')
303
+ # -VectorNumber["a"].remainder(VectorNumber[2]) # => (-1⋅'a')
304
+ # # Can't divide by a non-real:
305
+ # VectorNumber["a"].remainder(VectorNumber["b"]) # RangeError
306
+ # @example numeric types can be divided in reverse
307
+ # 3.remainder(VectorNumber[10]) # => (3)
308
+ # # Can't divide by a non-real:
309
+ # 3.remainder(VectorNumber["a"]) # RangeError
310
+ # @example compare to #%
311
+ # VectorNumber[-5] % 3 # => (1)
312
+ # VectorNumber[-5].remainder(3) # => (-2)
313
+ #
314
+ # @see #%
315
+ # @see Numeric#remainder
316
+ #
317
+ # @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
318
+ # @return [VectorNumber]
319
+ # @raise [RangeError] if +other+ is not a number or is not a real number
320
+ # @raise [ZeroDivisionError] if +other+ is zero
321
+ #
322
+ # @since 0.2.6
323
+ def remainder(other)
324
+ check_divisibility(other)
325
+
326
+ other = other.real
327
+ new { _1.remainder(other) }
328
+ end
329
+
330
+ private
331
+
332
+ # @raise [RangeError] unless +other+ is a real number
333
+ # @raise [ZeroDivisionError]
334
+ def check_divisibility(other)
335
+ raise RangeError, "can't divide #{self} by #{other.inspect}", caller unless real_number?(other)
336
+ raise ZeroDivisionError, "divided by 0", caller if other.zero?
344
337
  end
345
338
  end