@@ -434,6 +434,61 @@ PHP_FUNCTION(bcmod)
434434}
435435/* }}} */
436436
437+ PHP_FUNCTION (bcdivmod )
438+ {
439+ zend_string * left , * right ;
440+ zend_long scale_param ;
441+ bool scale_param_is_null = 1 ;
442+ bc_num first = NULL , second = NULL , quot = NULL , rem = NULL ;
443+ int scale = BCG (bc_precision );
444+
445+ ZEND_PARSE_PARAMETERS_START (2 , 3 )
446+ Z_PARAM_STR (left )
447+ Z_PARAM_STR (right )
448+ Z_PARAM_OPTIONAL
449+ Z_PARAM_LONG_OR_NULL (scale_param , scale_param_is_null )
450+ ZEND_PARSE_PARAMETERS_END ();
451+
452+ if (scale_param_is_null ) {
453+ scale = BCG (bc_precision );
454+ } else if (bcmath_check_scale (scale_param , 3 ) == FAILURE ) {
455+ RETURN_THROWS ();
456+ } else {
457+ scale = (int ) scale_param ;
458+ }
459+
460+ BC_ARENA_SETUP ;
461+
462+ if (php_str2num (& first , left ) == FAILURE ) {
463+ zend_argument_value_error (1 , "is not well-formed" );
464+ goto cleanup ;
465+ }
466+
467+ if (php_str2num (& second , right ) == FAILURE ) {
468+ zend_argument_value_error (2 , "is not well-formed" );
469+ goto cleanup ;
470+ }
471+
472+ if (!bc_divmod (first , second , & quot , & rem , scale )) {
473+ zend_throw_exception_ex (zend_ce_division_by_zero_error , 0 , "Division by zero" );
474+ goto cleanup ;
475+ }
476+
477+ zval z_quot , z_rem ;
478+ ZVAL_STR (& z_quot , bc_num2str_ex (quot , 0 ));
479+ ZVAL_STR (& z_rem , bc_num2str_ex (rem , scale ));
480+
481+ RETVAL_ARR (zend_new_pair (& z_quot , & z_rem ));
482+
483+ cleanup : {
484+ bc_free_num (& first );
485+ bc_free_num (& second );
486+ bc_free_num (& quot );
487+ bc_free_num (& rem );
488+ BC_ARENA_TEARDOWN ;
489+ };
490+ }
491+
437492/* {{{ Returns the value of an arbitrary precision number raised to the power of another reduced by a modulus */
438493PHP_FUNCTION (bcpowmod )
439494{
@@ -1452,6 +1507,65 @@ PHP_METHOD(BcMath_Number, pow)
14521507 bcmath_number_calc_method (INTERNAL_FUNCTION_PARAM_PASSTHRU , ZEND_POW );
14531508}
14541509
1510+ PHP_METHOD (BcMath_Number , divmod )
1511+ {
1512+ zend_object * num_obj = NULL ;
1513+ zend_string * num_str = NULL ;
1514+ zend_long num_lval = 0 ;
1515+ zend_long scale_lval = 0 ;
1516+ bool scale_is_null = true;
1517+
1518+ ZEND_PARSE_PARAMETERS_START (1 , 2 )
1519+ BCMATH_PARAM_NUMBER_OR_STR_OR_LONG (num_obj , bcmath_number_ce , num_str , num_lval );
1520+ Z_PARAM_OPTIONAL
1521+ Z_PARAM_LONG_OR_NULL (scale_lval , scale_is_null );
1522+ ZEND_PARSE_PARAMETERS_END ();
1523+
1524+ bc_num num = NULL ;
1525+ size_t num_full_scale ;
1526+ if (bc_num_from_obj_or_str_or_long_with_err (& num , & num_full_scale , num_obj , num_str , num_lval , 1 ) == FAILURE ) {
1527+ goto fail ;
1528+ }
1529+ if (bcmath_check_scale (scale_lval , 2 ) == FAILURE ) {
1530+ goto fail ;
1531+ }
1532+
1533+ bc_num quot = NULL ;
1534+ bc_num rem = NULL ;
1535+ size_t scale = scale_lval ;
1536+ bcmath_number_obj_t * intern = get_bcmath_number_from_zval (ZEND_THIS );
1537+
1538+ if (scale_is_null ) {
1539+ scale = MAX (intern -> scale , num_full_scale );
1540+ }
1541+
1542+ if (!bc_divmod (intern -> num , num , & quot , & rem , scale )) {
1543+ zend_throw_exception_ex (zend_ce_division_by_zero_error , 0 , "Division by zero" );
1544+ goto fail ;
1545+ }
1546+ bc_rm_trailing_zeros (quot );
1547+ bc_rm_trailing_zeros (rem );
1548+
1549+ if (num_obj == NULL ) {
1550+ bc_free_num (& num );
1551+ }
1552+
1553+ bcmath_number_obj_t * quot_intern = bcmath_number_new_obj (quot , 0 );
1554+ bcmath_number_obj_t * rem_intern = bcmath_number_new_obj (rem , scale );
1555+
1556+ zval z_quot , z_rem ;
1557+ ZVAL_OBJ (& z_quot , & quot_intern -> std );
1558+ ZVAL_OBJ (& z_rem , & rem_intern -> std );
1559+
1560+ RETURN_ARR (zend_new_pair (& z_quot , & z_rem ));
1561+
1562+ fail :
1563+ if (num_obj == NULL ) {
1564+ bc_free_num (& num );
1565+ }
1566+ RETURN_THROWS ();
1567+ }
1568+
14551569PHP_METHOD (BcMath_Number , powmod )
14561570{
14571571 zend_object * exponent_obj = NULL ;
0 commit comments