philiprehberger-interval 0.4.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +14 -0
- data/lib/philiprehberger/interval/range.rb +36 -0
- data/lib/philiprehberger/interval/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2cc42dea01af0c3d94ccd1473f57540edadacd0da1763cfb29cfcceaca105900
|
|
4
|
+
data.tar.gz: 0455405d87eda7c2a20b913bcd9d26477247dfd69a99adc2f00be29c340aaf5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd54e350ee506ed02827ad6c23f4eec3d492eadc9b68cee0d4a4608773e1611a799ceb4ca2e56409ba0e27145852fe5c6d8adb168875f93c3818f25e82ef4c55
|
|
7
|
+
data.tar.gz: 626544c2d371d2c1de5a1a1b4f4ac7f181af2b8397ae85168e617b7d77a8445f0f3f6d7e66a01fc81586bce8f144692410d8c0a677d86cffbf44b323bfc4498a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-04-16
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Range#sample(n = nil)` — return a random Float within the interval, or an array of n random Floats; respects open/closed boundaries via rejection sampling; raises on empty intervals; returns start for point intervals
|
|
14
|
+
|
|
10
15
|
## [0.4.0] - 2026-04-15
|
|
11
16
|
|
|
12
17
|
### Added
|
data/README.md
CHANGED
|
@@ -84,6 +84,19 @@ Philiprehberger::Interval.gaps(intervals)
|
|
|
84
84
|
# => [[7, 10]]
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
### Sampling Random Values
|
|
88
|
+
|
|
89
|
+
Return one or more random Floats from within an interval. Open boundaries are respected via rejection sampling:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
interval = Philiprehberger::Interval.new(1.0, 5.0)
|
|
93
|
+
interval.sample # => 3.247... (single Float)
|
|
94
|
+
interval.sample(3) # => [1.823..., 4.501..., 2.964...]
|
|
95
|
+
|
|
96
|
+
open = Philiprehberger::Interval.new(1.0, 5.0, type: :open)
|
|
97
|
+
open.sample # => always strictly between 1.0 and 5.0
|
|
98
|
+
```
|
|
99
|
+
|
|
87
100
|
### Finding a Common Intersection
|
|
88
101
|
|
|
89
102
|
Compute the overlap shared by every interval, or `nil` if any pair is disjoint:
|
|
@@ -123,6 +136,7 @@ shift.include?(Time.new(2026, 1, 1, 12)) # => true
|
|
|
123
136
|
| `#scale(factor, anchor:)` | Scale width around anchor (`:center`, `:left`, `:right`) |
|
|
124
137
|
| `#split(n)` | Split into n equal sub-intervals |
|
|
125
138
|
| `#clamp(value)` | Clamp value to interval bounds |
|
|
139
|
+
| `#sample(n = nil)` | Return a random Float, or array of n Floats, within the interval (respects boundaries) |
|
|
126
140
|
| `.merge(intervals)` | Merge overlapping intervals into non-overlapping set |
|
|
127
141
|
| `.gaps(intervals)` | Find gaps between a set of intervals |
|
|
128
142
|
| `.intersection(intervals)` | Common overlap of a collection of intervals, or `nil` |
|
|
@@ -186,6 +186,26 @@ module Philiprehberger
|
|
|
186
186
|
end
|
|
187
187
|
end
|
|
188
188
|
|
|
189
|
+
# Return one or more random Floats within the interval.
|
|
190
|
+
#
|
|
191
|
+
# Without an argument, returns a single random Float. With an integer
|
|
192
|
+
# argument, returns an array of that many random Floats. Respects boundary
|
|
193
|
+
# types: open boundaries are excluded via rejection sampling. Returns
|
|
194
|
+
# +start+ immediately for point intervals (start == finish, closed).
|
|
195
|
+
#
|
|
196
|
+
# @param n [Integer, nil] number of samples, or nil for a single value
|
|
197
|
+
# @return [Float, Array<Float>]
|
|
198
|
+
# @raise [Error] if the interval is empty
|
|
199
|
+
def sample(n = nil)
|
|
200
|
+
raise Error, 'cannot sample an empty interval' if empty?
|
|
201
|
+
|
|
202
|
+
if n.nil?
|
|
203
|
+
sample_one
|
|
204
|
+
else
|
|
205
|
+
Array.new(n) { sample_one }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
189
209
|
# Clamp a value to the interval bounds.
|
|
190
210
|
#
|
|
191
211
|
# @param value [Comparable] the value to clamp
|
|
@@ -239,6 +259,22 @@ module Philiprehberger
|
|
|
239
259
|
def empty?
|
|
240
260
|
@start == @finish && @type != :closed
|
|
241
261
|
end
|
|
262
|
+
|
|
263
|
+
private
|
|
264
|
+
|
|
265
|
+
def sample_one
|
|
266
|
+
return @start.to_f if @start == @finish
|
|
267
|
+
|
|
268
|
+
lo = @start.to_f
|
|
269
|
+
hi = @finish.to_f
|
|
270
|
+
|
|
271
|
+
loop do
|
|
272
|
+
value = lo + (rand * (hi - lo))
|
|
273
|
+
left_ok = left_closed? ? value >= lo : value > lo
|
|
274
|
+
right_ok = right_closed? ? value <= hi : value < hi
|
|
275
|
+
return value if left_ok && right_ok
|
|
276
|
+
end
|
|
277
|
+
end
|
|
242
278
|
end
|
|
243
279
|
end
|
|
244
280
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-interval
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Interval data type supporting closed, open, and half-open boundaries
|
|
14
14
|
with overlap detection, containment, intersection, union, subtraction, shift, scale,
|