=encoding utf8

=head1 NAME

Sidef::Types::Range::RangeNumber - Numeric range object supporting iteration, slicing, and lazy sequences.

=head1 DESCRIPTION

This class represents numerical ranges in Sidef: sequences of numbers between a C<from> and C<to> bound, advancing by a C<step>. It is a subclass of L<Sidef::Types::Range::Range> and inherits that class's general-purpose iteration, filtering, and conversion methods (C<each>, C<map>, C<grep>, C<to_a>, and so on).

On top of that, C<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 C<1> or C<-1>), computed directly from the C<from>/C<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.

=head1 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

=head1 INHERITS

Inherits methods from L<Sidef::Types::Range::Range>.

=head1 CONSTRUCTION

=head2 new

    RangeNumber.new(from, to, step)
    RangeNumber(from, to, step)

Creates a new C<RangeNumber> object. C<step> defaults to C<1> if omitted. A few special cases:

=over 4

=item * If C<from> is omitted entirely, the result is the empty range C<0..-1>.

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

=item * If C<to> is itself another C<RangeNumber>, only I<its> C<to> bound is used (its own C<from> is discarded).

=back

    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: I<call>

=cut

=head2 call

    RangeNumber(from, to, step)

Allows C<RangeNumber> to be invoked directly as a function, equivalent to L</new>.

Aliases: I<new>

=cut

=head1 STRING REPRESENTATION

=head2 dump

    self.dump

Returns a string representation of the range, showing its C<from>, C<to>, and C<step> values.

    say((1..10).dump)    #=> "RangeNum(1, 10, 1)"

Aliases: I<to_s>, I<to_str>

=cut

=head1 ITERATION

=head2 iter

    self.iter

Returns an iterator (a C<Block>) that generates successive elements of the range each time it's called, returning C<nil> once exhausted. This overrides the generic iterator from the parent C<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

=cut

=head1 AGGREGATION

=head2 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 C<0> for an empty range. With a block, delegates entirely to L</sum_by> (the block is I<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: I<Σ>

=cut

=head2 sum_by

    self.sum_by(block)

Iterates the range lazily and returns the sum of C<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 C<block> is omitted, elements are summed directly.

    say((1..10).sum_by {|n| n**2 })    #=> 385

=cut

=head2 prod

    self.prod
    self.prod(block)

With no argument, returns the product of all elements in the range. If the range is C<1..n> with step C<1>, this is computed instantly as C<n.factorial>; otherwise, the range is fully materialized into a list first. With a block, delegates entirely to L</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: I<Π>

=cut

=head2 prod_by

    self.prod_by(block)

Iterates the range lazily and returns the product of C<block> applied to each element. Processes elements incrementally (in internal batches). If C<block> is omitted, elements are multiplied directly.

    say((1..5).prod_by {|n| n + 1 })    #=> 720  (2*3*4*5*6)

=cut

=head2 avg

    self.avg
    self.avg(block)

Returns the arithmetic mean of all elements in the range (C<self.sum / self.len>). With a block, delegates to L</avg_by>.

    say((1..10).avg)             #=> 5.5
    say((1..10).avg {|n| n**2 }) #=> 38.5

=cut

=head2 avg_by

    self.avg_by(block)

Returns the arithmetic mean of C<block> applied to each element (C<self.sum_by(block) / self.len>).

    say((1..10).avg_by {|n| n**2 })  #=> 38.5

=cut

=head2 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 L</prod> or L</lcm>). With a block, delegates to L</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

=cut

=head2 gcd_by

    self.gcd_by(block)

Iterates the range lazily and returns the greatest common divisor of C<block> applied to each element.

    say((1..10).gcd_by {|n| 2*n })

=cut

=head2 lcm

    self.lcm
    self.lcm(block)

Returns the least common multiple of all elements in the range. If the range is C<1..n> with step C<1>, this uses an optimized consecutive-LCM formula; otherwise, the range is fully materialized into a list first. With a block, delegates to L</lcm_by> (the lazy, iterative path).

    say((1..10).lcm)              #=> 2520
    say((1..10).lcm {|n| 2*n })

=cut

=head2 lcm_by

    self.lcm_by(block)

Iterates the range lazily and returns the least common multiple of C<block> applied to each element.

    say((1..10).lcm_by {|n| n + 1 })

=cut

=head2 faulhaber_sum

    self.faulhaber_sum(k)

