mpz_prevprime

Seth Troisi braintwo at gmail.com
Sat Aug 29 08:24:57 UTC 2020


I made a few improvements.

tested with '--enable-assert' and verified no impact to timing with
`./tune/speed -f 1.02 -s 10-260 mpz_prevprime -p100000000 -P time_prevprime`
comparing with mpz_nextprime (before and after my change)

On Fri, Mar 27, 2020 at 2:29 AM Seth Troisi <braintwo at gmail.com> wrote:

> Thanks for the quick review and probing comments.
>
> On Thu, Mar 26, 2020 at 2:00 PM Marco Bodrato <bodrato at mail.dm.unipi.it>
> wrote:
>
>> Ciao,
>>
>> Il 2020-03-25 02:25 Seth Troisi ha scritto:
>> > I'm back with a new mpz_prevprime patch
>>
>> diff -r 805304ca965a doc/gmp.texi
>> + at deftypefun int mpz_prevprime (mpz_t @var{rop}, const mpz_t @var{op})
>>
>> +If previous prime doesn't exist (e.g. @var{op} < 3), rop is unchanged
>> and
>> +0 is returned.
>>
>> I suggest "i.e." instead of "e.g.".
>>
> Replaced
>
>>
>> diff -r 805304ca965a mpz/nextprime.c
>> +findnext_small (unsigned t, short diff)
>> [...]
>> +  ASSERT (t > 0 || (diff < 0 && t > 2));
>>
>> This is equivalent to (t > 0). Do you mean (t > 2 || (diff > 0 && t >
>> 0))?
>>
> Yes. changed now.
>
>>
>> +  t = diff > 0 ? ((t + 1) | (t > 1)) :
>> +                 ((t == 3) ? 2 : ((t - 2) | 1));
>>
>> Maybe move this to the caller side? Or partially, leaving here just
>>    ASSERT (t >= 2);
>>    t |= (t != 2);
>>
> I moved this to the caller side (so that both findnext and findnext_small
> consider p) and added some comments
>
>>
>> -void
>> -mpz_nextprime (mpz_ptr p, mpz_srcptr n)
>> +int
>> +findnext (mpz_ptr p,
>>
>> If the function is not public any more, use static.
>>
> Done.
>
>>
>> -  mpz_setbit (p, 0);
>>
>> This line can still be here, maybe converted to
>> * PTR (p) |= 1;
>>
> This has been moved to the outer functions.
> Maybe I should add a test that p is odd?
> Something like ASSERT (PTR(p) & 1 == 0);
>
>
>> +  /* smaller numbers handled earlier*/
>> +  ASSERT (nbits >= 15);
>>
>> Not needed. Maybe ASSERT (nbits > 3), because we don't want to handle
>> very small numbers with this code.
>>
> Changed back to nbits > 3  and added an ASSERT (SIZ(p) > 0);
>
>>
>> +int
>> +mpz_prevprime (mpz_ptr p, mpz_srcptr n)
>> +{
>> +  /* First handle tiny numbers */
>> +  if (mpz_cmp_ui (n, 2) <= 0)
>> +    return 0;
>> +
>> +  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
>> +    {
>> +      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
>> +      mpz_set_ui (p, findnext_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1,
>> -2));
>> +      return 2;
>> +    }
>>
>> The line "if (mpz_cmp_ui (n, 2) <= 0)" already handle the case (SIZ (n)
>> <= 0), checking if (SIZ (n) > 0) is a nonsense
>> Anyway... assume that code is used: what happens if findnext_small(1,-2)
>> is called?
>>
> This has been reworked but should never have been included.
>
>>
>> diff -r 805304ca965a tests/mpz/t-nextprime.c
>> [...]
>> +refmpz_prevprime (mpz_ptr p, mpz_srcptr t)
>> [...]
>> +  if (mpz_cmp_ui(t, 3) <= 0)
>>
>> The loop after that branch handles also that case, don't it?
>>
> Yes, I was counting by two but I reverted that at some point.
>
>>
>>
>>   test_largegaps ()
>>   {
>> [...]
>> +  mpz_set_ui (n, 3842610773);
>> [...]
>> +  mpz_set_ui (n, 18361375334787046697UL);
>>
>> Those lines can fail at compile time... if 3842610773 does not fit in an
>> int and 18361375334787046697 not in an unsigned long. E.g. when
>> sizeof(int)==4.
>> Use _set_str.
>>
>> +  mpz_mul_ui (n, n, 4280516017);
>> [...]
>> +  mpz_mul_ui (n, n, 3483347771);
>>
>> ...
>>
>> > I also added large negative tests for mpz_nextprime
>>
>> To be honest... I do not like this (undocumented) detail of the current
>> behaviour of _nextprime. I personally do not like the idea to enforce it
>> with a test...
>>
>> > and we can enable test_largegaps now that the default gap is smaller
>>
>> Yes, we should.
>> I would also check many gaps around 2^{16n}, to check if everything
>> works correctly when the search crosses the limb boundaries.
>> Maybe structuring the test with a table {"number(base16?)", gap}, i.e.
>> with (also) something like:
>> {"65521", 16},
>> {"4294967291", 20},
>> {"281474976710597", 80},
>> {"18446744073709551557", 72},
>> {"1208925819614629174706111", 78},
>> {"79228162514264337593543950319", 78},
>> {"5192296858534827628530496329220021", 100},
>> {"340282366920938463463374607431768211297", 210},
>>
> I did this (using hex form) I threw in some 16*n-1 also
>
>>
>>
>> +void
>> +test_prevprime (gmp_randstate_ptr rands, int reps)
>> [...]
>> +  /* Test mpz_prevprime(3 <= n < 2^45) returns 2. */
>> [...]
>> +  /* Test mpz_prevprime(n > 2^70) returns 1. */
>> [...]
>> +        if ( retval != 1 )
>> [...]
>>
>> I do not understand. A test-function should fail if a function behaviour
>> does not agree with the documented interface, or it can fail for some
>> other kind of regression that we want to avoid...
>> Your test will warn us against possible improvements! What if the future
>> primality testing functions will return 2 on some large primes?
>>
>
> I modified the tests so that it makes it more clean that it's testing that
> it verifies the retval matches
> the return of mpz_prob_prime.
>
>
>> Ok, I'm sleepy now. I hope I did not write wrong things. Good night!
>>
> Given the number of times you are pointing our real issues, I wouldn't be
> worried about writing one or two wrong comments :)
>
>>
>> Ĝis,
>> m
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: prev_prime_0829.patch
Type: text/x-patch
Size: 16228 bytes
Desc: not available
URL: <https://gmplib.org/list-archives/gmp-devel/attachments/20200829/aebda025/attachment-0001.bin>


More information about the gmp-devel mailing list