NAME
Sidef::Types::Range::RangeNumber - Numeric range object supporting iteration, slicing, and lazy sequences.
DESCRIPTION
This class represents numerical ranges in Sidef: sequences of numbers between a from and to bound, advancing by a step. It is a subclass of Sidef::Types::Range::Range and inherits that class's general-purpose iteration, filtering, and conversion methods (each, map, grep, to_a, and so on).
On top of that, RangeNumber adds numeric-specific functionality: aggregation (sum, product, average, GCD, LCM), binary search, and a large family of number-theoretic filters (primes, semiprimes, squarefree/powerful numbers, Carmichael numbers, almost primes, and more).
Many of these methods have a fast, closed-form implementation for the common case of a unit-step range (step of 1 or -1), computed directly from the from/to bounds without iterating at all. For any other step, they fall back to filtering (and sometimes fully materializing) the sequence, which requires the range to be finite.
SYNOPSIS
var r = RangeNumber(1, 10) # range from 1 to 10, step 1
var r = RangeNumber(1, 10, 2) # range from 1 to 10, step 2
var r = 1..10 # same as RangeNumber(1, 10)
var r = ^10 # range from 0 to 9
INHERITS
Inherits methods from Sidef::Types::Range::Range.
CONSTRUCTION
new
RangeNumber.new(from, to, step)
RangeNumber(from, to, step)
Creates a new RangeNumber object. step defaults to 1 if omitted. A few special cases:
If
fromis omitted entirely, the result is the empty range0..-1.If only
fromis given (toomitted), it's treated as a count: the range becomes0 .. (from - 1), i.e.fromelements starting at0.If
tois itself anotherRangeNumber, only itstobound is used (its ownfromis discarded).
var r1 = RangeNumber.new(1, 10) # 1 to 10, step 1
var r2 = RangeNumber.new(1, 10, 2) # 1, 3, 5, 7, 9
var r3 = RangeNumber.new(10) # 0 to 9
Aliases: call
call
RangeNumber(from, to, step)
Allows RangeNumber to be invoked directly as a function, equivalent to "new".
Aliases: new
STRING REPRESENTATION
dump
self.dump
Returns a string representation of the range, showing its from, to, and step values.
say((1..10).dump) #=> "RangeNum(1, 10, 1)"
Aliases: to_s, to_str
ITERATION
iter
self.iter
Returns an iterator (a Block) that generates successive elements of the range each time it's called, returning nil once exhausted. This overrides the generic iterator from the parent Range class with one optimized specifically for numbers: it uses native machine integers where possible and transparently switches to arbitrary-precision arithmetic if the values would overflow.
var it = (1..5).iter
say(it.run) #=> 1
say(it.run) #=> 2
say(it.run) #=> 3
AGGREGATION
sum
self.sum
self.sum(block)
With no argument, returns the sum of all elements in the range, computed directly from a closed-form arithmetic-series formula (no iteration needed, so this works even for very large finite ranges). Returns 0 for an empty range. With a block, delegates entirely to "sum_by" (the block is not optional sugar here -- passing one changes to the iterative, per-element code path).
say((1..10).sum) #=> 55
say((1..10).sum {|n| n**2 }) #=> 385
Aliases: Σ
sum_by
self.sum_by(block)
Iterates the range lazily and returns the sum of block applied to each element. Processes elements incrementally (in internal batches), so it doesn't need to hold the whole sequence in memory at once. If block is omitted, elements are summed directly.
say((1..10).sum_by {|n| n**2 }) #=> 385
prod
self.prod
self.prod(block)
With no argument, returns the product of all elements in the range. If the range is 1..n with step 1, this is computed instantly as n.factorial; otherwise, the range is fully materialized into a list first. With a block, delegates entirely to "prod_by" (the lazy, iterative path).
say((1..5).prod) #=> 120 (1*2*3*4*5, via 5.factorial)
say((1..5).prod {|n| n**2 }) #=> 14400
Aliases: Π
prod_by
self.prod_by(block)
Iterates the range lazily and returns the product of block applied to each element. Processes elements incrementally (in internal batches). If block is omitted, elements are multiplied directly.
say((1..5).prod_by {|n| n + 1 }) #=> 720 (2*3*4*5*6)
avg
self.avg
self.avg(block)
Returns the arithmetic mean of all elements in the range (self.sum / self.len). With a block, delegates to "avg_by".
say((1..10).avg) #=> 5.5
say((1..10).avg {|n| n**2 }) #=> 38.5
avg_by
self.avg_by(block)
Returns the arithmetic mean of block applied to each element (self.sum_by(block) / self.len).
say((1..10).avg_by {|n| n**2 }) #=> 38.5
gcd
self.gcd
self.gcd(block)
Returns the greatest common divisor of all elements in the range. With no block, the range is fully materialized into a list first (there is no closed-form shortcut for GCD, unlike "prod" or "lcm"). With a block, delegates to "gcd_by" (the lazy, iterative path).
say((6..12).gcd) # GCD of 6,7,8,9,10,11,12
say((1..10).gcd {|n| n * 6 }) # GCD of 6,12,18,...,60
gcd_by
self.gcd_by(block)
Iterates the range lazily and returns the greatest common divisor of block applied to each element.
say((1..10).gcd_by {|n| 2*n })
lcm
self.lcm
self.lcm(block)
Returns the least common multiple of all elements in the range. If the range is 1..n with step 1, this uses an optimized consecutive-LCM formula; otherwise, the range is fully materialized into a list first. With a block, delegates to "lcm_by" (the lazy, iterative path).
say((1..10).lcm) #=> 2520
say((1..10).lcm {|n| 2*n })
lcm_by
self.lcm_by(block)
Iterates the range lazily and returns the least common multiple of block applied to each element.
say((1..10).lcm_by {|n| n + 1 })
faulhaber_sum
self.faulhaber_sum(k)
Returns the sum of the k-th powers of all integers in the range, using Faulhaber's summation formula. If the range's step is 1, this is computed in closed form; otherwise, it falls back to lazily mapping each element to its k-th power and summing.
say((1..10).faulhaber_sum(2)) #=> 385 (sum of squares: 1+4+9+...+100)
say((1..10).faulhaber_sum(3)) #=> 3025 (sum of cubes: 1+8+27+...+1000)
Aliases: faulhaber
mertens
self.mertens
Returns the Mertens function M(n) = the sum of the Moebius function μ(k) for every k in the range. If the range's step is 1, this is computed in closed form; otherwise, it falls back to lazily keeping only the squarefree elements (the Moebius function is 0 on non-squarefree numbers), mapping each to its Moebius value, and summing.
say((1..100).mertens)
SEARCHING
bsearch
self.bsearch(block)
Performs a binary search over the range using block as the comparison function, returning the element for which block returns 0, or nil if none is found. If the range's step is 1, the search is delegated directly to Number's own binary search over the from/to bounds; otherwise, the range is first fully materialized into an array and searched there.
# Find x where x**2 == 49
say((1..100).bsearch {|n| 49 <=> n**2 }) #=> 7
bsearch_le
self.bsearch_le(block)
Like "bsearch", but returns the last element for which block returns a value <= 0.
say((1..100).bsearch_le {|n| n**2 - 50 }) # last n where n**2 <= 50
bsearch_ge
self.bsearch_ge(block)
Like "bsearch", but returns the first element for which block returns a value >= 0.
say((1..100).bsearch_ge {|n| n**2 - 50 }) # first n where n**2 >= 50
SQUAREFREE, CUBEFREE, AND K-TH-POWER(FREE/FULL) NUMBERS
Each concept below (squarefree, cubefree, k-powerful, k-powerfree, and their complements) generally comes as up to four related methods: each_X(block) to iterate over matching numbers, X to collect them into an array, X_count to count them, and X_sum to sum them. For a range whose step is 1 (or -1, for the array/count/sum forms), these delegate directly to an optimized Number function over the from/to bounds; for any other step, they fall back to filtering the range's lazy sequence by the underlying predicate (which still requires the range to be finite).
squarefree
self.squarefree
Returns an array of squarefree numbers in the range. A squarefree number has no perfect square (other than 1) as a divisor.
say((1..20).squarefree) #=> [1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15, 17, 19]
each_squarefree
self.each_squarefree(block)
Iterates over all squarefree numbers in the range, calling block for each, and returns self.
(1..100).each_squarefree {|n| say(n) }
squarefree_count
self.squarefree_count
Returns the count of squarefree numbers in the range.
say((1..100).squarefree_count) #=> 61
squarefree_sum
self.squarefree_sum
Returns the sum of all squarefree numbers in the range.
say((1..100).squarefree_sum)
cubefree
self.cubefree
Returns an array of cubefree numbers in the range. A cubefree number has no perfect cube (other than 1) as a divisor.
say((1..20).cubefree) #=> [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20]
each_cubefree
self.each_cubefree(block)
Iterates over all cubefree numbers in the range, calling block for each, and returns self.
(1..100).each_cubefree {|n| say(n) }
cubefree_count
self.cubefree_count
Returns the count of cubefree numbers in the range.
say((1..1000).cubefree_count)
cubefree_sum
self.cubefree_sum
Returns the sum of all cubefree numbers in the range.
say((1..100).cubefree_sum)
nonsquarefree
self.nonsquarefree
Returns an array of non-squarefree numbers in the range (numbers divisible by a perfect square greater than 1).
say((1..50).nonsquarefree) #=> [4, 8, 9, 12, 16, 18, 20, 24, 25, ...]
each_nonsquarefree
self.each_nonsquarefree(block)
Iterates over all non-squarefree numbers in the range, calling block for each, and returns self.
(1..100).each_nonsquarefree {|n| say(n) } # 4, 8, 9, 12, 16, ...
nonsquarefree_count
self.nonsquarefree_count
Returns the count of non-squarefree numbers in the range.
say((1..1000).nonsquarefree_count)
nonsquarefree_sum
self.nonsquarefree_sum
Returns the sum of all non-squarefree numbers in the range.
say((1..100).nonsquarefree_sum)
noncubefree
self.noncubefree
Returns an array of non-cubefree numbers in the range (numbers divisible by a perfect cube greater than 1).
say((1..100).noncubefree) #=> [8, 16, 24, 27, 32, ...]
each_noncubefree
self.each_noncubefree(block)
Iterates over all non-cubefree numbers in the range, calling block for each, and returns self.
(1..100).each_noncubefree {|n| say(n) } # 8, 16, 24, 27, ...
noncubefree_count
self.noncubefree_count
Returns the count of non-cubefree numbers in the range.
say((1..1000).noncubefree_count)
noncubefree_sum
self.noncubefree_sum
Returns the sum of all non-cubefree numbers in the range.
say((1..100).noncubefree_sum)
squarefull
self.squarefull
Returns an array of squarefull (2-powerful) numbers in the range. A squarefull number has every prime factor appearing at least twice.
say((1..100).squarefull) #=> [1, 4, 8, 9, 16, 25, 27, 32, 36, 49, 64, 72, 81, 100]
each_squarefull
self.each_squarefull(block)
Iterates over all squarefull numbers in the range, calling block for each, and returns self.
(1..100).each_squarefull {|n| say(n) } # 1, 4, 8, 9, 16, 25, 27, ...
squarefull_count
self.squarefull_count
Returns the count of squarefull numbers in the range.
say((1..10000).squarefull_count)
squarefull_sum
self.squarefull_sum
Returns the sum of all squarefull numbers in the range.
say((1..1000).squarefull_sum)
cubefull
self.cubefull
Returns an array of cubefull (3-powerful) numbers in the range. A cubefull number has every prime factor appearing at least 3 times.
say((1..1000).cubefull) #=> [1, 8, 16, 27, 32, 64, 81, ...]
each_cubefull
self.each_cubefull(block)
Iterates over all cubefull numbers in the range, calling block for each, and returns self.
(1..1000).each_cubefull {|n| say(n) }
cubefull_count
self.cubefull_count
Returns the count of cubefull numbers in the range.
say((1..10000).cubefull_count)
cubefull_sum
self.cubefull_sum
Returns the sum of all cubefull numbers in the range.
say((1..1000).cubefull_sum)
powerful
self.powerful(k)
Returns an array of k-powerful numbers in the range. A k-powerful number has every prime factor appearing at least k times.
say((1..100).powerful(2)) # squarefull: [1, 4, 8, 9, 16, 25, 27, ...]
each_powerful
self.each_powerful(k, block)
Iterates over all k-powerful numbers in the range, calling block for each, and returns self.
(1..1000).each_powerful(2, {|n| say(n) }) # squarefull numbers
powerful_count
self.powerful_count(k)
Returns the count of k-powerful numbers in the range.
say((1..10000).powerful_count(2))
powerful_sum
self.powerful_sum(k)
Returns the sum of all k-powerful numbers in the range.
say((1..1000).powerful_sum(2))
powerfree
self.powerfree(k)
Returns an array of k-powerfree numbers in the range (numbers not divisible by any k-th power greater than 1).
say((1..50).powerfree(2)) # squarefree numbers
say((1..50).powerfree(3)) # cubefree numbers
each_powerfree
self.each_powerfree(k, block)
Iterates over all k-powerfree numbers in the range, calling block for each, and returns self.
(1..100).each_powerfree(2, {|n| say(n) }) # squarefree numbers
powerfree_count
self.powerfree_count(k)
Returns the count of k-powerfree numbers in the range.
say((1..1000).powerfree_count(2)) # count of squarefree numbers
powerfree_sum
self.powerfree_sum(k)
Returns the sum of all k-powerfree numbers in the range.
say((1..100).powerfree_sum(2))
nonpowerfree
self.nonpowerfree(k)
Returns an array of non-k-powerfree numbers in the range (numbers divisible by a k-th power greater than 1).
say((1..100).nonpowerfree(2)) # non-squarefree numbers
each_nonpowerfree
self.each_nonpowerfree(k, block)
Iterates over all non-k-powerfree numbers in the range, calling block for each, and returns self.
(1..100).each_nonpowerfree(2, {|n| say(n) }) # non-squarefree numbers
nonpowerfree_count
self.nonpowerfree_count(k)
Returns the count of non-k-powerfree numbers in the range.
say((1..1000).nonpowerfree_count(2))
nonpowerfree_sum
self.nonpowerfree_sum(k)
Returns the sum of all non-k-powerfree numbers in the range.
say((1..100).nonpowerfree_sum(2))
PRIMES, PRIME POWERS, AND ALMOST PRIMES
As with the previous category, each concept here comes as up to four related methods (each_X, X, X_count, X_sum), with a fast closed-form path for unit-step ranges and a lazy-filtering fallback otherwise.
primes
self.primes
Returns an array of prime numbers in the range.
say((1..50).primes) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
each_prime
self.each_prime(block)
Iterates over all prime numbers in the range, calling block for each, and returns self.
(1..100).each_prime {|p| say(p) } # print primes up to 100
prime_count
self.prime_count
Returns the count of prime numbers in the range.
say((1..100).prime_count) #=> 25
prime_sum
self.prime_sum
Returns the sum of all prime numbers in the range.
say((1..100).prime_sum) #=> 1060
prime_powers
self.prime_powers
Returns an array of prime powers in the range. A prime power is p**k where p is prime and k >= 1.
say((1..50).prime_powers) #=> [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19, 23, 25, 27, 29, 31, 32, 37, 41, 43, 47, 49]
each_prime_power
self.each_prime_power(block)
Iterates over all prime powers in the range, calling block for each, and returns self.
(1..100).each_prime_power {|n| say(n) } # 2, 3, 4, 5, 7, 8, 9, 11, ...
prime_power_count
self.prime_power_count
Returns the count of prime powers in the range.
say((1..100).prime_power_count)
prime_power_sum
self.prime_power_sum
Returns the sum of all prime powers in the range.
say((1..100).prime_power_sum)
composites
self.composites
Returns an array of composite numbers in the range.
say((1..20).composites) #=> [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20]
each_composite
self.each_composite(block)
Iterates over all composite numbers in the range, calling block for each, and returns self.
(1..20).each_composite {|n| say(n) }
composite_count
self.composite_count
Returns the count of composite numbers in the range.
say((1..100).composite_count) #=> 74
composite_sum
self.composite_sum
Returns the sum of all composite numbers in the range.
say((1..100).composite_sum)
semiprimes
self.semiprimes
Returns an array of semiprimes in the range. A semiprime is a product of exactly two primes (with multiplicity), i.e. a 2-almost prime.
say((1..50).semiprimes) #=> [4, 6, 9, 10, 14, 15, 21, 22, 25, 26, 33, 34, 35, 38, 39, 46, 49]
each_semiprime
self.each_semiprime(block)
Iterates over all semiprimes in the range, calling block for each, and returns self.
(1..100).each_semiprime {|n| say(n) } # 4, 6, 9, 10, 14, 15, ...
semiprime_count
self.semiprime_count
Returns the count of semiprimes in the range.
say((1..100).semiprime_count)
semiprime_sum
self.semiprime_sum
Returns the sum of all semiprimes in the range.
say((1..100).semiprime_sum)
squarefree_semiprimes
self.squarefree_semiprimes
Returns an array of squarefree semiprimes in the range: products of two distinct primes.
say((1..50).squarefree_semiprimes) #=> [6, 10, 14, 15, 21, 22, 26, 33, 34, 35, 38, 39, 46]
each_squarefree_semiprime
self.each_squarefree_semiprime(block)
Iterates over all squarefree semiprimes in the range, calling block for each, and returns self.
(1..100).each_squarefree_semiprime {|n| say(n) } # 6, 10, 14, 15, ...
squarefree_semiprime_count
self.squarefree_semiprime_count
Returns the count of squarefree semiprimes in the range.
say((1..100).squarefree_semiprime_count)
squarefree_semiprime_sum
self.squarefree_semiprime_sum
Returns the sum of all squarefree semiprimes in the range.
say((1..100).squarefree_semiprime_sum)
almost_primes
self.almost_primes(k)
Returns an array of k-almost prime numbers in the range. A k-almost prime is a number with exactly k prime factors, counted with multiplicity.
say((1..100).almost_primes(2)) # semiprimes: [4, 6, 9, 10, 14, ...]
say((1..100).almost_primes(3)) # 3-almost primes: [8, 12, 18, 20, ...]
each_almost_prime
self.each_almost_prime(k, block)
Iterates over all k-almost prime numbers in the range, calling block for each, and returns self.
(1..100).each_almost_prime(2, {|n| say(n) }) # print semiprimes
almost_prime_count
self.almost_prime_count(k)
Returns the count of k-almost prime numbers in the range.
say((1..100).almost_prime_count(2)) # count of semiprimes in range
almost_prime_sum
self.almost_prime_sum(k)
Returns the sum of all k-almost prime numbers in the range.
say((1..100).almost_prime_sum(2)) # sum of semiprimes in range
squarefree_almost_primes
self.squarefree_almost_primes(k)
Returns an array of squarefree k-almost prime numbers in the range: products of exactly k distinct primes.
say((1..100).squarefree_almost_primes(3)) # products of 3 distinct primes: [30, 42, 66, 70, 78]
each_squarefree_almost_prime
self.each_squarefree_almost_prime(k, block)
Iterates over all squarefree k-almost prime numbers in the range, calling block for each, and returns self.
(1..100).each_squarefree_almost_prime(3, {|n| say(n) }) # products of 3 distinct primes
squarefree_almost_prime_count
self.squarefree_almost_prime_count(k)
Returns the count of squarefree k-almost prime numbers in the range.
say((1..1000).squarefree_almost_prime_count(3))
squarefree_almost_prime_sum
self.squarefree_almost_prime_sum(k)
Returns the sum of all squarefree k-almost prime numbers in the range.
say((1..1000).squarefree_almost_prime_sum(3))
omega_primes
self.omega_primes(k)
Returns an array of k-omega prime numbers in the range: numbers with exactly k distinct prime factors (regardless of multiplicity).
say((1..100).omega_primes(2)) # numbers with exactly 2 distinct prime factors
each_omega_prime
self.each_omega_prime(k, block)
Iterates over all k-omega prime numbers in the range, calling block for each, and returns self.
(1..100).each_omega_prime(2, {|n| say(n) }) # numbers with exactly 2 distinct prime factors
omega_prime_count
self.omega_prime_count(k)
Returns the count of k-omega prime numbers in the range.
say((1..1000).omega_prime_count(2))
omega_prime_sum
self.omega_prime_sum(k)
Returns the sum of all k-omega prime numbers in the range.
say((1..1000).omega_prime_sum(2))
CARMICHAEL NUMBERS
Unlike most of the number-theoretic families above, these two concepts only provide each_X and plain X (array) forms -- there is no corresponding _count or _sum method.
carmichael
self.carmichael(k)
Returns an array of Carmichael numbers in the range that are also k-almost primes. Carmichael numbers are composite numbers n that satisfy a**(n-1) == 1 (mod n) for every integer a coprime to n.
say((1..10000).carmichael(3)) # 3-factor Carmichael numbers
each_carmichael
self.each_carmichael(k, block)
Iterates over all Carmichael numbers in the range that are also k-almost primes, calling block for each, and returns self.
(1..100000).each_carmichael(3, {|n| say(n) })
lucas_carmichael
self.lucas_carmichael(k)
Returns an array of Lucas-Carmichael numbers in the range that are also k-almost primes. Lucas-Carmichael numbers are analogous to Carmichael numbers, defined via the relation (p+1) | (n+1) for every prime factor p of n.
say((1..100000).lucas_carmichael(3))
each_lucas_carmichael
self.each_lucas_carmichael(k, block)
Iterates over all Lucas-Carmichael numbers in the range that are also k-almost primes, calling block for each, and returns self.
(1..100000).each_lucas_carmichael(3, {|n| say(n) })
SMOOTH AND ROUGH NUMBERS
These two concepts only provide a _count form -- there is no corresponding each_X, plain X (array), or _sum method.
smooth_count
self.smooth_count(k)
Returns the count of k-smooth numbers in the range. A k-smooth number has every prime factor <= k.
say((1..1000).smooth_count(5)) # 5-smooth numbers (regular numbers)
rough_count
self.rough_count(k)
Returns the count of k-rough numbers in the range. A k-rough number has every prime factor >= k.
say((1..1000).rough_count(5)) # numbers with all prime factors >= 5
SEE ALSO
Sidef::Types::Range::Range, Sidef::Types::Number::Number, Sidef::Types::Array::Array