Returns the sum of the C<k>-th powers of all integers in the range, using Faulhaber's summation formula. If the range's step is C<1>, this is computed in closed form; otherwise, it falls back to lazily mapping each element to its C<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: I<faulhaber>

=cut

=head2 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 C<1>, this is computed in closed form; otherwise, it falls back to lazily keeping only the squarefree elements (the Moebius function is C<0> on non-squarefree numbers), mapping each to its Moebius value, and summing.

    say((1..100).mertens)

=cut

=head1 SEARCHING

=head2 bsearch

    self.bsearch(block)

Performs a binary search over the range using C<block> as the comparison function, returning the element for which C<block> returns C<0>, or C<nil> if none is found. If the range's step is C<1>, the search is delegated directly to C<Number>'s own binary search over the C<from>/C<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

=cut

=head2 bsearch_le

    self.bsearch_le(block)

Like L</bsearch>, but returns the last element for which C<block> returns a value C<< <= 0 >>.

    say((1..100).bsearch_le {|n| n**2 - 50 })   # last n where n**2 <= 50

=cut

=head2 bsearch_ge

    self.bsearch_ge(block)

Like L</bsearch>, but returns the first element for which C<block> returns a value C<< >= 0 >>.

    say((1..100).bsearch_ge {|n| n**2 - 50 })   # first n where n**2 >= 50

=cut

=head1 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: C<each_X(block)> to iterate over matching numbers, C<X> to collect them into an array, C<X_count> to count them, and C<X_sum> to sum them. For a range whose step is C<1> (or C<-1>, for the array/count/sum forms), these delegate directly to an optimized C<Number> function over the C<from>/C<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).

=head2 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]

=cut

=head2 each_squarefree

    self.each_squarefree(block)

Iterates over all squarefree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_squarefree {|n| say(n) }

=cut

=head2 squarefree_count

    self.squarefree_count

Returns the count of squarefree numbers in the range.

    say((1..100).squarefree_count)    #=> 61

=cut

=head2 squarefree_sum

    self.squarefree_sum

Returns the sum of all squarefree numbers in the range.

    say((1..100).squarefree_sum)

=cut

=head2 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]

=cut

=head2 each_cubefree

    self.each_cubefree(block)

Iterates over all cubefree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_cubefree {|n| say(n) }

=cut

=head2 cubefree_count

    self.cubefree_count

Returns the count of cubefree numbers in the range.

    say((1..1000).cubefree_count)

=cut

=head2 cubefree_sum

    self.cubefree_sum

Returns the sum of all cubefree numbers in the range.

    say((1..100).cubefree_sum)

=cut

=head2 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, ...]

=cut

=head2 each_nonsquarefree

    self.each_nonsquarefree(block)

Iterates over all non-squarefree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_nonsquarefree {|n| say(n) }    # 4, 8, 9, 12, 16, ...

=cut

=head2 nonsquarefree_count

    self.nonsquarefree_count

Returns the count of non-squarefree numbers in the range.

    say((1..1000).nonsquarefree_count)

=cut

=head2 nonsquarefree_sum

    self.nonsquarefree_sum

Returns the sum of all non-squarefree numbers in the range.

    say((1..100).nonsquarefree_sum)

=cut

=head2 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, ...]

=cut

=head2 each_noncubefree

    self.each_noncubefree(block)

Iterates over all non-cubefree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_noncubefree {|n| say(n) }    # 8, 16, 24, 27, ...

=cut

=head2 noncubefree_count

    self.noncubefree_count

Returns the count of non-cubefree numbers in the range.

    say((1..1000).noncubefree_count)

=cut

=head2 noncubefree_sum

    self.noncubefree_sum

Returns the sum of all non-cubefree numbers in the range.

    say((1..100).noncubefree_sum)

=cut

=head2 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]

=cut

=head2 each_squarefull

    self.each_squarefull(block)

Iterates over all squarefull numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_squarefull {|n| say(n) }    # 1, 4, 8, 9, 16, 25, 27, ...

=cut

=head2 squarefull_count

    self.squarefull_count

Returns the count of squarefull numbers in the range.

    say((1..10000).squarefull_count)

=cut

=head2 squarefull_sum

    self.squarefull_sum

Returns the sum of all squarefull numbers in the range.

    say((1..1000).squarefull_sum)

=cut

=head2 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, ...]

=cut

=head2 each_cubefull

    self.each_cubefull(block)

Iterates over all cubefull numbers in the range, calling C<block> for each, and returns C<self>.

    (1..1000).each_cubefull {|n| say(n) }

=cut

