Skip to content

Commit

Permalink
- Added the Number quadratic_nonresidue(n) method.
Browse files Browse the repository at this point in the history
Returns the least quadratic non-residue of n. Also aliased as `qnr(n)`.

Example:

	say qnr(17676352761153241)	#=> 37
	say qnr(172138573277896681)	#=> 41
  • Loading branch information
trizen committed Aug 3, 2020
1 parent 1e250bc commit 725721c
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,7 @@ scripts/Tests/prefix_methods.sf
scripts/Tests/prefix_unary_operators.sf
scripts/Tests/problem_of_apollonius.sf
scripts/Tests/pythagorean_means.sf
scripts/Tests/quadratic_nonresidue.sf
scripts/Tests/quicksort.sf
scripts/Tests/quoted_strings.sf
scripts/Tests/rand_pick.sf
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Sidef is a modern, high-level, general-purpose programming language, inspired by

### WWW

* Gitbook: [https://trizen.gitbooks.io/sidef-lang](https://trizen.gitbooks.io/sidef-lang)
* Tutorial: [https://github.com/trizen/sidef/wiki](https://github.com/trizen/sidef/wiki)
* RosettaCode: [https://rosettacode.org/wiki/Sidef](https://rosettacode.org/wiki/Sidef)
* Gitbook: https://trizen.gitbook.io/sidef-lang/ ([legacy](https://trizen.gitbooks.io/sidef-lang))
* Tutorial: https://github.com/trizen/sidef/wiki
* RosettaCode: https://rosettacode.org/wiki/Sidef

## EXAMPLES

Expand Down
51 changes: 51 additions & 0 deletions lib/Sidef/Types/Number/Number.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6867,6 +6867,57 @@ package Sidef::Types::Number::Number {
bless \$r;
}

sub quadratic_nonresidue {
my ($n) = @_;

# Least quadratic non-residue of n. (OEIS: A020649)
# Inspired by Dana Jacobsen's code from Math::Prime::Util::PP.

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

if (Math::GMPz::Rmpz_cmp_ui($n, 2) <= 0) {
return bless \$n;
}

if (Math::GMPz::Rmpz_ui_kronecker(2, $n) == -1) {
return TWO;
}

if (_primality_pretest($n) && Math::Prime::Util::GMP::is_prob_prime($n)) {
for (my $k = 3 ; ; $k = Math::Prime::Util::GMP::next_prime($k)) {
if (Math::GMPz::Rmpz_ui_kronecker($k, $n) == -1) {
return __PACKAGE__->_set_uint($k);
}
}
}

if (Math::GMPz::Rmpz_even_p($n)) {
return TWO if Math::GMPz::Rmpz_scan1($n, 0) >= 2;
}

foreach my $k (3, 5, 11, 13, 19) {
if (Math::GMPz::Rmpz_divisible_ui_p($n, $k)) {
return TWO;
}
}

my %f;
++$f{$_} for Math::Prime::Util::GMP::factor($n);

my @factors =
map { ($_ < ULONG_MAX) ? Math::GMPz::Rmpz_init_set_ui($_) : Math::GMPz::Rmpz_init_set_str($_, 10) } keys %f;

for (my $k = 2 ; ; $k = Math::Prime::Util::GMP::next_prime($k)) {
foreach my $p (@factors) {
if (Math::GMPz::Rmpz_cmp_ui($p, $k) > 0 and Math::GMPz::Rmpz_ui_kronecker($k, $p) == -1) {
return __PACKAGE__->_set_uint($k);
}
}
}
}

*qnr = \&quadratic_nonresidue;

sub sqrtmod {
my ($x, $y) = @_;
_valid(\$y);
Expand Down
14 changes: 14 additions & 0 deletions scripts/Tests/quadratic_nonresidue.sf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/ruby

# Tests for the least quadratic non-residue of n.

var a = %n[3277, 3281, 121463, 491209, 11530801, 512330281, 15656266201, 139309114031, 7947339136801, 72054898434289, 334152420730129, 17676352761153241, 172138573277896681]
var b = %n[3, 7, 23, 71, 311, 479, 1559, 5711, 10559, 18191, 31391, 422231, 701399, 366791, 3818929, 9257329, 22000801, 36415991, 48473881, 175244281, 120293879, 427733329, 131486759, 3389934071, 2929911599, 7979490791, 36504256799, 23616331489, 89206899239, 121560956039]

assert_eq(a.map { .qnr }, a.len.pn_primes)
assert_eq(b.map { .qnr }, b.len.pn_primes)

assert_eq(1..100 -> map { .prime.qnr }, %n[2, 2, 2, 3, 2, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5, 2, 3, 2, 2, 3, 3, 2, 3, 2, 2, 3, 2, 2, 5, 2, 2, 2, 7, 5, 2, 3, 2, 3, 2, 2, 3, 7, 7, 2, 3, 5, 2, 3, 2, 3, 2, 2, 2, 11, 5, 2, 2, 5, 2, 2, 3, 7, 3, 2, 2, 5, 2, 2, 3, 7, 2, 2, 7, 5, 3, 2, 3, 5, 2, 3, 2, 13, 3, 2, 2, 5, 2, 3, 2, 2])
assert_eq(3..110 -> map { .qnr }, %n[2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 5, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 5, 2, 2, 2, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 2, 2, 5, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2])

say "** Test passed!"

0 comments on commit 725721c

Please sign in to comment.