Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ PHP NEWS
. Implemented partial function application RFC. (Arnaud)

- GMP:
. Added gmp_prevprime(). (Weilin Du, David Carlier)
. Fixed GMP power and shift operators to reject GMP right operands outside
the unsigned long range instead of silently truncating them. (Weilin Du)
. Fixed GMP integer string parsing to reject strings containing NUL bytes
Expand Down
8 changes: 8 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ PHP 8.6 UPGRADE NOTES
- Fileinfo:
. finfo_file() now works with remote streams.

- GMP:
. Added gmp_prevprime() to get the largest prime smaller than the given
number. A ValueError is thrown if no such prime exists. Requires GNU MP
6.3.0 or later.

- Intl:
. Added Locale::getDisplayKeyword() and Locale::getDisplayKeywordValue(),
with the alias of locale_get_display_keyword() and
Expand Down Expand Up @@ -401,6 +406,9 @@ PHP 8.6 UPGRADE NOTES
6. New Functions
========================================

- GMP:
. gmp_prevprime()

- Intl:
. grapheme_strrev()
RFC: https://wiki.php.net/rfc/grapheme_strrev
Expand Down
1 change: 1 addition & 0 deletions ext/gmp/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ if test "$PHP_GMP" != "no"; then
LIBS="$LIBS $GMP_LIBS"
gmp_check=no
AC_CHECK_HEADER([gmp.h], [AC_CHECK_FUNC([__gmpz_rootrem], [gmp_check=yes])])
AC_CHECK_FUNCS([__gmpz_prevprime])
CFLAGS=$CFLAGS_SAVED
LIBS=$LIBS_SAVED

Expand Down
3 changes: 3 additions & 0 deletions ext/gmp/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ ARG_WITH("gmp", "Include GNU MP support.", "no");
if (PHP_GMP != "no") {
if (CHECK_LIB("mpir_a.lib", "gmp", PHP_GMP) &&
CHECK_HEADER("gmp.h", "CFLAGS_GMP", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) {
if (GREP_HEADER("gmp.h", "mpz_prevprime", PHP_GMP + ";" + PHP_PHP_BUILD + "\\include\\mpir")) {
AC_DEFINE('HAVE___GMPZ_PREVPRIME', 1, "Define to 1 if GMP has the 'mpz_prevprime' function.");
}
EXTENSION("gmp", "gmp.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
PHP_INSTALL_HEADERS("ext/gmp", "php_gmp_int.h");
AC_DEFINE('HAVE_GMP', 1, "Define to 1 if the PHP extension 'gmp' is available.");
Expand Down
31 changes: 31 additions & 0 deletions ext/gmp/gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,37 @@ GMP_UNARY_OP_FUNCTION(com);
/* {{{ Finds next prime of a */
GMP_UNARY_OP_FUNCTION(nextprime);

#ifdef HAVE___GMPZ_PREVPRIME
/* {{{ Finds previous prime of a */
ZEND_FUNCTION(gmp_prevprime)
{
mpz_ptr gmpnum_a, gmpnum_result;
int res;

ZEND_PARSE_PARAMETERS_START(1, 1)
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_a)
ZEND_PARSE_PARAMETERS_END();

if (mpz_cmp_ui(gmpnum_a, 2) <= 0) {
/*
* mpz_prevprime() returns 0 when no previous prime exists, which happens
* for operands not greater than 2.
* https://gmplib.org/manual/Number-Theoretic-Functions#index-mpz_005fprevprime
* However. since returning a prime number smaller than 2 is mathemeticaly
* impossible, throwing a ValueError instead is a more widely used solution
* throughout the php code base.
*/
zend_argument_value_error(1, "must be greater than 2");
RETURN_THROWS();
}

INIT_GMP_RETVAL(gmpnum_result);
res = mpz_prevprime(gmpnum_result, gmpnum_a);
ZEND_ASSERT(res);
}
/* }}} */
#endif

/* Add a and b */
GMP_BINARY_OP_FUNCTION(add);
/* Subtract b from a */
Expand Down
4 changes: 4 additions & 0 deletions ext/gmp/gmp.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,8 @@ function gmp_hamdist(GMP|int|string $num1, GMP|int|string $num2): int {}

function gmp_nextprime(GMP|int|string $num): GMP {}

#ifdef HAVE___GMPZ_PREVPRIME
function gmp_prevprime(GMP|int|string $num): GMP {}
#endif

function gmp_binomial(GMP|int|string $n, int $k): GMP {}
14 changes: 13 additions & 1 deletion ext/gmp/gmp_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions ext/gmp/tests/bug80560.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ $functions1 = [
'gmp_com',
'gmp_nextprime',
];
if (function_exists('gmp_prevprime')) {
$functions1[] = 'gmp_prevprime';
}
$functions1_need_int_2 = [
'gmp_testbit',
'gmp_scan0',
Expand Down
34 changes: 34 additions & 0 deletions ext/gmp/tests/gh13661.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
gmp_prevprime()
--EXTENSIONS--
gmp
--SKIPIF--
<?php
if (!function_exists('gmp_prevprime')) {
die('skip gmp_prevprime() is not available');
}
?>
--FILE--
<?php

foreach ([-1, 0, 1, 2] as $value) {
try {
var_dump(gmp_prevprime($value));
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
}

var_dump(gmp_strval(gmp_prevprime(3)));
var_dump(gmp_strval(gmp_prevprime(4)));
var_dump(gmp_strval(gmp_prevprime(10000)));

?>
--EXPECT--
gmp_prevprime(): Argument #1 ($num) must be greater than 2
gmp_prevprime(): Argument #1 ($num) must be greater than 2
gmp_prevprime(): Argument #1 ($num) must be greater than 2
gmp_prevprime(): Argument #1 ($num) must be greater than 2
string(1) "2"
string(1) "3"
string(4) "9973"