=head2 cubefull_count

    self.cubefull_count

Returns the count of cubefull numbers in the range.

    say((1..10000).cubefull_count)

=cut

=head2 cubefull_sum

    self.cubefull_sum

Returns the sum of all cubefull numbers in the range.

    say((1..1000).cubefull_sum)

=cut

=head2 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 C<k> times.

    say((1..100).powerful(2))    # squarefull: [1, 4, 8, 9, 16, 25, 27, ...]

=cut

=head2 each_powerful

    self.each_powerful(k, block)

Iterates over all k-powerful numbers in the range, calling C<block> for each, and returns C<self>.

    (1..1000).each_powerful(2, {|n| say(n) })    # squarefull numbers

=cut

=head2 powerful_count

    self.powerful_count(k)

Returns the count of k-powerful numbers in the range.

    say((1..10000).powerful_count(2))

=cut

=head2 powerful_sum

    self.powerful_sum(k)

Returns the sum of all k-powerful numbers in the range.

    say((1..1000).powerful_sum(2))

=cut

=head2 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

=cut

=head2 each_powerfree

    self.each_powerfree(k, block)

Iterates over all k-powerfree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_powerfree(2, {|n| say(n) })    # squarefree numbers

=cut

=head2 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

=cut

=head2 powerfree_sum

    self.powerfree_sum(k)

Returns the sum of all k-powerfree numbers in the range.

    say((1..100).powerfree_sum(2))

=cut

=head2 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

=cut

=head2 each_nonpowerfree

    self.each_nonpowerfree(k, block)

Iterates over all non-k-powerfree numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_nonpowerfree(2, {|n| say(n) })    # non-squarefree numbers

=cut

=head2 nonpowerfree_count

    self.nonpowerfree_count(k)

Returns the count of non-k-powerfree numbers in the range.

    say((1..1000).nonpowerfree_count(2))

=cut

=head2 nonpowerfree_sum

    self.nonpowerfree_sum(k)

Returns the sum of all non-k-powerfree numbers in the range.

    say((1..100).nonpowerfree_sum(2))

=cut

=head1 PRIMES, PRIME POWERS, AND ALMOST PRIMES

As with the previous category, each concept here comes as up to four related methods (C<each_X>, C<X>, C<X_count>, C<X_sum>), with a fast closed-form path for unit-step ranges and a lazy-filtering fallback otherwise.

=head2 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]

=cut

=head2 each_prime

    self.each_prime(block)

Iterates over all prime numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_prime {|p| say(p) }    # print primes up to 100

=cut

=head2 prime_count

    self.prime_count

Returns the count of prime numbers in the range.

    say((1..100).prime_count)    #=> 25

=cut

=head2 prime_sum

    self.prime_sum

Returns the sum of all prime numbers in the range.

    say((1..100).prime_sum)    #=> 1060

=cut

=head2 prime_powers

    self.prime_powers

Returns an array of prime powers in the range. A prime power is C<p**k> where C<p> is prime and C<k E<gt>= 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]

=cut

=head2 each_prime_power

    self.each_prime_power(block)

Iterates over all prime powers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_prime_power {|n| say(n) }    # 2, 3, 4, 5, 7, 8, 9, 11, ...

=cut

=head2 prime_power_count

    self.prime_power_count

Returns the count of prime powers in the range.

    say((1..100).prime_power_count)

=cut

=head2 prime_power_sum

    self.prime_power_sum

Returns the sum of all prime powers in the range.

    say((1..100).prime_power_sum)

=cut

=head2 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]

=cut

=head2 each_composite

    self.each_composite(block)

Iterates over all composite numbers in the range, calling C<block> for each, and returns C<self>.

    (1..20).each_composite {|n| say(n) }

=cut

=head2 composite_count

    self.composite_count

Returns the count of composite numbers in the range.

    say((1..100).composite_count)    #=> 74

=cut

=head2 composite_sum

    self.composite_sum

Returns the sum of all composite numbers in the range.

    say((1..100).composite_sum)

=cut

=head2 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]

=cut

=head2 each_semiprime

    self.each_semiprime(block)

Iterates over all semiprimes in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_semiprime {|n| say(n) }    # 4, 6, 9, 10, 14, 15, ...

=cut

=head2 semiprime_count

    self.semiprime_count

Returns the count of semiprimes in the range.

    say((1..100).semiprime_count)

=cut

=head2 semiprime_sum

    self.semiprime_sum

Returns the sum of all semiprimes in the range.

    say((1..100).semiprime_sum)

