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 from is omitted entirely, the result is the empty range 0..-1.

  • If only from is given (to omitted), it's treated as a count: the range becomes 0 .. (from - 1), i.e. from elements starting at 0.

  • If to is itself another RangeNumber, only its to bound is used (its own from is 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