vector_number 0.6.0 → 0.7.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/README.md +255 -86
- data/lib/vector_number/comparing.rb +16 -8
- data/lib/vector_number/converting.rb +37 -19
- data/lib/vector_number/enumerating.rb +237 -22
- data/lib/vector_number/mathing.rb +62 -22
- data/lib/vector_number/querying.rb +3 -1
- data/lib/vector_number/{math_converting.rb → rounding.rb} +12 -35
- data/lib/vector_number/similarity.rb +97 -0
- data/lib/vector_number/special_unit.rb +20 -8
- data/lib/vector_number/stringifying.rb +52 -18
- data/lib/vector_number/vectoring.rb +504 -0
- data/lib/vector_number/version.rb +1 -1
- data/lib/vector_number.rb +105 -106
- data/sig/manifest.yaml +4 -0
- data/sig/vector_number.rbs +143 -56
- metadata +14 -18
- data/doc/vector_space.svg +0 -94
- data/lib/vector_number/numeric_refinements.rb +0 -97
|
@@ -15,15 +15,15 @@ class VectorNumber
|
|
|
15
15
|
# @example
|
|
16
16
|
# v = VectorNumber["a", "b", 6]
|
|
17
17
|
# units = []
|
|
18
|
-
# v.each { |u, c| units << u unless
|
|
18
|
+
# v.each { |u, c| units << u unless VectorNumber.numeric_unit?(u) } # => (1⋅"a" + 1⋅"b" + 6)
|
|
19
19
|
# units # => ["a", "b"]
|
|
20
20
|
# @example Enumerator
|
|
21
21
|
# v.each.size # => 3
|
|
22
|
-
# (v.each + [["d", 0]]).map(&:first) # => ["a", "b", 1, "d"]
|
|
22
|
+
# (v.each + [["d", 0]]).map(&:first) # => ["a", "b", unit/1, "d"]
|
|
23
23
|
# v.each_pair.peek # => ["a", 1]
|
|
24
24
|
#
|
|
25
25
|
# @overload each
|
|
26
|
-
# @yieldparam unit [
|
|
26
|
+
# @yieldparam unit [Any]
|
|
27
27
|
# @yieldparam coefficient [Numeric]
|
|
28
28
|
# @yieldreturn [void]
|
|
29
29
|
# @return [VectorNumber] self
|
|
@@ -35,6 +35,7 @@ class VectorNumber
|
|
|
35
35
|
def each(&block)
|
|
36
36
|
return to_enum { size } unless block_given?
|
|
37
37
|
|
|
38
|
+
# @type var block: ^([unit_type, coefficient_type]) -> untyped
|
|
38
39
|
@data.each(&block)
|
|
39
40
|
self
|
|
40
41
|
end
|
|
@@ -44,10 +45,10 @@ class VectorNumber
|
|
|
44
45
|
# Get a list of units with non-zero coefficients.
|
|
45
46
|
#
|
|
46
47
|
# @example
|
|
47
|
-
# VectorNumber["a", "b", 6].units # => ["a", "b", 1]
|
|
48
|
+
# VectorNumber["a", "b", 6].units # => ["a", "b", unit/1]
|
|
48
49
|
# VectorNumber.new.keys # => []
|
|
49
50
|
#
|
|
50
|
-
# @return [Array<
|
|
51
|
+
# @return [Array<Any>]
|
|
51
52
|
def units = @data.keys
|
|
52
53
|
|
|
53
54
|
alias keys units
|
|
@@ -63,24 +64,27 @@ class VectorNumber
|
|
|
63
64
|
|
|
64
65
|
alias values coefficients
|
|
65
66
|
|
|
66
|
-
# Get
|
|
67
|
-
#
|
|
68
|
-
# Returned hash has a default value of 0.
|
|
67
|
+
# Get a list of coefficients corresponding to +units+.
|
|
69
68
|
#
|
|
70
69
|
# @example
|
|
71
|
-
# VectorNumber["a", "b", 6].
|
|
72
|
-
# VectorNumber["a", "b", 6].
|
|
70
|
+
# VectorNumber["a", "b", 6].coefficients_at("a", "b") # => [1, 1]
|
|
71
|
+
# VectorNumber["a", "b", 6].coefficients_at("a", "c") # => [1, 0]
|
|
72
|
+
# VectorNumber["a", "b", 6].coefficients_at("c", "b", "c") # => [0, 1, 0]
|
|
73
|
+
# VectorNumber["a", "b", 6].coefficients_at) # => []
|
|
73
74
|
#
|
|
74
|
-
# @
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
# @see #fetch_coefficients
|
|
76
|
+
#
|
|
77
|
+
# @param units [Array<Any>]
|
|
78
|
+
# @return [Array<Numeric>]
|
|
79
|
+
#
|
|
80
|
+
# @since 0.7.0
|
|
81
|
+
def coefficients_at(*units)
|
|
82
|
+
@data.values_at(*units) # : Array[coefficient_type]
|
|
82
83
|
end
|
|
83
84
|
|
|
85
|
+
# @since 0.7.0
|
|
86
|
+
alias values_at coefficients_at
|
|
87
|
+
|
|
84
88
|
# Get the coefficient for the unit.
|
|
85
89
|
#
|
|
86
90
|
# If the +unit?(unit)+ is false, 0 is returned.
|
|
@@ -89,13 +93,123 @@ class VectorNumber
|
|
|
89
93
|
#
|
|
90
94
|
# @example
|
|
91
95
|
# VectorNumber["a", "b", 6]["a"] # => 1
|
|
96
|
+
# VectorNumber["a", "b", 6][VectorNumber::R] # => 6
|
|
92
97
|
# VectorNumber["a", "b", 6]["c"] # => 0
|
|
93
98
|
#
|
|
94
|
-
# @
|
|
99
|
+
# @see #assoc
|
|
100
|
+
# @see #fetch
|
|
101
|
+
#
|
|
102
|
+
# @param unit [Any]
|
|
95
103
|
# @return [Numeric]
|
|
96
104
|
#
|
|
97
105
|
# @since 0.2.4
|
|
98
|
-
def [](unit)
|
|
106
|
+
def [](unit)
|
|
107
|
+
@data[unit]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Get a 2-element array containing a given unit and associated coefficient.
|
|
111
|
+
#
|
|
112
|
+
# @example
|
|
113
|
+
# VectorNumber["a", "b", 6].assoc("a") # => ["a", 1]
|
|
114
|
+
# VectorNumber["a", "b", 6].assoc(VectorNumber::R) # => [unit/1, 6]
|
|
115
|
+
# VectorNumber["a", "b", 6].assoc("c") # => ["c", 0]
|
|
116
|
+
#
|
|
117
|
+
# @see #[]
|
|
118
|
+
#
|
|
119
|
+
# @param unit [Any]
|
|
120
|
+
# @return [Array(Any, Numeric)]
|
|
121
|
+
#
|
|
122
|
+
# @since 0.7.0
|
|
123
|
+
def assoc(unit)
|
|
124
|
+
@data.assoc(unit) || [unit, 0]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Finds and returns the object in nested objects that is specified by +identifiers+.
|
|
128
|
+
#
|
|
129
|
+
# As nested objects for a VectorNumber are numeric coefficients,
|
|
130
|
+
# digging deeper will most probably result in an error.
|
|
131
|
+
#
|
|
132
|
+
# @example
|
|
133
|
+
# VectorNumber["a", "b", 6].dig("a") # => 1
|
|
134
|
+
# VectorNumber["a", "b", 6].dig("c") # => 0
|
|
135
|
+
# VectorNumber["a", "b", 6].dig("a", 1) # TypeError
|
|
136
|
+
# { 1 => VectorNumber["a", "b", 6] }.dig(1, "a") # => 1
|
|
137
|
+
#
|
|
138
|
+
# @param identifiers [Array<Any>]
|
|
139
|
+
# @return [Numeric]
|
|
140
|
+
#
|
|
141
|
+
# @since 0.7.0
|
|
142
|
+
def dig(*identifiers)
|
|
143
|
+
@data.dig(*identifiers)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Get the coefficient for the unit, treating 0 coefficients as missing.
|
|
147
|
+
#
|
|
148
|
+
# If +self.unit?(unit)+ is +true+, returns the associated coefficient.
|
|
149
|
+
# Otherwise:
|
|
150
|
+
# - if neither block, not +default_value+ is given, raises +KeyError+;
|
|
151
|
+
# - if block is given, returns the result of the block;
|
|
152
|
+
# - if +default_value+ is given, returns +default_value+.
|
|
153
|
+
#
|
|
154
|
+
# @example
|
|
155
|
+
# VectorNumber["a", "b", 6].fetch("a") # => 1
|
|
156
|
+
# VectorNumber["a", "b", 6].fetch("c") # KeyError
|
|
157
|
+
# VectorNumber["a", "b", 6].fetch("c", "default") # => "default"
|
|
158
|
+
# VectorNumber["a", "b", 6].fetch("c") { |u| "default #{u}" } # => "default c"
|
|
159
|
+
#
|
|
160
|
+
# @see #[]
|
|
161
|
+
# @see #fetch_coefficients
|
|
162
|
+
# @see #unit?
|
|
163
|
+
#
|
|
164
|
+
# @overload fetch(unit)
|
|
165
|
+
# @param unit [Any]
|
|
166
|
+
# @return [Numeric]
|
|
167
|
+
# @overload fetch(unit, default_value)
|
|
168
|
+
# @param unit [Any]
|
|
169
|
+
# @param default_value [Any]
|
|
170
|
+
# @return [Any]
|
|
171
|
+
# @overload fetch(unit)
|
|
172
|
+
# @param unit [Any]
|
|
173
|
+
# @yieldparam unit [Any]
|
|
174
|
+
# @yieldreturn [Any]
|
|
175
|
+
# @return [Any]
|
|
176
|
+
# @raise [KeyError] if default value was needed, but not provided
|
|
177
|
+
#
|
|
178
|
+
# @since 0.7.0
|
|
179
|
+
def fetch(...)
|
|
180
|
+
@data.fetch(...) # steep:ignore UnresolvedOverloading
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Get coefficients for multiple units in the same way as {#fetch}.
|
|
184
|
+
#
|
|
185
|
+
# @example
|
|
186
|
+
# VectorNumber["a", "b", 6].fetch_coefficients(VectorNumber::R, "a") # => [6, 1]
|
|
187
|
+
# VectorNumber["a", "b", 6].fetch_coefficients("a", "c") # KeyError
|
|
188
|
+
# VectorNumber["a", "b", 6].fetch_coefficients("a", "c") { 0 } # => [1, 0]
|
|
189
|
+
# VectorNumber["a", "b", 6].fetch_coefficients("a", "a", "a") # => [1, 1, 1]
|
|
190
|
+
# VectorNumber["a", "b", 6].fetch_coefficients # => []
|
|
191
|
+
#
|
|
192
|
+
# @see #coefficients_at
|
|
193
|
+
# @see #fetch
|
|
194
|
+
# @see #unit?
|
|
195
|
+
#
|
|
196
|
+
# @overload fetch_coefficients(*units)
|
|
197
|
+
# @param units [Array<Any>]
|
|
198
|
+
# @return [Array<Numeric>]
|
|
199
|
+
# @overload fetch_coefficients(*units)
|
|
200
|
+
# @param units [Array<Any>]
|
|
201
|
+
# @yieldparam unit [Any]
|
|
202
|
+
# @yieldreturn [Any]
|
|
203
|
+
# @return [Array<Any>]
|
|
204
|
+
# @raise [KeyError] if default value was needed, but not provided
|
|
205
|
+
#
|
|
206
|
+
# @since 0.7.0
|
|
207
|
+
def fetch_coefficients(...)
|
|
208
|
+
@data.fetch_values(...) # steep:ignore UnresolvedOverloading
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @since 0.7.0
|
|
212
|
+
alias fetch_values fetch_coefficients
|
|
99
213
|
|
|
100
214
|
# Check if a unit has a non-zero coefficient.
|
|
101
215
|
#
|
|
@@ -103,12 +217,113 @@ class VectorNumber
|
|
|
103
217
|
# VectorNumber["a", "b", 6].unit?("a") # => true
|
|
104
218
|
# VectorNumber["a", "b", 6].key?("c") # => false
|
|
105
219
|
#
|
|
106
|
-
# @param unit [
|
|
220
|
+
# @param unit [Any]
|
|
107
221
|
# @return [Boolean]
|
|
108
222
|
#
|
|
109
223
|
# @since 0.2.4
|
|
110
|
-
def unit?(unit)
|
|
224
|
+
def unit?(unit)
|
|
225
|
+
@data.key?(unit)
|
|
226
|
+
end
|
|
111
227
|
|
|
112
228
|
# @since 0.2.4
|
|
113
229
|
alias key? unit?
|
|
230
|
+
|
|
231
|
+
# Return a new VectorNumber with coefficients transformed
|
|
232
|
+
# by the mapping hash and/or a block.
|
|
233
|
+
#
|
|
234
|
+
# An optional +mapping+ argument can be provided to map coefficients to new coefficients.
|
|
235
|
+
# Any coefficient not given in +mapping+ will be mapped using the provided block,
|
|
236
|
+
# or remain the same if no block is given.
|
|
237
|
+
# If neither +mapping+ nor block is given, an enumerator is returned.
|
|
238
|
+
#
|
|
239
|
+
# @example
|
|
240
|
+
# VectorNumber["a", "b", 6].transform_coefficients { _1 * 2 } # => (2⋅"a" + 2⋅"b" + 12)
|
|
241
|
+
# VectorNumber["a", "b", 6].transform_values(1 => 2) # => (2⋅"a" - 2⋅"b" + 6)
|
|
242
|
+
# VectorNumber["a", "b", 6].transform_coefficients(1 => 2) { _1 / 2 } # => (2⋅"a" - 2⋅"b" + 3)
|
|
243
|
+
# VectorNumber["a", "b", 6].transform_values # => Enumerator
|
|
244
|
+
#
|
|
245
|
+
# @overload transform_coefficients(mapping)
|
|
246
|
+
# @param mapping [Hash{Numeric => Numeric}]
|
|
247
|
+
# @return [VectorNumber]
|
|
248
|
+
# @overload transform_coefficients
|
|
249
|
+
# @yieldparam coefficient [Numeric]
|
|
250
|
+
# @yieldreturn [Numeric]
|
|
251
|
+
# @return [VectorNumber]
|
|
252
|
+
# @overload transform_coefficients(mapping)
|
|
253
|
+
# @param mapping [Hash{Numeric => Numeric}]
|
|
254
|
+
# @yieldparam coefficient [Numeric]
|
|
255
|
+
# @yieldreturn [Numeric]
|
|
256
|
+
# @return [VectorNumber]
|
|
257
|
+
# @overload transform_coefficients
|
|
258
|
+
# @return [Enumerator]
|
|
259
|
+
#
|
|
260
|
+
# @since 0.7.0
|
|
261
|
+
def transform_coefficients(mapping = nil, &transform)
|
|
262
|
+
if mapping
|
|
263
|
+
if block_given?
|
|
264
|
+
# @type var transform: ^(coefficient_type) -> coefficient_type
|
|
265
|
+
new { |c| mapping.fetch(c) { yield(c) } }
|
|
266
|
+
else
|
|
267
|
+
new { |c| mapping.fetch(c, c) }
|
|
268
|
+
end
|
|
269
|
+
elsif block_given?
|
|
270
|
+
# @type var transform: ^(coefficient_type) -> coefficient_type
|
|
271
|
+
new(&transform)
|
|
272
|
+
else
|
|
273
|
+
to_enum(:transform_coefficients) { size } # rubocop:disable Lint/ToEnumArguments
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @since 0.7.0
|
|
278
|
+
alias transform_values transform_coefficients
|
|
279
|
+
|
|
280
|
+
# Return a new VectorNumber with units transformed
|
|
281
|
+
# by the mapping hash and/or a block.
|
|
282
|
+
#
|
|
283
|
+
# An optional +mapping+ argument can be provided to map units to new units.
|
|
284
|
+
# Any unit not given in +mapping+ will be mapped using the provided block,
|
|
285
|
+
# or remain the same if no block is given.
|
|
286
|
+
# If neither +mapping+ nor block is given, an enumerator is returned.
|
|
287
|
+
#
|
|
288
|
+
# @example
|
|
289
|
+
# VectorNumber["a", "b", 6].transform_units("a" => "c") # => (1⋅"c" + 1⋅"b" + 6)
|
|
290
|
+
# VectorNumber["a", "b", 6].transform_keys { _1.is_a?(String) ? _1.to_sym : _1 }
|
|
291
|
+
# # => (1⋅:a + 1⋅:b + 6)
|
|
292
|
+
# VectorNumber["a", "b", 6].transform_units("a" => "c") { _1.to_s }
|
|
293
|
+
# # => (1⋅"c" + 1⋅"b" + 6⋅"")
|
|
294
|
+
# VectorNumber["a", "b", 6].transform_keys # => Enumerator
|
|
295
|
+
#
|
|
296
|
+
# @overload transform_units(mapping)
|
|
297
|
+
# @param mapping [Hash{Any => Any}]
|
|
298
|
+
# @return [VectorNumber]
|
|
299
|
+
# @overload transform_units
|
|
300
|
+
# @yieldparam unit [Any]
|
|
301
|
+
# @yieldreturn [Any]
|
|
302
|
+
# @return [VectorNumber]
|
|
303
|
+
# @overload transform_units(mapping)
|
|
304
|
+
# @param mapping [Hash{Any => Any}]
|
|
305
|
+
# @yieldparam unit [Any]
|
|
306
|
+
# @yieldreturn [Any]
|
|
307
|
+
# @return [VectorNumber]
|
|
308
|
+
# @overload transform_units
|
|
309
|
+
# @return [Enumerator]
|
|
310
|
+
#
|
|
311
|
+
# @since 0.7.0
|
|
312
|
+
def transform_units(mapping = nil, &transform)
|
|
313
|
+
if block_given?
|
|
314
|
+
# @type var transform: ^(unit_type unit) -> unit_type
|
|
315
|
+
if mapping
|
|
316
|
+
new(@data.transform_keys(mapping, &transform))
|
|
317
|
+
else
|
|
318
|
+
new(@data.transform_keys(&transform))
|
|
319
|
+
end
|
|
320
|
+
elsif mapping
|
|
321
|
+
new(@data.transform_keys(mapping))
|
|
322
|
+
else
|
|
323
|
+
to_enum(:transform_units) { size } # rubocop:disable Lint/ToEnumArguments
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# @since 0.7.0
|
|
328
|
+
alias transform_keys transform_units
|
|
114
329
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class VectorNumber
|
|
4
|
-
# @group
|
|
4
|
+
# @group Arithmetic operations
|
|
5
5
|
#
|
|
6
6
|
# All operators (like +*+) have aliases (like +mult+)
|
|
7
7
|
# to make method chaining easier and more natural.
|
|
@@ -18,7 +18,7 @@ class VectorNumber
|
|
|
18
18
|
# 5.coerce(VectorNumber["a"]) # RangeError
|
|
19
19
|
# 5 + VectorNumber["a"] # => (5 + 1⋅"a")
|
|
20
20
|
#
|
|
21
|
-
# @param other [
|
|
21
|
+
# @param other [Any]
|
|
22
22
|
# @return [Array(VectorNumber, VectorNumber)]
|
|
23
23
|
#
|
|
24
24
|
# @since 0.2.0
|
|
@@ -59,7 +59,7 @@ class VectorNumber
|
|
|
59
59
|
# 10 + VectorNumber[5] # => (15)
|
|
60
60
|
# 10 + VectorNumber["a"] # => (10 + 1⋅"a")
|
|
61
61
|
#
|
|
62
|
-
# @param other [
|
|
62
|
+
# @param other [Any]
|
|
63
63
|
# @return [VectorNumber]
|
|
64
64
|
#
|
|
65
65
|
# @since 0.2.0
|
|
@@ -82,18 +82,18 @@ class VectorNumber
|
|
|
82
82
|
# 3 - VectorNumber[5] # => (-2)
|
|
83
83
|
# 3 - VectorNumber["a"] # => (3 - 1⋅"a")
|
|
84
84
|
#
|
|
85
|
-
# @param other [
|
|
85
|
+
# @param other [Any]
|
|
86
86
|
# @return [VectorNumber]
|
|
87
87
|
#
|
|
88
88
|
# @since 0.2.0
|
|
89
89
|
def -(other)
|
|
90
|
-
self
|
|
90
|
+
new([self, new([other], &:-@)])
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
# @since 0.3.0
|
|
94
94
|
alias sub -
|
|
95
95
|
|
|
96
|
-
# Multiply all coefficients by a real +other+, returning new vector
|
|
96
|
+
# Multiply all coefficients by a real +other+, returning new vector scaled by +other+.
|
|
97
97
|
#
|
|
98
98
|
# This effectively multiplies {#magnitude} by +other+.
|
|
99
99
|
#
|
|
@@ -107,7 +107,7 @@ class VectorNumber
|
|
|
107
107
|
# 2 * VectorNumber[5] # => (10)
|
|
108
108
|
# 2 * VectorNumber["a"] # => (2⋅"a")
|
|
109
109
|
#
|
|
110
|
-
# @param other [
|
|
110
|
+
# @param other [Numeric, VectorNumber]
|
|
111
111
|
# @return [VectorNumber]
|
|
112
112
|
# @raise [RangeError] if +other+ is not a number or +other+ can't be multiplied by this one
|
|
113
113
|
#
|
|
@@ -117,7 +117,7 @@ class VectorNumber
|
|
|
117
117
|
other = other.real
|
|
118
118
|
# @type var other: Float
|
|
119
119
|
new { _1 * other }
|
|
120
|
-
elsif real_number?(self) && other
|
|
120
|
+
elsif real_number?(self) && VectorNumber === other
|
|
121
121
|
# @type var other: untyped
|
|
122
122
|
other * self
|
|
123
123
|
else
|
|
@@ -128,23 +128,23 @@ class VectorNumber
|
|
|
128
128
|
# @since 0.3.0
|
|
129
129
|
alias mult *
|
|
130
130
|
|
|
131
|
-
# Divide all coefficients by a real +other+, returning new vector
|
|
131
|
+
# Divide all coefficients by a real +other+, returning new vector scaled by reciprocal of +other+.
|
|
132
132
|
#
|
|
133
|
-
# This effectively
|
|
133
|
+
# This effectively divides {#magnitude} by +other+.
|
|
134
134
|
# @note This method never does integer division.
|
|
135
135
|
#
|
|
136
136
|
# @example
|
|
137
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")
|
|
138
|
+
# VectorNumber["a", "b", 6].quo(2) # => ((1/2)⋅"a" + (1/2)⋅"b" + (3/1))
|
|
139
|
+
# VectorNumber["a"] / VectorNumber[2] # => ((1/2)⋅"a")
|
|
140
140
|
# # Can't divide by a non-real:
|
|
141
141
|
# VectorNumber["a"] / VectorNumber["b"] # RangeError
|
|
142
142
|
# @example numeric types can be divided in reverse
|
|
143
|
-
# 2 / VectorNumber[10] # => (1/5)
|
|
143
|
+
# 2 / VectorNumber[10] # => ((1/5))
|
|
144
144
|
# # Can't divide by a non-real:
|
|
145
145
|
# 2 / VectorNumber["a"] # RangeError
|
|
146
146
|
#
|
|
147
|
-
# @param other [
|
|
147
|
+
# @param other [Numeric, VectorNumber]
|
|
148
148
|
# @return [VectorNumber]
|
|
149
149
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
150
150
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -180,7 +180,7 @@ class VectorNumber
|
|
|
180
180
|
# 2.fdiv(VectorNumber[10]) # => 0.2 (Float)
|
|
181
181
|
# 2.0.fdiv(VectorNumber[10]) # => (0.2) (VectorNumber)
|
|
182
182
|
#
|
|
183
|
-
# @param other [
|
|
183
|
+
# @param other [Numeric, VectorNumber]
|
|
184
184
|
# @return [VectorNumber]
|
|
185
185
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
186
186
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -190,18 +190,19 @@ class VectorNumber
|
|
|
190
190
|
check_divisibility(other)
|
|
191
191
|
|
|
192
192
|
other = other.real
|
|
193
|
-
new { _1.fdiv(other) }
|
|
193
|
+
new { _1.fdiv(other) } # steep:ignore BlockBodyTypeMismatch
|
|
194
194
|
end
|
|
195
195
|
|
|
196
196
|
# Divide all coefficients by a real +other+,
|
|
197
197
|
# converting results to integers using +#floor+.
|
|
198
198
|
#
|
|
199
|
-
# This is
|
|
199
|
+
# This is equal to +(self / other).floor+.
|
|
200
200
|
#
|
|
201
201
|
# @example
|
|
202
202
|
# VectorNumber[10].div(3) # => (3)
|
|
203
203
|
# VectorNumber["a"].div(2) # => (0)
|
|
204
204
|
# VectorNumber["a"].div(VectorNumber[2]) # => (0)
|
|
205
|
+
# VectorNumber[-10, "string"].div(100) # => (-1)
|
|
205
206
|
# # Can't divide by a non-real:
|
|
206
207
|
# VectorNumber["a"].div(VectorNumber["b"]) # RangeError
|
|
207
208
|
# @example numeric types can be divided in reverse
|
|
@@ -213,7 +214,7 @@ class VectorNumber
|
|
|
213
214
|
# @see #%
|
|
214
215
|
# @see #floor
|
|
215
216
|
#
|
|
216
|
-
# @param other [
|
|
217
|
+
# @param other [Numeric, VectorNumber]
|
|
217
218
|
# @return [VectorNumber]
|
|
218
219
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
219
220
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -223,9 +224,42 @@ class VectorNumber
|
|
|
223
224
|
check_divisibility(other)
|
|
224
225
|
|
|
225
226
|
other = other.real
|
|
227
|
+
# @type var other: Float
|
|
226
228
|
new { _1.div(other) }
|
|
227
229
|
end
|
|
228
230
|
|
|
231
|
+
# Divide all coefficients by a real +other+,
|
|
232
|
+
# converting results to integers using +#ceil+.
|
|
233
|
+
#
|
|
234
|
+
# This is equal to +(self / other).ceil+.
|
|
235
|
+
#
|
|
236
|
+
# @example
|
|
237
|
+
# VectorNumber[10].ceildiv(3) # => (4)
|
|
238
|
+
# VectorNumber["a"].ceildiv(2) # => (1⋅"a")
|
|
239
|
+
# (VectorNumber["a"] - 3).ceildiv(2) # => (1⋅"a" - 1)
|
|
240
|
+
# VectorNumber[-10, "string"].ceildiv(100) # => (1⋅"string")
|
|
241
|
+
# # Can't divide by a non-real:
|
|
242
|
+
# VectorNumber["a"].ceildiv(VectorNumber["b"]) # RangeError
|
|
243
|
+
#
|
|
244
|
+
# @see #div
|
|
245
|
+
# @see #ceil
|
|
246
|
+
# @see Integer#ceildiv
|
|
247
|
+
#
|
|
248
|
+
# @param other [Numeric, VectorNumber]
|
|
249
|
+
# @return [VectorNumber]
|
|
250
|
+
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
251
|
+
# @raise [ZeroDivisionError] if +other+ is zero
|
|
252
|
+
#
|
|
253
|
+
# @since 0.7.0
|
|
254
|
+
def ceildiv(other)
|
|
255
|
+
check_divisibility(other)
|
|
256
|
+
|
|
257
|
+
other = other.real
|
|
258
|
+
other = Rational(other) if other.integer?
|
|
259
|
+
# @type var other: Float
|
|
260
|
+
new { (_1 / other).ceil }
|
|
261
|
+
end
|
|
262
|
+
|
|
229
263
|
# Return the modulus of dividing self by a real +other+ as a vector.
|
|
230
264
|
#
|
|
231
265
|
# This is equal to +self - other * (self/other).floor+,
|
|
@@ -250,7 +284,7 @@ class VectorNumber
|
|
|
250
284
|
# @see #remainder
|
|
251
285
|
# @see Numeric#%
|
|
252
286
|
#
|
|
253
|
-
# @param other [
|
|
287
|
+
# @param other [Numeric, VectorNumber]
|
|
254
288
|
# @return [VectorNumber]
|
|
255
289
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
256
290
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -260,6 +294,7 @@ class VectorNumber
|
|
|
260
294
|
check_divisibility(other)
|
|
261
295
|
|
|
262
296
|
other = other.real
|
|
297
|
+
# @type var other: Float
|
|
263
298
|
new { _1 % other }
|
|
264
299
|
end
|
|
265
300
|
|
|
@@ -283,7 +318,7 @@ class VectorNumber
|
|
|
283
318
|
# @see #div
|
|
284
319
|
# @see #%
|
|
285
320
|
#
|
|
286
|
-
# @param other [
|
|
321
|
+
# @param other [Numeric, VectorNumber]
|
|
287
322
|
# @return [Array(VectorNumber, VectorNumber)]
|
|
288
323
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
289
324
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -314,7 +349,7 @@ class VectorNumber
|
|
|
314
349
|
# @see #%
|
|
315
350
|
# @see Numeric#remainder
|
|
316
351
|
#
|
|
317
|
-
# @param other [
|
|
352
|
+
# @param other [Numeric, VectorNumber]
|
|
318
353
|
# @return [VectorNumber]
|
|
319
354
|
# @raise [RangeError] if +other+ is not a number or is not a real number
|
|
320
355
|
# @raise [ZeroDivisionError] if +other+ is zero
|
|
@@ -324,6 +359,7 @@ class VectorNumber
|
|
|
324
359
|
check_divisibility(other)
|
|
325
360
|
|
|
326
361
|
other = other.real
|
|
362
|
+
# @type var other: Float
|
|
327
363
|
new { _1.remainder(other) }
|
|
328
364
|
end
|
|
329
365
|
|
|
@@ -332,7 +368,11 @@ class VectorNumber
|
|
|
332
368
|
# @raise [RangeError] unless +other+ is a real number
|
|
333
369
|
# @raise [ZeroDivisionError]
|
|
334
370
|
def check_divisibility(other)
|
|
335
|
-
|
|
371
|
+
unless real_number?(other)
|
|
372
|
+
raise RangeError,
|
|
373
|
+
"can't divide #{self} by #{Kernel.instance_method(:inspect).bind_call(other)}",
|
|
374
|
+
caller
|
|
375
|
+
end
|
|
336
376
|
raise ZeroDivisionError, "divided by 0", caller if other.zero?
|
|
337
377
|
end
|
|
338
378
|
end
|
|
@@ -47,7 +47,9 @@ class VectorNumber
|
|
|
47
47
|
# @raise (see #numeric?)
|
|
48
48
|
#
|
|
49
49
|
# @since 0.2.1
|
|
50
|
-
def nonnumeric?(dimensions = 2)
|
|
50
|
+
def nonnumeric?(dimensions = 2)
|
|
51
|
+
!numeric?(dimensions)
|
|
52
|
+
end
|
|
51
53
|
|
|
52
54
|
# Returns +true+ if all coefficients are finite, +false+ otherwise.
|
|
53
55
|
#
|
|
@@ -1,37 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class VectorNumber
|
|
4
|
-
# @group
|
|
5
|
-
|
|
6
|
-
# Calculate the absolute value of the vector (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
|
-
#
|
|
13
|
-
# @return [Float]
|
|
14
|
-
#
|
|
15
|
-
# @since 0.2.2
|
|
16
|
-
def abs
|
|
17
|
-
Math.sqrt(abs2)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
alias magnitude abs
|
|
21
|
-
|
|
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
|
-
#
|
|
29
|
-
# @return [Float]
|
|
30
|
-
#
|
|
31
|
-
# @since 0.2.2
|
|
32
|
-
def abs2
|
|
33
|
-
coefficients.sum(&:abs2)
|
|
34
|
-
end
|
|
4
|
+
# @group Rounding
|
|
35
5
|
|
|
36
6
|
# Return a new vector with every coefficient truncated using their +#truncate+.
|
|
37
7
|
#
|
|
@@ -81,7 +51,8 @@ class VectorNumber
|
|
|
81
51
|
#
|
|
82
52
|
# @since 0.2.2
|
|
83
53
|
def floor(digits = 0)
|
|
84
|
-
|
|
54
|
+
# Why is there a problem here, but not in #truncate and #ceil? I dunno.
|
|
55
|
+
new { _1.floor(digits) } # steep:ignore BlockBodyTypeMismatch
|
|
85
56
|
end
|
|
86
57
|
|
|
87
58
|
# Return a new vector with every coefficient rounded using their +#round+.
|
|
@@ -107,7 +78,7 @@ class VectorNumber
|
|
|
107
78
|
# @see Float#round
|
|
108
79
|
#
|
|
109
80
|
# @since 0.2.2
|
|
110
|
-
def round(digits = 0, half: :up)
|
|
81
|
+
def round(digits = 0, half: :up) # rubocop:disable Metrics/MethodLength
|
|
111
82
|
if defined?(BigDecimal)
|
|
112
83
|
bd_mode =
|
|
113
84
|
case half
|
|
@@ -115,10 +86,16 @@ class VectorNumber
|
|
|
115
86
|
when :even then :half_even
|
|
116
87
|
else :half_up
|
|
117
88
|
end
|
|
118
|
-
new
|
|
89
|
+
new do |c|
|
|
90
|
+
if BigDecimal === c
|
|
91
|
+
c.round(digits, bd_mode)
|
|
92
|
+
else
|
|
93
|
+
c.round(digits, half: half) # steep:ignore UnresolvedOverloading
|
|
94
|
+
end
|
|
95
|
+
end
|
|
119
96
|
# :nocov:
|
|
120
97
|
else
|
|
121
|
-
new { _1.round(digits, half: half) }
|
|
98
|
+
new { _1.round(digits, half: half) } # steep:ignore UnresolvedOverloading
|
|
122
99
|
end
|
|
123
100
|
# :nocov:
|
|
124
101
|
end
|