
=encoding utf8

=head1 NAME

Sidef::Math::Math

=head1 DESCRIPTION

The C<Math> class implements several useful mathematical functions.

=head1 SYNOPSIS

    say Math.lcm(3,4,5)
    say Math.avg(1,2,3,4)

=head1 INHERITS

Inherits methods from:

       * Sidef::Object::Object

=head1 METHODS

=head2 avg

    Math.avg(list...)

Returns the arithmetic mean of a list of numbers.

    say Math.avg(42, 50, 99, 147)       #=> 84.5

Aliases: I<arithmetic_mean>

=cut

=head2 batch_gcd

    Math.batch_gcd(list...)

Efficiently computes the batch-gcd of a list of integers.

    say Math.batch_gcd(1909,2923,291,205,989,62,451,1943,1079,2419)

Output:

    [1909, 1, 1, 41, 23, 1, 41, 1, 83, 41]

=cut

=head2 batch_invmod

    Math.batch_invmod(array, n)

Efficiently computes the modular multiplicative inverses of a list of integers, modulo C<n>.

    say Math.batch_invmod([33, 42, 99, 103], 2017)      #=> [489, 1969, 163, 235]

=cut

=head2 binary_exp

    Math.binary_exp(c, x, n, {|a,b| ... })

Generic implementation of the binary exponentiation algorithm, using the binary expansion of C<n>.

    say Math.binary_exp(1, 3, 43, {|a,b| a * b })  #=> 3^43
    say Math.binary_exp(0, 3, 43, {|a,b| a + b })  #=> 3*43

=cut

=head2 binsplit

    Math.binsplit(block, list...)

Binary splitting algorithm.

        var arr = [1,2,3,4,5,6,7]

        # Sum of a list using binary splitting
        say Math.binsplit({|a,b| a + b }, arr...)

        # Product of a list using binary splitting
        say Math.binsplit({|a,b| a * b }, arr...)

=cut

=head2 chinese

    Math.chinese(pairs...)

Returns the solution for C<x> in C<x ≡ a_k (mod m_k)>, using the Chinese Remainder Theorem (CRT), given a list of pairs C<[a_k,m_k]>:

    say Math.chinese([14,643], [254,419], [87,733])     #=> 87041638

=cut

=head2 for

    Math.for(initial, conditionBlock, nextTermBlock)

Returns an Enumerator object, generating a sequence of numbers based on the C<conditionBlock> and C<nextTermBlock> blocks.

    Math.for(1, { _ <= 10 }, { .inc }).each { .say }     # count from 1 to 10

The value of C<conditionBlock> can be C<nil>, which creates an infinite Enumerator object:

    say Math.for(2, nil, { .next_prime }).first(25)      # array of first 25 primes

=cut

=head2 gcd

    Math.gcd(list...)

Returns the greatest common divisor (GCD) of a list of integers.

=cut

=head2 gcd_factors

    Math.gcd_factors(n, [a, b, ...])

Given a positive integer and an array of integers, it tries to find non-trivial factors of n, checking each C<gcd(n, array[0])>, C<gcd(n, array[1])>, etc.

    var n = 43*43*97*503
    var a = [19*43*97, 1, 13*41*43*101]
    say Math.gcd_factors(n, a)          #=> [43, 43, 97, 503]

The product of the factors gives back C<n>. However, some factors may be composite.

=cut

=head2 geometric_mean

    Math.geometric_mean(list...)

Returns the geometric mean of a list of numbers.

    say Math.geometric_mean(42, 50, 99, 147)        #=> 74.352051512093712...

=cut

=head2 harmonic_mean

    Math.harmonic_mean(list...)

Returns the harmonic mean of a list of numbers.

    say Math.harmonic_mean(42, 50, 99, 147)         #=> 65.883471411109602...

=cut

=head2 lcm

    Math.lcm(list...)

Returns the least common multiple (LCM) of a list of integers.

=cut

=head2 linear_rec

    Math.linear_rec(ker, init, n)
    Math.linear_rec(ker, init, from, to)

Returns the n-th term or the terms with indices in the range C<from> .. C<to> (as an Array object), by iterating the linear recurrence with kernel C<ker> starting with initial values C<init>.

    say Math.linear_rec([1, 1], [0, 1], 0, 5)                    #=> [0, 1, 1, 2, 3, 5]
    say Math.linear_rec([3, -3, 1], [0, 1, 3], 0, 5)             #=> [0, 1, 3, 6, 10, 15]
    say Math.linear_rec([4, -6, 4, -1], [0, 1, 5, 14], 100000)   #=> 333338333350000

