Skip to content

Commit

Permalink
- Added the Number solve_lcg(n, r, m) method.
Browse files Browse the repository at this point in the history
Returns the smallest solution for `x` to the following linear congruence:

    n*x == r (mod m)

Example:

    say solve_lcg(143, 44, 231)     #=> 10
  • Loading branch information
trizen committed Sep 27, 2021
1 parent 4b08705 commit efcdfad
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
39 changes: 39 additions & 0 deletions lib/Sidef/Types/Number/Number.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6344,6 +6344,45 @@ package Sidef::Types::Number::Number {
return (undef, undef);
}

sub solve_lcg {
my ($n, $r, $m) = @_;

# Solve: n*x == r (mod m)

_valid(\$r, \$m);

$n = _any2mpz($$n) // goto &nan;
$r = _any2mpz($$r) // goto &nan;
$m = _any2mpz($$m) // goto &nan;

Math::GMPz::Rmpz_sgn($m) || goto &nan;

my $g = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_gcd($g, $n, $m);

if (Math::GMPz::Rmpz_cmp_ui($g, 1) != 0) {

# No solution exists if `r` is NOT divisible by `gcd(n,m)`
Math::GMPz::Rmpz_divisible_p($r, $g) || goto &nan;

$n = Math::GMPz::Rmpz_init_set($n);
$r = Math::GMPz::Rmpz_init_set($r);
$m = Math::GMPz::Rmpz_init_set($m);

Math::GMPz::Rmpz_divexact($n, $n, $g);
Math::GMPz::Rmpz_divexact($r, $r, $g);
Math::GMPz::Rmpz_divexact($m, $m, $g);
}

Math::GMPz::Rmpz_invert($g, $n, $m);
Math::GMPz::Rmpz_mul($g, $g, $r);
Math::GMPz::Rmpz_mod($g, $g, $m);

bless \$g;
}

*solve_linear_congruence = \&solve_lcg;

sub sqrt_cfrac_period_each {
my ($n, $block, $max) = @_;

Expand Down
22 changes: 20 additions & 2 deletions lib/Sidef/Types/Number/Number.pod
Original file line number Diff line number Diff line change
Expand Up @@ -2466,7 +2466,7 @@ For negative values of C<k>, falling factorial is defined as:

falling_factorial(n, -k) = 1/falling_factorial(n + k, k)

When the denominator is zero, NaN is returned.
When the denominator is zero, C<NaN> is returned.

=cut

Expand Down Expand Up @@ -5938,7 +5938,7 @@ Example:
say rat_approx(3.14).as_frac #=> 22/7
say rat_approx(zeta(-5)).as_frac #=> -1/252

Returns NaN when C<x> is not a real number.
Returns C<NaN> when C<x> is not a real number.

=cut

Expand Down Expand Up @@ -6225,6 +6225,24 @@ Example:

=cut

=head2 solve_lcg

solve_lcg(n, r, m)

Return the smallest solution for C<x> to the following linear congruence:

n*x == r (mod m)

Example:

say solve_lcg(143, 44, 231) #=> 10

Return C<NaN> when no solution exists (i.e.: when C<r> is not divisbile by C<gcd(n, m)>).

Aliases: I<solve_linear_congruence>

=cut

=head2 solve_pell

solve_pell(d, k=1)
Expand Down

0 comments on commit efcdfad

Please sign in to comment.