=cut

=head2 squarefree_semiprimes

    self.squarefree_semiprimes

Returns an array of squarefree semiprimes in the range: products of two I<distinct> primes.

    say((1..50).squarefree_semiprimes)    #=> [6, 10, 14, 15, 21, 22, 26, 33, 34, 35, 38, 39, 46]

=cut

=head2 each_squarefree_semiprime

    self.each_squarefree_semiprime(block)

Iterates over all squarefree semiprimes in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_squarefree_semiprime {|n| say(n) }    # 6, 10, 14, 15, ...

=cut

=head2 squarefree_semiprime_count

    self.squarefree_semiprime_count

Returns the count of squarefree semiprimes in the range.

    say((1..100).squarefree_semiprime_count)

=cut

=head2 squarefree_semiprime_sum

    self.squarefree_semiprime_sum

Returns the sum of all squarefree semiprimes in the range.

    say((1..100).squarefree_semiprime_sum)

=cut

=head2 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 C<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, ...]

=cut

=head2 each_almost_prime

    self.each_almost_prime(k, block)

Iterates over all k-almost prime numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_almost_prime(2, {|n| say(n) })    # print semiprimes

=cut

=head2 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

=cut

=head2 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

=cut

=head2 squarefree_almost_primes

    self.squarefree_almost_primes(k)

Returns an array of squarefree k-almost prime numbers in the range: products of exactly C<k> I<distinct> primes.

    say((1..100).squarefree_almost_primes(3))    # products of 3 distinct primes: [30, 42, 66, 70, 78]

=cut

=head2 each_squarefree_almost_prime

    self.each_squarefree_almost_prime(k, block)

Iterates over all squarefree k-almost prime numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_squarefree_almost_prime(3, {|n| say(n) })    # products of 3 distinct primes

=cut

=head2 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))

=cut

=head2 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))

=cut

=head2 omega_primes

    self.omega_primes(k)

Returns an array of k-omega prime numbers in the range: numbers with exactly C<k> I<distinct> prime factors (regardless of multiplicity).

    say((1..100).omega_primes(2))    # numbers with exactly 2 distinct prime factors

=cut

=head2 each_omega_prime

    self.each_omega_prime(k, block)

Iterates over all k-omega prime numbers in the range, calling C<block> for each, and returns C<self>.

    (1..100).each_omega_prime(2, {|n| say(n) })    # numbers with exactly 2 distinct prime factors

=cut

=head2 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))

=cut

=head2 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))

=cut

=head1 CARMICHAEL NUMBERS

Unlike most of the number-theoretic families above, these two concepts only provide C<each_X> and plain C<X> (array) forms -- there is no corresponding C<_count> or C<_sum> method.

=head2 carmichael

    self.carmichael(k)

Returns an array of Carmichael numbers in the range that are also k-almost primes. Carmichael numbers are composite numbers C<n> that satisfy C<a**(n-1) == 1 (mod n)> for every integer C<a> coprime to C<n>.

    say((1..10000).carmichael(3))    # 3-factor Carmichael numbers

=cut

=head2 each_carmichael

    self.each_carmichael(k, block)

Iterates over all Carmichael numbers in the range that are also k-almost primes, calling C<block> for each, and returns C<self>.

    (1..100000).each_carmichael(3, {|n| say(n) })

=cut

=head2 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 C<(p+1) | (n+1)> for every prime factor C<p> of C<n>.

    say((1..100000).lucas_carmichael(3))

=cut

=head2 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 C<block> for each, and returns C<self>.

    (1..100000).each_lucas_carmichael(3, {|n| say(n) })

=cut

=head1 SMOOTH AND ROUGH NUMBERS

These two concepts only provide a C<_count> form -- there is no corresponding C<each_X>, plain C<X> (array), or C<_sum> method.

=head2 smooth_count

    self.smooth_count(k)

Returns the count of k-smooth numbers in the range. A k-smooth number has every prime factor C<< <= k >>.

    say((1..1000).smooth_count(5))    # 5-smooth numbers (regular numbers)

=cut

=head2 rough_count

    self.rough_count(k)

Returns the count of k-rough numbers in the range. A k-rough number has every prime factor C<< >= k >>.

    say((1..1000).rough_count(5))    # numbers with all prime factors >= 5

=cut

=head1 SEE ALSO

L<Sidef::Types::Range::Range>, L<Sidef::Types::Number::Number>, L<Sidef::Types::Array::Array>

=cut