Aliases: I<linear_recurrence>

=cut

=head2 linear_recmod

    Math.linear_recmod(ker, init, n, m)

Returns the n-th term modulo C<m>, defined by the linear recurrence with kernel C<ker> starting with initial values C<init>.

    say Math.linear_recmod([1, 1], [0, 1], 43, 43)     #=> 42 (== fibmod(43,43))

Aliases: I<linear_recurrence_mod>

=cut

=head2 linear_recurrence_matrix

    Math.linear_recurrence_matrix(ker)

Returns a Matrix object that represents the given linear recurrence kernel.

=cut

=head2 map

    Math.map(value, in_min, in_max, out_min, out_max)

Return a given value mapped from a given range to another given range.

    # Map 25 from 1..100, to 1..10
    say Math.map(25, 1, 100, 1, 10)     #=> 3.181818181...

=cut

=head2 max

    Math.max(list...)

Returns the largest numerical value from a list of numbers.

=cut

=head2 min

    Math.min(list...)

Returns the smallest numerical value from a list of numbers.

=cut

=head2 num2percent

    Math.num2percent(num, min, max)

Returns a given value as a percentage, given C<min> and C<max> of the value range.

    # Map the value 25 as a percentage, from a range 1..400
    say Math.num2percent(25, 1, 400)        #=> 6.01503759398...

=cut

=head2 prod

    Math.prod(list...)

Returns the product of a list of numbers.

Aliases: I<product>

=cut

=head2 product_tree

    Math.product_tree(list...)

Return the product-tree of a list of integers.

    say Math.product_tree(10,20,30,40,50,60)

=cut

=head2 range_map

    Math.range_map(amount, from, to)

Returns a RangeNumber object with the C<amount> value mapped between the values C<from> and C<to>.

    say Math.range_map(10, 2, 5)    #=> RangeNum(2, 5, 3/10)

=cut

=head2 range_sum

    Math.range_sum(from, to, step)

Returns the sum of a given range and an optional given step.

    say Math.range_sum(1, 10)      #=> 55
    say Math.range_sum(1, 10, 2)   #=> 30.25

=cut

=head2 remainders

    Math.remainders(n, array)

Efficiently returns the remainders of C<n> when divided by each integer from the given array.

    say Math.remainders(8675309, [11,13,17,19,23])      #=> [5, 6, 5, 4, 8]

=cut

=head2 seq

    Math.seq(x, y, z, ..., {|a,n| ... })

Returns an Enumerator object which generates an infinite sequence specified by the initial terms and the given block.

Example:

    say Math.seq(2, { .last.next_prime }).first(30)     # prime numbers
    say Math.seq(1, 1, { .last(2).sum }).first(30)      # Fibonacci numbers

=cut

=head2 smooth_numbers

    Math.smooth_numbers(primes...)

It returns an Enumerator object, which generates smooth numbers using the given list of primes.

Example:

        var a = Math.smooth_numbers(2,3,5,7)    # 7-smooth numbers
        var b = Math.smooth_numbers(2,5,7)      # 7-smooth numbers not divisible by 3

        say a.first(30)
        say b.first(30)

        # Iteration is also supported
        a.each {|k|
            if (k > 1e5) {
                say k           #=> 100352
                break
            }
        }

=cut

=head2 solve_rec_seq

    Math.solve_rec_seq(array)

Attempts to find a minimal linear recurrence that generates the given array of numbers:

    say Math.solve_rec_seq(30.of { .fibonacci })      #=> [1, 1]
    say Math.solve_rec_seq(30.of { .square })         #=> [3, -3, 1]
    say Math.solve_rec_seq(30.of { .faulhaber(2) })   #=> [4, -6, 4, -1]

Aliases: I<find_linear_recurrence>

=cut

=head2 solve_seq

    Math.solve_seq(array, offset=0)

Returns a Polynomial object that generates the terms of the given sequence.

Example:

    say Math.solve_seq(20.of { .square })         #=> x^2
    say Math.solve_seq(20.of { .faulhaber(2) })   #=> 1/3*x^3 + 1/2*x^2 + 1/6*x

Example with offset:

    say Math.solve_seq(20.of { (_+10)**3 })       #=> x^3 + 30*x^2 + 300*x + 1000
    say Math.solve_seq(20.of { (_+10)**3 }, 10)   #=> x^3

=cut

=head2 sum

    Math.sum(list...)

Returns the sum of a list of numbers.

=cut
