Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions for primality testing #145

Merged
merged 4 commits into from
Aug 10, 2023

Conversation

primo-ppcg
Copy link
Contributor

@primo-ppcg primo-ppcg commented Jul 24, 2023

Related: #140

Adds the following functions for primality testing:

  • (math/prime? n)
    A primality test, deterministic for all n less than 2^63.
  • (math/next-prime n)
    Returns the next prime number strictly larger than n.
  • (math/primes)
    A boundless prime number generator.

Also defines the following support functions in a separate C module:

  • (math/powmod a b m)
    Modular exponentiation of a to the power of b mod m.
  • (math/mulmod a b m)
    Modular multiplication of a and b mod m.
  • (math/invmod a m)
    Modular multiplicative inverse of a mod m.
  • (math/jacobi a m)
    Computes the Jacobi Symbol (a|m).

I haven't added any tests to the PR yet (now added), but it has passed this battery of tests: prime-tests.janet. This could be stripped down some before including in a test suite.

Prime testing for primes on the range 2^53 - 2^63 is about 16µs per prime on my system. Composites on average are much faster. This is down from around 600µs using a pure Janet implementation.

Possible Concerns

The C module is imported without prefix into the spork/math module. I don't know if this is the proper way to do it.

128-bit operations are used for modular multiplication where available. On Linux, I test with:

#if defined(__SIZEOF_INT128__)

which is also used in the Linux kernel, so it's probably sufficient.

For Windows I test with:

#elif defined(_WIN64) && defined(_MSC_VER)

which I can confirm works with VC 2019 and VC 2022.

The C functions use signed 64-bit integers in order to allow potentially negative arguments, which unfortunately means these functions (and therefore also the Janet functions that rely on them) don't work properly with int/u64 values exceeding 2^63. I think this could possibly be addressed, but not without a lot of code duplication in the C module.

@sogaiu
Copy link
Contributor

sogaiu commented Jul 24, 2023

it has passed this battery of tests: prime-tests.janet.

I gave these a try here (manually as well), and unsurprisingly, they passed :)

Also tried some random-ish invocations successfully.

My attempts were on a Linux machine. I don't have access to macos or any BSD machine -- I wonder if we can get someone to test on some of those.

Prime testing for primes on the range 2^53 - 2^63 is about 16µs per prime on my system. Composites on average are much faster. This is down from around 600µs using a pure Janet implementation.

Nice!

The C module is imported without prefix into the spork/math module.

That seems ok to me.

The C functions use signed 64-bit integers in order to allow potentially negative arguments, which unfortunately means these functions (and therefore also the Janet functions that rely on them) don't work properly with int/u64 values exceeding 2^63. I think this could possibly be addressed, but not without a lot of code duplication in the C module.

Perhaps this can be left as an exercise for the interested user down the line?

@sogaiu
Copy link
Contributor

sogaiu commented Jul 27, 2023

I got NetBSD running via qemu and tried out the PR and it seemed to worked fine.

Building was ok and the prime-tests.janet file gave no errors 👍

@primo-ppcg primo-ppcg marked this pull request as ready for review July 27, 2023 10:12
@sogaiu
Copy link
Contributor

sogaiu commented Jul 28, 2023

FWIW, ran the tests for e74b793 on Linux and NetBSD and things seemed fine 👍

@Techcable
Copy link
Contributor

How common is testing for primes? What use case are you thinking of that makes it deserve to be in spork?

(Just curious, not trying to be combative...)

@primo-ppcg
Copy link
Contributor Author

primo-ppcg commented Jul 30, 2023

How common is testing for primes? What use case are you thinking of that makes it deserve to be in spork?

The most useful function is likely next-prime. A number of applications require one or more primes, often of a similar length. This of course also relies on prime?. The miller-rabin-prp? function is perhaps a bit too niche, and wouldn't need to be exported necessarily.

@sogaiu
Copy link
Contributor

sogaiu commented Jul 30, 2023

It was mentioned in #140 (where there was a query about interest in prime number generation) that some hash functions have initial values that depend on primes.

I ran into this when implementing some of the SHA-2 functions.

Granted, that's not directly testing for primality (as asked about above), but rather generating primes (^^;


I guess not everyone is really into simulating cicada populations over time :P

@primo-ppcg
Copy link
Contributor Author

It was mentioned in #140 (where there was a query about interest in prime number generation) that> I ran into this when implementing some of the SHA-2 functions.

(take 64 (math/primes))

would definitely look cleaner, although with so few, listing them out is fine too.

@sogaiu
Copy link
Contributor

sogaiu commented Jul 31, 2023

(take 64 (math/primes))

would definitely look cleaner, although with so few, listing them
out is fine too.

Yes, I agree.

Using a form like the aforementioned allows one to skip the step of manually enumerating as well as verifying correctness of individual numbers and whether any had been skipped or duplicated (^^;

Do not export `miller-rabin-prp?`.
@sogaiu
Copy link
Contributor

sogaiu commented Jul 31, 2023

Tests from b828418 ran with no issues here (Linux and NetBSD) 👍

@primo-ppcg
Copy link
Contributor Author

Tests from b828418 ran with no issues here (Linux and NetBSD) +1

Appreciated. I apologize for the force pushes, I just want to avoid a bunch of minor commits in the commit history, should this PR be merged.

@bakpakin bakpakin merged commit ce3e437 into janet-lang:master Aug 10, 2023
1 check passed
@primo-ppcg primo-ppcg deleted the modular-arithmetic branch August 10, 2023 05:49
@primo-ppcg primo-ppcg mentioned this pull request Aug 10, 2023
@sogaiu
Copy link
Contributor

sogaiu commented Sep 7, 2023

I noticed today that janet itself has a primes example. Just mentioning it as there having been some additional interest in the past :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants