diff --git a/NEWS b/NEWS index a87e4e0804675..8dcad6a6e8473 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - BCMath: . Fixed LONG_MAX in BCMath ext. (Saki Takamachi) . Fixed bcdiv() div by one. (Saki Takamachi) + . [RFC] Support object types in BCMath. (Saki Takamachi) - Core: . Fixed bug GH-15330 (Do not scan generator frames more than once). (Arnaud) diff --git a/UPGRADING b/UPGRADING index a037d8afd46d2..85e598ba896a1 100644 --- a/UPGRADING +++ b/UPGRADING @@ -873,6 +873,15 @@ PHP 8.4 UPGRADE NOTES 7. New Classes and Interfaces ======================================== +- BCMath: + . Added BcMath\Number class. It is an immutable object, has methods that are + equivalent to existing BCMath calculation functions, and can also be calculated + using operators. + The existing BCMath function returned a string for each calculation, but this + class returns an object. + RFC: https://wiki.php.net/rfc/support_object_type_in_bcmath, + https://wiki.php.net/rfc/fix_up_bcmath_number_class + - Core: . New RequestParseBodyException. RFC: https://wiki.php.net/rfc/rfc1867-non-post diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index ec1cba2f7771f..08f6b7c14cb90 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -24,6 +24,7 @@ #include "php_ini.h" #include "zend_exceptions.h" +#include "zend_interfaces.h" #include "bcmath_arginfo.h" #include "ext/standard/info.h" #include "php_bcmath.h" @@ -116,10 +117,13 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath) } /* }}} */ +static void bcmath_number_register_class(void); + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(bcmath) { REGISTER_INI_ENTRIES(); + bcmath_number_register_class(); return SUCCESS; } @@ -144,16 +148,26 @@ PHP_MINFO_FUNCTION(bcmath) } /* }}} */ -/* {{{ php_str2num - Convert to bc_num detecting scale */ -static zend_result php_str2num(bc_num *num, const zend_string *str) +static void php_long2num(bc_num *num, zend_long lval) +{ + *num = bc_long2num(lval); +} + +static zend_result php_str2num_ex(bc_num *num, const zend_string *str, size_t *full_scale) { - if (!bc_str2num(num, ZSTR_VAL(str), ZSTR_VAL(str) + ZSTR_LEN(str), 0, true)) { + if (!bc_str2num(num, ZSTR_VAL(str), ZSTR_VAL(str) + ZSTR_LEN(str), 0, full_scale, true)) { return FAILURE; } return SUCCESS; } + +/* {{{ php_str2num + Convert to bc_num detecting scale */ +static zend_result php_str2num(bc_num *num, const zend_string *str) +{ + return php_str2num_ex(num, str, NULL); +} /* }}} */ /* {{{ Returns the sum of two arbitrary precision numbers */ @@ -628,12 +642,12 @@ PHP_FUNCTION(bccomp) BC_ARENA_SETUP; - if (!bc_str2num(&first, ZSTR_VAL(left), ZSTR_VAL(left) + ZSTR_LEN(left), scale, false)) { + if (!bc_str2num(&first, ZSTR_VAL(left), ZSTR_VAL(left) + ZSTR_LEN(left), scale, NULL, false)) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; } - if (!bc_str2num(&second, ZSTR_VAL(right), ZSTR_VAL(right) + ZSTR_LEN(right), scale, false)) { + if (!bc_str2num(&second, ZSTR_VAL(right), ZSTR_VAL(right) + ZSTR_LEN(right), scale, NULL, false)) { zend_argument_value_error(2, "is not well-formed"); goto cleanup; } @@ -777,4 +791,943 @@ PHP_FUNCTION(bcscale) /* }}} */ + +static zend_class_entry *bcmath_number_ce; +static zend_object_handlers bcmath_number_obj_handlers; + +static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zval *op1, zval *op2); +static int bcmath_number_compare(zval *op1, zval *op2); + +#if SIZEOF_SIZE_T >= 8 +# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX) +#else +# define CHECK_RET_SCALE_OVERFLOW(scale, origin_scale) (scale > INT_MAX || scale < origin_scale) +#endif + +static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_obj(const zend_object *obj) +{ + return (bcmath_number_obj_t*)((char*)(obj) - XtOffsetOf(bcmath_number_obj_t, std)); +} + +static zend_always_inline bcmath_number_obj_t *get_bcmath_number_from_zval(const zval *zv) +{ + return get_bcmath_number_from_obj(Z_OBJ_P(zv)); +} + +static zend_always_inline zend_string *bcmath_number_value_to_str(bcmath_number_obj_t *intern) +{ + if (intern->value == NULL) { + intern->value = bc_num2str_ex(intern->num, intern->scale); + } + return intern->value; +} + +static zend_object *bcmath_number_create(zend_class_entry *ce) +{ + bcmath_number_obj_t *intern = zend_object_alloc(sizeof(bcmath_number_obj_t), ce); + + zend_object_std_init(&intern->std, ce); + object_properties_init(&intern->std, ce); + + intern->scale = 1; + + return &intern->std; +} + +static void bcmath_number_free(zend_object *obj) +{ + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + if (intern->num) { + bc_free_num(&intern->num); + intern->num = NULL; + } + if (intern->value) { + zend_string_release(intern->value); + intern->value = NULL; + } + zend_object_std_dtor(&intern->std); +} + +static zend_object *bcmath_number_clone(zend_object *obj) +{ + bcmath_number_obj_t *original = get_bcmath_number_from_obj(obj); + bcmath_number_obj_t *clone = get_bcmath_number_from_obj(bcmath_number_create(bcmath_number_ce)); + + clone->num = bc_copy_num(original->num); + if (original->value) { + clone->value = zend_string_copy(original->value); + } + clone->scale = original->scale; + + return &clone->std; +} + +static HashTable *bcmath_number_get_properties_for(zend_object *obj, zend_prop_purpose purpose) +{ + zval zv; + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + HashTable *props = zend_array_dup(zend_std_get_properties(obj)); + + ZVAL_STR_COPY(&zv, bcmath_number_value_to_str(intern)); + zend_hash_update(props, ZSTR_KNOWN(ZEND_STR_VALUE), &zv); + ZVAL_LONG(&zv, intern->scale); + zend_hash_str_update(props, ZEND_STRL("scale"), &zv); + + return props; +} + +static zval *bcmath_number_write_property(zend_object *obj, zend_string *name, zval *value, void **cache_slot) +{ + if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale")) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(obj->ce->name), ZSTR_VAL(name)); + return &EG(error_zval); + } + + return zend_std_write_property(obj, name, value, cache_slot); +} + +static void bcmath_number_unset_property(zend_object *obj, zend_string *name, void **cache_slot) +{ + if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale")) { + zend_throw_error(NULL, "Cannot unset readonly property %s::$%s", ZSTR_VAL(obj->ce->name), ZSTR_VAL(name)); + return; + } + + zend_std_unset_property(obj, name, cache_slot); +} + +static zval *bcmath_number_read_property(zend_object *obj, zend_string *name, int type, void **cache_slot, zval *rv) +{ + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + + if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE))) { + ZVAL_STR_COPY(rv, bcmath_number_value_to_str(intern)); + return rv; + } + + if (zend_string_equals_literal(name, "scale")) { + ZVAL_LONG(rv, intern->scale); + return rv; + } + + return zend_std_read_property(obj, name, type, cache_slot, rv); +} + +static int bcmath_number_has_property(zend_object *obj, zend_string *name, int check_empty, void **cache_slot) +{ + if (check_empty == ZEND_PROPERTY_NOT_EMPTY) { + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + + if (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE))) { + return !bc_is_zero(intern->num); + } + + if (zend_string_equals_literal(name, "scale")) { + return intern->scale != 0; + } + } + return zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_VALUE)) || zend_string_equals_literal(name, "scale"); +} + +static zend_result bcmath_number_cast_object(zend_object *obj, zval *ret, int type) +{ + if (type == _IS_BOOL) { + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + ZVAL_BOOL(ret, !bc_is_zero(intern->num)); + return SUCCESS; + } + + return zend_std_cast_object_tostring(obj, ret, type); +} + +static void bcmath_number_register_class(void) +{ + bcmath_number_ce = register_class_BcMath_Number(zend_ce_stringable); + bcmath_number_ce->create_object = bcmath_number_create; + bcmath_number_ce->default_object_handlers = &bcmath_number_obj_handlers; + + memcpy(&bcmath_number_obj_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + bcmath_number_obj_handlers.offset = XtOffsetOf(bcmath_number_obj_t, std); + bcmath_number_obj_handlers.free_obj = bcmath_number_free; + bcmath_number_obj_handlers.clone_obj = bcmath_number_clone; + bcmath_number_obj_handlers.do_operation = bcmath_number_do_operation; + bcmath_number_obj_handlers.compare = bcmath_number_compare; + bcmath_number_obj_handlers.write_property = bcmath_number_write_property; + bcmath_number_obj_handlers.unset_property = bcmath_number_unset_property; + bcmath_number_obj_handlers.has_property = bcmath_number_has_property; + bcmath_number_obj_handlers.read_property = bcmath_number_read_property; + bcmath_number_obj_handlers.get_properties_for = bcmath_number_get_properties_for; + bcmath_number_obj_handlers.cast_object = bcmath_number_cast_object; +} + +static zend_always_inline void bcmath_number_add_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale +) { + if (auto_scale) { + *scale = MAX(n1_full_scale, n2_full_scale); + } + *ret = bc_add(n1, n2, *scale); + (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + bc_rm_trailing_zeros(*ret); +} + +static zend_always_inline void bcmath_number_sub_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale +) { + if (auto_scale) { + *scale = MAX(n1_full_scale, n2_full_scale); + } + *ret = bc_sub(n1, n2, *scale); + (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + bc_rm_trailing_zeros(*ret); +} + +static zend_always_inline zend_result bcmath_number_mul_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale +) { + if (auto_scale) { + *scale = n1_full_scale + n2_full_scale; + if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) { + zend_value_error("scale of the result is too large"); + return FAILURE; + } + } + *ret = bc_multiply(n1, n2, *scale); + (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + bc_rm_trailing_zeros(*ret); + return SUCCESS; +} + +static zend_always_inline zend_result bcmath_number_div_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t *scale, bool auto_scale +) { + if (auto_scale) { + *scale = n1_full_scale + BC_MATH_NUMBER_EXPAND_SCALE; + if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) { + zend_value_error("scale of the result is too large"); + return FAILURE; + } + } + if (!bc_divide(n1, n2, ret, *scale)) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero"); + return FAILURE; + } + bc_rm_trailing_zeros(*ret); + if (auto_scale) { + size_t diff = *scale - (*ret)->n_scale; + *scale -= diff > BC_MATH_NUMBER_EXPAND_SCALE ? BC_MATH_NUMBER_EXPAND_SCALE : diff; + } + return SUCCESS; +} + +static zend_always_inline zend_result bcmath_number_mod_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t n2_full_scale, size_t *scale, bool auto_scale +) { + if (auto_scale) { + *scale = MAX(n1_full_scale, n2_full_scale); + } + if (!bc_modulo(n1, n2, ret, *scale)) { + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); + return FAILURE; + } + bc_rm_trailing_zeros(*ret); + return SUCCESS; +} + +static zend_result bcmath_number_pow_internal( + bc_num n1, bc_num n2, bc_num *ret, + size_t n1_full_scale, size_t *scale, bool auto_scale, bool is_op +) { + /* Check the exponent for scale digits and convert to a long. */ + if (UNEXPECTED(n2->n_scale != 0)) { + if (is_op) { + zend_value_error("exponent cannot have a fractional part"); + } else { + zend_argument_value_error(1, "exponent cannot have a fractional part"); + } + return FAILURE; + } + long exponent = bc_num2long(n2); + + bool scale_expand = false; + if (auto_scale) { + if (exponent > 0) { + *scale = n1_full_scale * exponent; + if (UNEXPECTED(*scale > INT_MAX || *scale < n1_full_scale)) { + zend_value_error("scale of the result is too large"); + return FAILURE; + } + } else if (exponent < 0) { + *scale = n1_full_scale + BC_MATH_NUMBER_EXPAND_SCALE; + if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(*scale, n1_full_scale))) { + zend_value_error("scale of the result is too large"); + return FAILURE; + } + scale_expand = true; + } else { + *scale = 0; + } + } + + /** + * bc_num2long() returns 0 if exponent is too large. + * Here, if n2->n_value is not 0 but exponent is 0, it is considered too large. + */ + if (UNEXPECTED(exponent == 0 && (n2->n_len > 1 || n2->n_value[0] != 0))) { + if (is_op) { + zend_value_error("exponent is too large"); + } else { + zend_argument_value_error(1, "exponent is too large"); + } + return FAILURE; + } + bc_raise(n1, exponent, ret, *scale); + bc_rm_trailing_zeros(*ret); + if (scale_expand) { + size_t diff = *scale - (*ret)->n_scale; + *scale -= diff > BC_MATH_NUMBER_EXPAND_SCALE ? BC_MATH_NUMBER_EXPAND_SCALE : diff; + } + return SUCCESS; +} + +static zend_always_inline bcmath_number_obj_t *bcmath_number_new_obj(bc_num ret, size_t scale) +{ + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(bcmath_number_create(bcmath_number_ce)); + intern->num = ret; + intern->scale = scale; + return intern; +} + +static zend_result bcmath_number_parse_num(zval *zv, zend_object **obj, zend_string **str, zend_long *lval) +{ + if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), bcmath_number_ce)) { + *obj = Z_OBJ_P(zv); + return SUCCESS; + } else { + switch (Z_TYPE_P(zv)) { + case IS_LONG: + *lval = Z_LVAL_P(zv); + return SUCCESS; + + case IS_STRING: + *str = Z_STR_P(zv); + return SUCCESS; + + case IS_NULL: + *lval = 0; + return SUCCESS; + + default: + return zend_parse_arg_str_or_long_slow(zv, str, lval, 1 /* dummy */) ? SUCCESS : FAILURE; + } + } +} + +static zend_result bc_num_from_obj_or_str_or_long( + bc_num *num, size_t *full_scale, const zend_object *obj, const zend_string *str, zend_long lval) +{ + if (obj) { + bcmath_number_obj_t *intern = get_bcmath_number_from_obj(obj); + *num = intern->num; + if (full_scale) { + *full_scale = intern->scale; + } + return SUCCESS; + } else if (str) { + return php_str2num_ex(num, str, full_scale); + } else { + php_long2num(num, lval); + if (full_scale) { + *full_scale = 0; + } + return SUCCESS; + } +} + +static zend_result bcmath_number_do_operation(uint8_t opcode, zval *ret_val, zval *op1, zval *op2) +{ + switch (opcode) { + case ZEND_ADD: + case ZEND_SUB: + case ZEND_MUL: + case ZEND_DIV: + case ZEND_MOD: + case ZEND_POW: + break; + default: + return FAILURE; + } + + zend_object *obj1 = NULL; + zend_string *str1 = NULL; + zend_long lval1 = 0; + + zend_object *obj2 = NULL; + zend_string *str2 = NULL; + zend_long lval2 = 0; + + if (UNEXPECTED(bcmath_number_parse_num(op1, &obj1, &str1, &lval1) == FAILURE || bcmath_number_parse_num(op2, &obj2, &str2, &lval2) == FAILURE)) { + return FAILURE; + } + + bc_num n1 = NULL; + bc_num n2 = NULL; + size_t n1_full_scale; + size_t n2_full_scale; + if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, &n1_full_scale, obj1, str1, lval1) == FAILURE || + bc_num_from_obj_or_str_or_long(&n2, &n2_full_scale, obj2, str2, lval2) == FAILURE)) { + zend_value_error("Number is not well-formed"); + goto fail; + } + + bc_num ret = NULL; + size_t scale; + switch (opcode) { + case ZEND_ADD: + bcmath_number_add_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true); + break; + case ZEND_SUB: + bcmath_number_sub_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true); + break; + case ZEND_MUL: + if (UNEXPECTED(bcmath_number_mul_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true) == FAILURE)) { + goto fail; + } + break; + case ZEND_DIV: + if (UNEXPECTED(bcmath_number_div_internal(n1, n2, &ret, n1_full_scale, &scale, true) == FAILURE)) { + goto fail; + } + break; + case ZEND_MOD: + if (UNEXPECTED(bcmath_number_mod_internal(n1, n2, &ret, n1_full_scale, n2_full_scale, &scale, true) == FAILURE)) { + goto fail; + } + break; + case ZEND_POW: + if (UNEXPECTED(bcmath_number_pow_internal(n1, n2, &ret, n1_full_scale, &scale, true, true) == FAILURE)) { + goto fail; + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + if (Z_TYPE_P(op1) != IS_OBJECT) { + bc_free_num(&n1); + } + if (Z_TYPE_P(op2) != IS_OBJECT) { + bc_free_num(&n2); + } + + bcmath_number_obj_t *intern = bcmath_number_new_obj(ret, scale); + + /* For increment and decrement, etc */ + if (ret_val == op1) { + zval_ptr_dtor(ret_val); + } + ZVAL_OBJ(ret_val, &intern->std); + + return SUCCESS; + +fail: + if (Z_TYPE_P(op1) != IS_OBJECT) { + bc_free_num(&n1); + } + if (Z_TYPE_P(op2) != IS_OBJECT) { + bc_free_num(&n2); + } + return FAILURE; +} + +static int bcmath_number_compare(zval *op1, zval *op2) +{ + zend_object *obj1 = NULL; + zend_string *str1 = NULL; + zend_long lval1 = 0; + + zend_object *obj2 = NULL; + zend_string *str2 = NULL; + zend_long lval2 = 0; + + bc_num n1 = NULL; + bc_num n2 = NULL; + + if (UNEXPECTED(bcmath_number_parse_num(op1, &obj1, &str1, &lval1) == FAILURE)) { + goto fallback; + } + + if (UNEXPECTED(bcmath_number_parse_num(op2, &obj2, &str2, &lval2) == FAILURE)) { + goto fallback; + } + + if (UNEXPECTED(bc_num_from_obj_or_str_or_long(&n1, NULL, obj1, str1, lval1) == FAILURE || + bc_num_from_obj_or_str_or_long(&n2, NULL, obj2, str2, lval2) == FAILURE)) { + goto fallback; + } + + bcmath_compare_result ret = bc_compare(n1, n2, MAX(n1->n_scale, n2->n_scale)); + + if (Z_TYPE_P(op1) != IS_OBJECT) { + bc_free_num(&n1); + } + if (Z_TYPE_P(op2) != IS_OBJECT) { + bc_free_num(&n2); + } + + return (int) ret; + +fallback: + return zend_std_compare_objects(op1, op2); +} + +#define BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(dest_obj, ce, dest_str, dest_long) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!(zend_parse_arg_obj(_arg, &(dest_obj), ce, 0) || \ + zend_parse_arg_str_or_long(_arg, &(dest_str), &(dest_long), &_dummy, 0, _i)))) { \ + zend_argument_type_error(_i, "must be of type int, string, or %s, %s given", \ + ZSTR_VAL(bcmath_number_ce->name), zend_zval_value_name(_arg)); \ + _error_code = ZPP_ERROR_FAILURE; \ + break; \ + } + +static zend_always_inline zend_result bc_num_from_obj_or_str_or_long_with_err( + bc_num *num, size_t *scale, zend_object *obj, zend_string *str, zend_long lval, uint32_t arg_num) +{ + if (UNEXPECTED(bc_num_from_obj_or_str_or_long(num, scale, obj, str, lval) == FAILURE)) { + zend_argument_value_error(arg_num, "is not well-formed"); + return FAILURE; + } + return SUCCESS; +} + +static zend_always_inline zend_result bcmath_check_scale(zend_long scale, bool scale_is_null, uint32_t arg_num) +{ + if (UNEXPECTED(!scale_is_null && (scale < 0 || scale > INT_MAX))) { + zend_argument_value_error(arg_num, "must be between 0 and %d", INT_MAX); + return FAILURE; + } + return SUCCESS; +} + +PHP_METHOD(BcMath_Number, __construct) +{ + zend_string *str = NULL; + zend_long lval = 0; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR_OR_LONG(str, lval); + ZEND_PARSE_PARAMETERS_END(); + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + if (UNEXPECTED(intern->num != NULL)) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(bcmath_number_ce->name), "value"); + RETURN_THROWS(); + } + + bc_num num = NULL; + size_t scale; + if (bc_num_from_obj_or_str_or_long_with_err(&num, &scale, NULL, str, lval, 1) == FAILURE) { + bc_free_num(&num); + RETURN_THROWS(); + } + + intern->num = num; + intern->scale = scale; +} + +static void bcmath_number_calc_method(INTERNAL_FUNCTION_PARAMETERS, uint8_t opcode) +{ + zend_object *num_obj = NULL; + zend_string *num_str = NULL; + zend_long num_lval = 0; + zend_long scale_lval = 0; + bool scale_is_null = true; + + ZEND_PARSE_PARAMETERS_START(1, 2) + BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(num_obj, bcmath_number_ce, num_str, num_lval); + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null); + ZEND_PARSE_PARAMETERS_END(); + + bc_num num = NULL; + size_t num_full_scale; + if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) { + goto fail; + } + if (bcmath_check_scale(scale_lval, scale_is_null, 2) == FAILURE) { + goto fail; + } + + bc_num ret = NULL; + size_t scale = scale_lval; + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + + switch (opcode) { + case ZEND_ADD: + bcmath_number_add_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null); + break; + case ZEND_SUB: + bcmath_number_sub_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null); + break; + case ZEND_MUL: + if (UNEXPECTED(bcmath_number_mul_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null) == FAILURE)) { + goto fail; + } + break; + case ZEND_DIV: + if (UNEXPECTED(bcmath_number_div_internal(intern->num, num, &ret, intern->scale, &scale, scale_is_null) == FAILURE)) { + goto fail; + } + break; + case ZEND_MOD: + if (UNEXPECTED(bcmath_number_mod_internal(intern->num, num, &ret, intern->scale, num_full_scale, &scale, scale_is_null) == FAILURE)) { + goto fail; + } + break; + case ZEND_POW: + if (UNEXPECTED(bcmath_number_pow_internal(intern->num, num, &ret, intern->scale, &scale, scale_is_null, false) == FAILURE)) { + goto fail; + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + if (num_obj == NULL) { + bc_free_num(&num); + } + + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale); + RETURN_OBJ(&new_intern->std); + +fail: + if (num_obj == NULL) { + bc_free_num(&num); + } + RETURN_THROWS(); +} + +PHP_METHOD(BcMath_Number, add) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ADD); +} + +PHP_METHOD(BcMath_Number, sub) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_SUB); +} + +PHP_METHOD(BcMath_Number, mul) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_MUL); +} + +PHP_METHOD(BcMath_Number, div) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_DIV); +} + +PHP_METHOD(BcMath_Number, mod) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_MOD); +} + +PHP_METHOD(BcMath_Number, pow) +{ + bcmath_number_calc_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_POW); +} + +PHP_METHOD(BcMath_Number, powmod) +{ + zend_object *exponent_obj = NULL; + zend_string *exponent_str = NULL; + zend_long exponent_lval = 0; + + zend_object *modulus_obj = NULL; + zend_string *modulus_str = NULL; + zend_long modulus_lval = 0; + + zend_long scale_lval = 0; + bool scale_is_null = true; + + ZEND_PARSE_PARAMETERS_START(2, 3) + BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(exponent_obj, bcmath_number_ce, exponent_str, exponent_lval); + BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(modulus_obj, bcmath_number_ce, modulus_str, modulus_lval); + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null); + ZEND_PARSE_PARAMETERS_END(); + + bc_num exponent_num = NULL; + bc_num modulus_num = NULL; + if (bc_num_from_obj_or_str_or_long_with_err(&exponent_num, NULL, exponent_obj, exponent_str, exponent_lval, 1) == FAILURE) { + goto cleanup; + } + if (bc_num_from_obj_or_str_or_long_with_err(&modulus_num, NULL, modulus_obj, modulus_str, modulus_lval, 2) == FAILURE) { + goto cleanup; + } + if (bcmath_check_scale(scale_lval, scale_is_null, 3) == FAILURE) { + goto cleanup; + } + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + bc_num ret = NULL; + size_t scale = scale_lval; + raise_mod_status status = bc_raisemod(intern->num, exponent_num, modulus_num, &ret, scale); + switch (status) { + case BASE_HAS_FRACTIONAL: + zend_value_error("Base number cannot have a fractional part"); + goto cleanup; + case EXPO_HAS_FRACTIONAL: + zend_argument_value_error(1, "cannot have a fractional part"); + goto cleanup; + case EXPO_IS_NEGATIVE: + zend_argument_value_error(1, "must be greater than or equal to 0"); + goto cleanup; + case MOD_HAS_FRACTIONAL: + zend_argument_value_error(2, "cannot have a fractional part"); + goto cleanup; + case MOD_IS_ZERO: + zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero"); + goto cleanup; + case OK: + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + + bc_rm_trailing_zeros(ret); + + if (exponent_obj == NULL) { + bc_free_num(&exponent_num); + } + if (modulus_obj == NULL) { + bc_free_num(&modulus_num); + } + + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale); + RETURN_OBJ(&new_intern->std); + +cleanup: + if (exponent_obj == NULL) { + bc_free_num(&exponent_num); + } + if (modulus_obj == NULL) { + bc_free_num(&modulus_num); + } + RETURN_THROWS(); +} + +PHP_METHOD(BcMath_Number, sqrt) +{ + zend_long scale_lval = 0; + bool scale_is_null = true; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null); + ZEND_PARSE_PARAMETERS_END(); + + if (bcmath_check_scale(scale_lval, scale_is_null, 1) == FAILURE) { + RETURN_THROWS(); + } + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + + size_t scale; + if (scale_is_null) { + scale = intern->scale + BC_MATH_NUMBER_EXPAND_SCALE; + if (UNEXPECTED(CHECK_RET_SCALE_OVERFLOW(scale, intern->scale))) { + zend_value_error("scale of the result is too large"); + RETURN_THROWS(); + } + } else { + scale = scale_lval; + } + + bc_num ret = bc_copy_num(intern->num); + if (!bc_sqrt (&ret, scale)) { + zend_value_error("Base number must be greater than or equal to 0"); + bc_free_num(&ret); + RETURN_THROWS(); + } + + ret->n_scale = MIN(scale, ret->n_scale); + bc_rm_trailing_zeros(ret); + if (scale_is_null) { + size_t diff = scale - ret->n_scale; + scale -= diff > BC_MATH_NUMBER_EXPAND_SCALE ? BC_MATH_NUMBER_EXPAND_SCALE : diff; + } + + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale); + RETURN_OBJ(&new_intern->std); +} + +PHP_METHOD(BcMath_Number, compare) +{ + zend_object *num_obj = NULL; + zend_string *num_str = NULL; + zend_long num_lval = 0; + zend_long scale_lval = 0; + bool scale_is_null = true; + + ZEND_PARSE_PARAMETERS_START(1, 2) + BCMATH_PARAM_NUMBER_OR_STR_OR_LONG(num_obj, bcmath_number_ce, num_str, num_lval); + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(scale_lval, scale_is_null); + ZEND_PARSE_PARAMETERS_END(); + + bc_num num = NULL; + size_t num_full_scale; + if (bc_num_from_obj_or_str_or_long_with_err(&num, &num_full_scale, num_obj, num_str, num_lval, 1) == FAILURE) { + goto fail; + } + if (bcmath_check_scale(scale_lval, scale_is_null, 2) == FAILURE) { + goto fail; + } + + size_t scale; + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + if (scale_is_null) { + scale = MAX(intern->num->n_scale, num->n_scale); + } else { + scale = scale_lval; + } + zend_long ret = bc_compare(intern->num, num, scale); + + if (num_obj == NULL) { + bc_free_num(&num); + } + RETURN_LONG(ret); + +fail: + if (num_obj == NULL) { + bc_free_num(&num); + } + RETURN_THROWS(); +} + +static void bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + + bc_num ret = bc_floor_or_ceil(intern->num, is_floor); + + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, 0); + RETURN_OBJ(&new_intern->std); +} + +PHP_METHOD(BcMath_Number, floor) +{ + bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); +} + +PHP_METHOD(BcMath_Number, ceil) +{ + bcmath_number_floor_or_ceil(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); +} + +PHP_METHOD(BcMath_Number, round) +{ + zend_long precision = 0; + zend_long rounding_mode = PHP_ROUND_HALF_UP; + zend_object *mode_object = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(precision); + Z_PARAM_OBJ_OF_CLASS(mode_object, rounding_mode_ce); + ZEND_PARSE_PARAMETERS_END(); + + if (mode_object != NULL) { + rounding_mode = php_math_round_mode_from_enum(mode_object); + } + + switch (rounding_mode) { + case PHP_ROUND_HALF_UP: + case PHP_ROUND_HALF_DOWN: + case PHP_ROUND_HALF_EVEN: + case PHP_ROUND_HALF_ODD: + case PHP_ROUND_CEILING: + case PHP_ROUND_FLOOR: + case PHP_ROUND_TOWARD_ZERO: + case PHP_ROUND_AWAY_FROM_ZERO: + break; + default: + zend_argument_value_error(2, "is an unsupported rounding mode"); + RETURN_THROWS(); + } + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + + bc_num ret = NULL; + bc_round(intern->num, precision, rounding_mode, &ret); + + bc_rm_trailing_zeros(ret); + + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, ret->n_scale); + RETURN_OBJ(&new_intern->std); +} + +PHP_METHOD(BcMath_Number, __toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + RETURN_STR_COPY(bcmath_number_value_to_str(intern)); +} + +PHP_METHOD(BcMath_Number, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + + array_init(return_value); + HashTable *props = Z_ARRVAL_P(return_value); + + zval zv; + ZVAL_STR_COPY(&zv, bcmath_number_value_to_str(intern)); + zend_hash_update(props, ZSTR_KNOWN(ZEND_STR_VALUE), &zv); +} + +PHP_METHOD(BcMath_Number, __unserialize) +{ + HashTable *props; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(props) + ZEND_PARSE_PARAMETERS_END(); + + zval *zv = zend_hash_find(props, ZSTR_KNOWN(ZEND_STR_VALUE)); + if (!zv || Z_TYPE_P(zv) != IS_STRING || Z_STRLEN_P(zv) == 0) { + goto fail; + } + + bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); + if (UNEXPECTED(intern->num != NULL)) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(bcmath_number_ce->name), "value"); + RETURN_THROWS(); + } + + bc_num num = NULL; + size_t scale; + if (php_str2num_ex(&num, Z_STR_P(zv), &scale) == FAILURE) { + bc_free_num(&num); + goto fail; + } + + intern->num = num; + intern->scale = scale; + + return; + +fail: + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(bcmath_number_ce->name)); + RETURN_THROWS(); +} + #endif diff --git a/ext/bcmath/bcmath.stub.php b/ext/bcmath/bcmath.stub.php index eabc0a1042a1b..79c1569e8462a 100644 --- a/ext/bcmath/bcmath.stub.php +++ b/ext/bcmath/bcmath.stub.php @@ -2,39 +2,86 @@ /** @generate-class-entries */ -/** @refcount 1 */ -function bcadd(string $num1, string $num2, ?int $scale = null): string {} +namespace +{ + /** @refcount 1 */ + function bcadd(string $num1, string $num2, ?int $scale = null): string {} -/** @refcount 1 */ -function bcsub(string $num1, string $num2, ?int $scale = null): string {} + /** @refcount 1 */ + function bcsub(string $num1, string $num2, ?int $scale = null): string {} -/** @refcount 1 */ -function bcmul(string $num1, string $num2, ?int $scale = null): string {} + /** @refcount 1 */ + function bcmul(string $num1, string $num2, ?int $scale = null): string {} -/** @refcount 1 */ -function bcdiv(string $num1, string $num2, ?int $scale = null): string {} + /** @refcount 1 */ + function bcdiv(string $num1, string $num2, ?int $scale = null): string {} -/** @refcount 1 */ -function bcmod(string $num1, string $num2, ?int $scale = null): string {} + /** @refcount 1 */ + function bcmod(string $num1, string $num2, ?int $scale = null): string {} -/** @refcount 1 */ -function bcpowmod(string $num, string $exponent, string $modulus, ?int $scale = null): string {} + /** @refcount 1 */ + function bcpowmod(string $num, string $exponent, string $modulus, ?int $scale = null): string {} -/** @refcount 1 */ -function bcpow(string $num, string $exponent, ?int $scale = null): string {} + /** @refcount 1 */ + function bcpow(string $num, string $exponent, ?int $scale = null): string {} -/** @refcount 1 */ -function bcsqrt(string $num, ?int $scale = null): string {} + /** @refcount 1 */ + function bcsqrt(string $num, ?int $scale = null): string {} -function bccomp(string $num1, string $num2, ?int $scale = null): int {} + function bccomp(string $num1, string $num2, ?int $scale = null): int {} -function bcscale(?int $scale = null): int {} + function bcscale(?int $scale = null): int {} -/** @refcount 1 */ -function bcfloor(string $num): string {} + /** @refcount 1 */ + function bcfloor(string $num): string {} -/** @refcount 1 */ -function bcceil(string $num): string {} + /** @refcount 1 */ + function bcceil(string $num): string {} -/** @refcount 1 */ -function bcround(string $num, int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero): string {} + /** @refcount 1 */ + function bcround(string $num, int $precision = 0, RoundingMode $mode = RoundingMode::HalfAwayFromZero): string {} +} + +namespace BcMath +{ + /** @strict-properties */ + final readonly class Number implements \Stringable + { + /** @virtual */ + public string $value; + /** @virtual */ + public int $scale; + + public function __construct(string|int $num) {} + + public function add(Number|string|int $num, ?int $scale = null): Number {} + + public function sub(Number|string|int $num, ?int $scale = null): Number {} + + public function mul(Number|string|int $num, ?int $scale = null): Number {} + + public function div(Number|string|int $num, ?int $scale = null): Number {} + + public function mod(Number|string|int $num, ?int $scale = null): Number {} + + public function powmod(Number|string|int $exponent, Number|string|int $modulus, ?int $scale = null): Number {} + + public function pow(Number|string|int $exponent, ?int $scale = null): Number {} + + public function sqrt(?int $scale = null): Number {} + + public function floor(): Number {} + + public function ceil(): Number {} + + public function round(int $precision = 0, \RoundingMode $mode = \RoundingMode::HalfAwayFromZero): Number {} + + public function compare(Number|string|int $num, ?int $scale = null): int {} + + public function __toString(): string {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + } +} diff --git a/ext/bcmath/bcmath_arginfo.h b/ext/bcmath/bcmath_arginfo.h index c3f01527b2b26..12a0fa6800e0c 100644 --- a/ext/bcmath/bcmath_arginfo.h +++ b/ext/bcmath/bcmath_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7439a5fca649b8c4df317b0da1416c8fe59faf72 */ + * Stub hash: f3101bbd25da90d97801d53ea673789d1ce4f6a1 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcadd, 0, 2, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, num1, IS_STRING, 0) @@ -55,6 +55,63 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_bcround, 0, 1, IS_STRING, 0) ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, mode, RoundingMode, 0, "RoundingMode::HalfAwayFromZero") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_BcMath_Number___construct, 0, 0, 1) + ZEND_ARG_TYPE_MASK(0, num, MAY_BE_STRING|MAY_BE_LONG, NULL) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_add, 0, 1, BcMath\\\116umber, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, num, BcMath\\\116umber, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +#define arginfo_class_BcMath_Number_sub arginfo_class_BcMath_Number_add + +#define arginfo_class_BcMath_Number_mul arginfo_class_BcMath_Number_add + +#define arginfo_class_BcMath_Number_div arginfo_class_BcMath_Number_add + +#define arginfo_class_BcMath_Number_mod arginfo_class_BcMath_Number_add + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_powmod, 0, 2, BcMath\\\116umber, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, exponent, BcMath\\\116umber, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_OBJ_TYPE_MASK(0, modulus, BcMath\\\116umber, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_pow, 0, 1, BcMath\\\116umber, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, exponent, BcMath\\\116umber, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_sqrt, 0, 0, BcMath\\\116umber, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_floor, 0, 0, BcMath\\\116umber, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_BcMath_Number_ceil arginfo_class_BcMath_Number_floor + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_BcMath_Number_round, 0, 0, BcMath\\\116umber, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, precision, IS_LONG, 0, "0") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, mode, RoundingMode, 0, "RoundingMode::HalfAwayFromZero") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BcMath_Number_compare, 0, 1, IS_LONG, 0) + ZEND_ARG_OBJ_TYPE_MASK(0, num, BcMath\\\116umber, MAY_BE_STRING|MAY_BE_LONG, NULL) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scale, IS_LONG, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BcMath_Number___toString, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BcMath_Number___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_BcMath_Number___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_FUNCTION(bcadd); ZEND_FUNCTION(bcsub); ZEND_FUNCTION(bcmul); @@ -68,6 +125,22 @@ ZEND_FUNCTION(bcscale); ZEND_FUNCTION(bcfloor); ZEND_FUNCTION(bcceil); ZEND_FUNCTION(bcround); +ZEND_METHOD(BcMath_Number, __construct); +ZEND_METHOD(BcMath_Number, add); +ZEND_METHOD(BcMath_Number, sub); +ZEND_METHOD(BcMath_Number, mul); +ZEND_METHOD(BcMath_Number, div); +ZEND_METHOD(BcMath_Number, mod); +ZEND_METHOD(BcMath_Number, powmod); +ZEND_METHOD(BcMath_Number, pow); +ZEND_METHOD(BcMath_Number, sqrt); +ZEND_METHOD(BcMath_Number, floor); +ZEND_METHOD(BcMath_Number, ceil); +ZEND_METHOD(BcMath_Number, round); +ZEND_METHOD(BcMath_Number, compare); +ZEND_METHOD(BcMath_Number, __toString); +ZEND_METHOD(BcMath_Number, __serialize); +ZEND_METHOD(BcMath_Number, __unserialize); static const zend_function_entry ext_functions[] = { ZEND_FE(bcadd, arginfo_bcadd) @@ -85,3 +158,46 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(bcround, arginfo_bcround) ZEND_FE_END }; + +static const zend_function_entry class_BcMath_Number_methods[] = { + ZEND_ME(BcMath_Number, __construct, arginfo_class_BcMath_Number___construct, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, add, arginfo_class_BcMath_Number_add, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, sub, arginfo_class_BcMath_Number_sub, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, mul, arginfo_class_BcMath_Number_mul, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, div, arginfo_class_BcMath_Number_div, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, mod, arginfo_class_BcMath_Number_mod, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, powmod, arginfo_class_BcMath_Number_powmod, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, pow, arginfo_class_BcMath_Number_pow, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, sqrt, arginfo_class_BcMath_Number_sqrt, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, floor, arginfo_class_BcMath_Number_floor, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, ceil, arginfo_class_BcMath_Number_ceil, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, round, arginfo_class_BcMath_Number_round, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, compare, arginfo_class_BcMath_Number_compare, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, __toString, arginfo_class_BcMath_Number___toString, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, __serialize, arginfo_class_BcMath_Number___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(BcMath_Number, __unserialize, arginfo_class_BcMath_Number___unserialize, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +static zend_class_entry *register_class_BcMath_Number(zend_class_entry *class_entry_Stringable) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "BcMath", "Number", class_BcMath_Number_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS); + zend_class_implements(class_entry, 1, class_entry_Stringable); + + zval property_value_default_value; + ZVAL_UNDEF(&property_value_default_value); + zend_string *property_value_name = zend_string_init("value", sizeof("value") - 1, 1); + zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_value_name); + + zval property_scale_default_value; + ZVAL_UNDEF(&property_scale_default_value); + zend_string *property_scale_name = zend_string_init("scale", sizeof("scale") - 1, 1); + zend_declare_typed_property(class_entry, property_scale_name, &property_scale_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_scale_name); + + return class_entry; +} diff --git a/ext/bcmath/config.m4 b/ext/bcmath/config.m4 index 2617ee0f13503..a29f2af75ca8e 100644 --- a/ext/bcmath/config.m4 +++ b/ext/bcmath/config.m4 @@ -13,6 +13,7 @@ if test "$PHP_BCMATH" != "no"; then libbcmath/src/divmod.c libbcmath/src/doaddsub.c libbcmath/src/floor_or_ceil.c + libbcmath/src/long2num.c libbcmath/src/init.c libbcmath/src/int2num.c libbcmath/src/nearzero.c diff --git a/ext/bcmath/config.w32 b/ext/bcmath/config.w32 index f7346b1942692..74d1b38802eea 100644 --- a/ext/bcmath/config.w32 +++ b/ext/bcmath/config.w32 @@ -5,7 +5,7 @@ ARG_ENABLE("bcmath", "bc style precision math functions", "yes"); if (PHP_BCMATH == "yes") { EXTENSION("bcmath", "bcmath.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_SOURCES("ext/bcmath/libbcmath/src", "add.c div.c init.c neg.c \ - raisemod.c sub.c compare.c divmod.c int2num.c \ + raisemod.c sub.c compare.c divmod.c int2num.c long2num.c \ num2long.c recmul.c sqrt.c zero.c doaddsub.c \ floor_or_ceil.c nearzero.c num2str.c raise.c rmzero.c str2num.c \ round.c convert.c", "bcmath"); diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index 07dd84ff90d11..daf4642e6a323 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -98,7 +98,9 @@ static inline bc_num bc_copy_num(bc_num num) void bc_init_num(bc_num *num); -bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, bool auto_scale); +bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, size_t *full_scale, bool auto_scale); + +bc_num bc_long2num(zend_long lval); zend_string *bc_num2str_ex(bc_num num, size_t scale); @@ -122,6 +124,8 @@ bool bc_is_near_zero(bc_num num, size_t scale); bool bc_is_neg(bc_num num); +void bc_rm_trailing_zeros(bc_num num); + bc_num bc_add(bc_num n1, bc_num n2, size_t scale_min); #define bc_add_ex(n1, n2, result, scale_min) do { \ diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index 662e5600cb263..294a281b2e687 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -70,6 +70,12 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale *quot = quotient; } + /* The value of rscale changes during processing. Here we use the value of scale. It's not a typo. */ + (*rem)->n_scale = MIN(scale, (*rem)->n_scale); + if (bc_is_zero(*rem)) { + (*rem)->n_sign = PLUS; + } + return true; } diff --git a/ext/bcmath/libbcmath/src/long2num.c b/ext/bcmath/libbcmath/src/long2num.c new file mode 100644 index 0000000000000..7645045b1fa36 --- /dev/null +++ b/ext/bcmath/libbcmath/src/long2num.c @@ -0,0 +1,59 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Saki Takamachi | + +----------------------------------------------------------------------+ +*/ + +#include "bcmath.h" +#include +#include "convert.h" + +#define BC_LONG_MAX_DIGITS (sizeof(LONG_MIN_DIGITS) - 1) + +bc_num bc_long2num(zend_long lval) +{ + bc_num num; + + if (UNEXPECTED(lval == 0)) { + num = bc_copy_num(BCG(_zero_)); + return num; + } + + bool negative = lval < 0; + if (UNEXPECTED(lval == ZEND_LONG_MIN)) { + num = bc_new_num_nonzeroed(BC_LONG_MAX_DIGITS, 0); + const char *ptr = LONG_MIN_DIGITS; + bc_copy_and_toggle_bcd(num->n_value, ptr, ptr + BC_LONG_MAX_DIGITS); + num->n_sign = MINUS; + return num; + } else if (negative) { + lval = -lval; + } + + zend_long tmp = lval; + size_t len = 0; + while (tmp > 0) { + tmp /= BASE; + len++; + } + + num = bc_new_num_nonzeroed(len, 0); + char *ptr = num->n_value + len - 1; + for (; len > 0; len--) { + *ptr-- = lval % BASE; + lval /= BASE; + } + num->n_sign = negative ? MINUS : PLUS; + + return num; +} diff --git a/ext/bcmath/libbcmath/src/raise.c b/ext/bcmath/libbcmath/src/raise.c index 390f4d6935c6d..a503e77a1a4a4 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -94,9 +94,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) } else { bc_free_num (result); *result = temp; - if ((*result)->n_scale > rscale) { - (*result)->n_scale = rscale; - } + (*result)->n_scale = MIN(scale, (*result)->n_scale); } bc_free_num (&power); } diff --git a/ext/bcmath/libbcmath/src/rmzero.c b/ext/bcmath/libbcmath/src/rmzero.c index 8228e54f4aa57..9440785d80653 100644 --- a/ext/bcmath/libbcmath/src/rmzero.c +++ b/ext/bcmath/libbcmath/src/rmzero.c @@ -44,3 +44,16 @@ void _bc_rm_leading_zeros(bc_num num) num->n_len--; } } + +void bc_rm_trailing_zeros(bc_num num) +{ + if (num->n_scale == 0) { + return; + } + + char *end = num->n_value + num->n_len + num->n_scale - 1; + while (*end == 0 && num->n_scale > 0) { + num->n_scale--; + end--; + } +} diff --git a/ext/bcmath/libbcmath/src/str2num.c b/ext/bcmath/libbcmath/src/str2num.c index a46ae6a2c9d73..a56fefa02a4c7 100644 --- a/ext/bcmath/libbcmath/src/str2num.c +++ b/ext/bcmath/libbcmath/src/str2num.c @@ -106,7 +106,7 @@ static inline const char *bc_skip_zero_reverse(const char *scanner, const char * } /* Assumes `num` points to NULL, i.e. does yet not hold a number. */ -bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, bool auto_scale) +bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, size_t *full_scale, bool auto_scale) { size_t str_scale = 0; const char *ptr = str; @@ -143,6 +143,9 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo fractional_ptr = fractional_end = decimal_point + 1; /* For strings that end with a decimal point, such as "012." */ if (UNEXPECTED(*fractional_ptr == '\0')) { + if (full_scale) { + *full_scale = 0; + } goto after_fractional; } @@ -153,6 +156,10 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo goto fail; } + if (full_scale) { + *full_scale = fractional_end - fractional_ptr; + } + /* Exclude trailing zeros. */ fractional_end = bc_skip_zero_reverse(fractional_end, fractional_ptr); @@ -167,6 +174,10 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, boo fractional_end -= str_scale - scale; str_scale = scale; } + } else { + if (full_scale) { + *full_scale = 0; + } } after_fractional: diff --git a/ext/bcmath/php_bcmath.h b/ext/bcmath/php_bcmath.h index 77ebcbdb39fa6..6b6098a23945e 100644 --- a/ext/bcmath/php_bcmath.h +++ b/ext/bcmath/php_bcmath.h @@ -45,4 +45,14 @@ ZEND_TSRMLS_CACHE_EXTERN() ZEND_EXTERN_MODULE_GLOBALS(bcmath) #define BCG(v) ZEND_MODULE_GLOBALS_ACCESSOR(bcmath, v) +/* Maximum number of digits to extend when scale needs to be extended, such as in undivisible division */ +#define BC_MATH_NUMBER_EXPAND_SCALE 10 + +typedef struct _bcmath_number_obj_t { + zend_string *value; + size_t scale; + bc_num num; + zend_object std; +} bcmath_number_obj_t; + #endif /* PHP_BCMATH_H */ diff --git a/ext/bcmath/tests/number/cast.phpt b/ext/bcmath/tests/number/cast.phpt new file mode 100644 index 0000000000000..d16d1c285111b --- /dev/null +++ b/ext/bcmath/tests/number/cast.phpt @@ -0,0 +1,277 @@ +--TEST-- +BcMath\Number cast +--EXTENSIONS-- +bcmath +--FILE-- + (bool) $num, + 'string' => (string) $num, + 'array' => (array) $num, + ]); + echo "\n"; +} +?> +--EXPECT-- +========== 0 ========== +array(3) { + ["bool"]=> + bool(false) + ["string"]=> + string(1) "0" + ["array"]=> + array(2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) + } +} + +========== 0.0 ========== +array(3) { + ["bool"]=> + bool(false) + ["string"]=> + string(3) "0.0" + ["array"]=> + array(2) { + ["value"]=> + string(3) "0.0" + ["scale"]=> + int(1) + } +} + +========== 2 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(1) "2" + ["array"]=> + array(2) { + ["value"]=> + string(1) "2" + ["scale"]=> + int(0) + } +} + +========== 1234 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(4) "1234" + ["array"]=> + array(2) { + ["value"]=> + string(4) "1234" + ["scale"]=> + int(0) + } +} + +========== 12.0004 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(7) "12.0004" + ["array"]=> + array(2) { + ["value"]=> + string(7) "12.0004" + ["scale"]=> + int(4) + } +} + +========== 0.1230 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(6) "0.1230" + ["array"]=> + array(2) { + ["value"]=> + string(6) "0.1230" + ["scale"]=> + int(4) + } +} + +========== 1 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(1) "1" + ["array"]=> + array(2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) + } +} + +========== 12345 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(5) "12345" + ["array"]=> + array(2) { + ["value"]=> + string(5) "12345" + ["scale"]=> + int(0) + } +} + +========== -0 ========== +array(3) { + ["bool"]=> + bool(false) + ["string"]=> + string(1) "0" + ["array"]=> + array(2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) + } +} + +========== -0.0 ========== +array(3) { + ["bool"]=> + bool(false) + ["string"]=> + string(3) "0.0" + ["array"]=> + array(2) { + ["value"]=> + string(3) "0.0" + ["scale"]=> + int(1) + } +} + +========== -2 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(2) "-2" + ["array"]=> + array(2) { + ["value"]=> + string(2) "-2" + ["scale"]=> + int(0) + } +} + +========== -1234 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(5) "-1234" + ["array"]=> + array(2) { + ["value"]=> + string(5) "-1234" + ["scale"]=> + int(0) + } +} + +========== -12.0004 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(8) "-12.0004" + ["array"]=> + array(2) { + ["value"]=> + string(8) "-12.0004" + ["scale"]=> + int(4) + } +} + +========== -0.1230 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(7) "-0.1230" + ["array"]=> + array(2) { + ["value"]=> + string(7) "-0.1230" + ["scale"]=> + int(4) + } +} + +========== -1 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(2) "-1" + ["array"]=> + array(2) { + ["value"]=> + string(2) "-1" + ["scale"]=> + int(0) + } +} + +========== -12345 ========== +array(3) { + ["bool"]=> + bool(true) + ["string"]=> + string(6) "-12345" + ["array"]=> + array(2) { + ["value"]=> + string(6) "-12345" + ["scale"]=> + int(0) + } +} diff --git a/ext/bcmath/tests/number/cast_warning.phpt b/ext/bcmath/tests/number/cast_warning.phpt new file mode 100644 index 0000000000000..ad385d12331bf --- /dev/null +++ b/ext/bcmath/tests/number/cast_warning.phpt @@ -0,0 +1,14 @@ +--TEST-- +BcMath\Number cast warning +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECTF-- +Warning: Object of class BcMath\Number could not be converted to int in %s + +Warning: Object of class BcMath\Number could not be converted to float in %s diff --git a/ext/bcmath/tests/number/class_extends_error.phpt b/ext/bcmath/tests/number/class_extends_error.phpt new file mode 100644 index 0000000000000..27afe9b87294f --- /dev/null +++ b/ext/bcmath/tests/number/class_extends_error.phpt @@ -0,0 +1,13 @@ +--TEST-- +BcMath\Number class extends error +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECTF-- +Fatal error: Class Child cannot extend final class BcMath\Number in %s diff --git a/ext/bcmath/tests/number/clone.phpt b/ext/bcmath/tests/number/clone.phpt new file mode 100644 index 0000000000000..fe4f113e22b14 --- /dev/null +++ b/ext/bcmath/tests/number/clone.phpt @@ -0,0 +1,38 @@ +--TEST-- +BcMath\Number clone +--EXTENSIONS-- +bcmath +--FILE-- +value !== $clone->value || $num->scale !== $clone->scale || $num === $clone) { + echo "Result is incorrect.\n"; + var_dump($num, $clone); + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/construct_32bit.phpt b/ext/bcmath/tests/number/construct_32bit.phpt new file mode 100644 index 0000000000000..d8d78b89eca73 --- /dev/null +++ b/ext/bcmath/tests/number/construct_32bit.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number construct 32 bit +--EXTENSIONS-- +bcmath +--SKIPIF-- + 2147483647) { + die('skip only 32 bit'); +} +?> +--FILE-- + +--EXPECT-- +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.1" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.1" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.20" + ["scale"]=> + int(2) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(10) "0.00000030" + ["scale"]=> + int(8) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "1234.0" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "123450" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "123" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(10) "2147483646" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(10) "2147483647" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(11) "-2147483647" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(11) "-2147483648" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/construct_64bit.phpt b/ext/bcmath/tests/number/construct_64bit.phpt new file mode 100644 index 0000000000000..877014f308a12 --- /dev/null +++ b/ext/bcmath/tests/number/construct_64bit.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number construct 64 bit +--EXTENSIONS-- +bcmath +--SKIPIF-- + +--FILE-- + +--EXPECT-- +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.1" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.1" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.20" + ["scale"]=> + int(2) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(10) "0.00000030" + ["scale"]=> + int(8) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "1234.0" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "123450" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "123" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(19) "9223372036854775806" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(19) "9223372036854775807" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(20) "-9223372036854775807" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(20) "-9223372036854775808" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/construct_error.phpt b/ext/bcmath/tests/number/construct_error.phpt new file mode 100644 index 0000000000000..0b49e871cea96 --- /dev/null +++ b/ext/bcmath/tests/number/construct_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +BcMath\Number construct error +--EXTENSIONS-- +bcmath +--FILE-- +__construct(5); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num = new BcMath\Number('a'); + var_dump($num); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot modify readonly property BcMath\Number::$value +BcMath\Number::__construct(): Argument #1 ($num) is not well-formed diff --git a/ext/bcmath/tests/number/construct_float.phpt b/ext/bcmath/tests/number/construct_float.phpt new file mode 100644 index 0000000000000..57f2bbe524a8a --- /dev/null +++ b/ext/bcmath/tests/number/construct_float.phpt @@ -0,0 +1,17 @@ +--TEST-- +BcMath\Number construct float +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECTF-- +Deprecated: Implicit conversion from float 0.1234 to int loses precision in %s +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/methods/add.phpt b/ext/bcmath/tests/number/methods/add.phpt new file mode 100644 index 0000000000000..942347a64c7fb --- /dev/null +++ b/ext/bcmath/tests/number/methods/add.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number add() +--EXTENSIONS-- +bcmath +--FILE-- +add($value2); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100.012 + 100: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "200.012" + ["scale"]=> + int(3) +} + +100.012 + -30: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "70.012" + ["scale"]=> + int(3) +} + +100.012 + -20: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "80.012" + ["scale"]=> + int(3) +} + +100.012 + 0.01: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "100.022" + ["scale"]=> + int(3) +} + +100.012 + -0.40: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "99.612" + ["scale"]=> + int(3) +} + +100.012 + 80.3: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "180.312" + ["scale"]=> + int(3) +} + +100.012 + -50.6: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "49.412" + ["scale"]=> + int(3) +} + +-100.012 + 100: int +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-0.012" + ["scale"]=> + int(3) +} + +-100.012 + -30: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-130.012" + ["scale"]=> + int(3) +} + +-100.012 + -20: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "-120.012" + ["scale"]=> + int(3) +} + +-100.012 + 0.01: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-100.002" + ["scale"]=> + int(3) +} + +-100.012 + -0.40: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "-100.412" + ["scale"]=> + int(3) +} + +-100.012 + 80.3: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-19.712" + ["scale"]=> + int(3) +} + +-100.012 + -50.6: object +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "-150.612" + ["scale"]=> + int(3) +} diff --git a/ext/bcmath/tests/number/methods/add_with_scale.phpt b/ext/bcmath/tests/number/methods/add_with_scale.phpt new file mode 100644 index 0000000000000..f2a2cd5eb6481 --- /dev/null +++ b/ext/bcmath/tests/number/methods/add_with_scale.phpt @@ -0,0 +1,41 @@ +--TEST-- +BcMath\Number add() with scale +--EXTENSIONS-- +bcmath +--FILE-- +add($value2, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value1, $value2, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/calc_methods_num_arg_error.phpt b/ext/bcmath/tests/number/methods/calc_methods_num_arg_error.phpt new file mode 100644 index 0000000000000..7f64f31011395 --- /dev/null +++ b/ext/bcmath/tests/number/methods/calc_methods_num_arg_error.phpt @@ -0,0 +1,125 @@ +--TEST-- +BcMath\Number calc methods (add, sub, mul, div, mod, pow) num arg error +--EXTENSIONS-- +bcmath +--FILE-- +$method($val); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } + } + echo "\n"; +} +?> +--EXPECTF-- +========== add ========== +non number str: +BcMath\Number::add(): Argument #1 ($num) is not well-formed +array: +BcMath\Number::add(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::add(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +null: + +Deprecated: BcMath\Number::add(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s + +========== sub ========== +non number str: +BcMath\Number::sub(): Argument #1 ($num) is not well-formed +array: +BcMath\Number::sub(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::sub(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +null: + +Deprecated: BcMath\Number::sub(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s + +========== mul ========== +non number str: +BcMath\Number::mul(): Argument #1 ($num) is not well-formed +array: +BcMath\Number::mul(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::mul(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +null: + +Deprecated: BcMath\Number::mul(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s + +========== div ========== +non number str: +BcMath\Number::div(): Argument #1 ($num) is not well-formed +array: +BcMath\Number::div(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::div(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +Division by zero +null: + +Deprecated: BcMath\Number::div(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s +Division by zero + +========== mod ========== +non number str: +BcMath\Number::mod(): Argument #1 ($num) is not well-formed +array: +BcMath\Number::mod(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::mod(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +Modulo by zero +null: + +Deprecated: BcMath\Number::mod(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s +Modulo by zero + +========== pow ========== +non number str: +BcMath\Number::pow(): Argument #1 ($exponent) is not well-formed +array: +BcMath\Number::pow(): Argument #1 ($exponent) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::pow(): Argument #1 ($exponent) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +null: + +Deprecated: BcMath\Number::pow(): Passing null to parameter #1 ($exponent) of type BcMath\Number|string|int is deprecated in %s diff --git a/ext/bcmath/tests/number/methods/calc_methods_scale_arg_error.phpt b/ext/bcmath/tests/number/methods/calc_methods_scale_arg_error.phpt new file mode 100644 index 0000000000000..35e789f9c103e --- /dev/null +++ b/ext/bcmath/tests/number/methods/calc_methods_scale_arg_error.phpt @@ -0,0 +1,89 @@ +--TEST-- +BcMath\Number calc methods (add, sub, mul, div, mod, pow) scale arg error +--EXTENSIONS-- +bcmath +--FILE-- +$method(1, $val); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } + } + echo "\n"; +} +?> +--EXPECTF-- +========== add ========== +array: +BcMath\Number::add(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::add(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +========== sub ========== +array: +BcMath\Number::sub(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::sub(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +========== mul ========== +array: +BcMath\Number::mul(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::mul(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +========== div ========== +array: +BcMath\Number::div(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::div(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +========== mod ========== +array: +BcMath\Number::mod(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::mod(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +========== pow ========== +array: +BcMath\Number::pow(): Argument #2 ($scale) must be of type ?int, array given +other object: +BcMath\Number::pow(): Argument #2 ($scale) must be of type ?int, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s diff --git a/ext/bcmath/tests/number/methods/ceil.phpt b/ext/bcmath/tests/number/methods/ceil.phpt new file mode 100644 index 0000000000000..f37d665f09259 --- /dev/null +++ b/ext/bcmath/tests/number/methods/ceil.phpt @@ -0,0 +1,37 @@ +--TEST-- +BcMath\Number ceil() +--EXTENSIONS-- +bcmath +--FILE-- +ceil(); + if ($method_ret->compare($func_ret, 0) !== 0) { + echo "Result is incorrect.\n"; + var_dump($num, $func_ret, $method_ret); + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/compare.phpt b/ext/bcmath/tests/number/methods/compare.phpt new file mode 100644 index 0000000000000..736a8b3768eac --- /dev/null +++ b/ext/bcmath/tests/number/methods/compare.phpt @@ -0,0 +1,63 @@ +--TEST-- +BcMath\Number compare() +--EXTENSIONS-- +bcmath +--FILE-- +compare($value2)); + + echo "\n"; +} +?> +--EXPECT-- +========== with int 99 ========== +int(1) + +========== with string 99.9999 ========== +int(1) + +========== with object 99.9999 ========== +int(1) + +========== with int 100 ========== +int(0) + +========== with string 100 ========== +int(0) + +========== with string 100.0000 ========== +int(0) + +========== with object 100 ========== +int(0) + +========== with object 100.0000 ========== +int(0) + +========== with int 101 ========== +int(-1) + +========== with string 100.00001 ========== +int(-1) + +========== with object 100.00001 ========== +int(-1) diff --git a/ext/bcmath/tests/number/methods/compare_arg_error.phpt b/ext/bcmath/tests/number/methods/compare_arg_error.phpt new file mode 100644 index 0000000000000..bf714304d7fdc --- /dev/null +++ b/ext/bcmath/tests/number/methods/compare_arg_error.phpt @@ -0,0 +1,42 @@ +--TEST-- +BcMath\Number compare() arg error +--EXTENSIONS-- +bcmath +--FILE-- +compare($val); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } + echo "\n"; +} +?> +--EXPECTF-- +non number str: +BcMath\Number::compare(): Argument #1 ($num) is not well-formed + +array: +BcMath\Number::compare(): Argument #1 ($num) must be of type int, string, or BcMath\Number, array given + +other object: +BcMath\Number::compare(): Argument #1 ($num) must be of type int, string, or BcMath\Number, stdClass given + +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s + +null: + +Deprecated: BcMath\Number::compare(): Passing null to parameter #1 ($num) of type BcMath\Number|string|int is deprecated in %s diff --git a/ext/bcmath/tests/number/methods/compare_with_scale.phpt b/ext/bcmath/tests/number/methods/compare_with_scale.phpt new file mode 100644 index 0000000000000..b5cbe6dc120cb --- /dev/null +++ b/ext/bcmath/tests/number/methods/compare_with_scale.phpt @@ -0,0 +1,239 @@ +--TEST-- +BcMath\Number compare() with scale +--EXTENSIONS-- +bcmath +--FILE-- +compare($value2, $scale)); + + echo "\n"; + } +} +?> +--EXPECT-- +========== scale is 0 ========== +with int 100: +int(0) + +with string 100.0000: +int(0) + +with object 100.0000: +int(0) + +with string 100.0001: +int(0) + +with object 100.0001: +int(0) + +with string 100.0010: +int(0) + +with object 100.0010: +int(0) + +with string 100.0100: +int(0) + +with object 100.0100: +int(0) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) + +========== scale is 1 ========== +with int 100: +int(0) + +with string 100.0000: +int(0) + +with object 100.0000: +int(0) + +with string 100.0001: +int(0) + +with object 100.0001: +int(0) + +with string 100.0010: +int(0) + +with object 100.0010: +int(0) + +with string 100.0100: +int(0) + +with object 100.0100: +int(0) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) + +========== scale is 2 ========== +with int 100: +int(0) + +with string 100.0000: +int(0) + +with object 100.0000: +int(0) + +with string 100.0001: +int(0) + +with object 100.0001: +int(0) + +with string 100.0010: +int(0) + +with object 100.0010: +int(0) + +with string 100.0100: +int(-1) + +with object 100.0100: +int(-1) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) + +========== scale is 3 ========== +with int 100: +int(1) + +with string 100.0000: +int(1) + +with object 100.0000: +int(1) + +with string 100.0001: +int(1) + +with object 100.0001: +int(1) + +with string 100.0010: +int(0) + +with object 100.0010: +int(0) + +with string 100.0100: +int(-1) + +with object 100.0100: +int(-1) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) + +========== scale is 4 ========== +with int 100: +int(1) + +with string 100.0000: +int(1) + +with object 100.0000: +int(1) + +with string 100.0001: +int(1) + +with object 100.0001: +int(1) + +with string 100.0010: +int(1) + +with object 100.0010: +int(1) + +with string 100.0100: +int(-1) + +with object 100.0100: +int(-1) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) + +========== scale is 5 ========== +with int 100: +int(1) + +with string 100.0000: +int(1) + +with object 100.0000: +int(1) + +with string 100.0001: +int(1) + +with object 100.0001: +int(1) + +with string 100.0010: +int(1) + +with object 100.0010: +int(1) + +with string 100.0100: +int(-1) + +with object 100.0100: +int(-1) + +with string 100.0011: +int(0) + +with object 100.0011: +int(0) diff --git a/ext/bcmath/tests/number/methods/div.phpt b/ext/bcmath/tests/number/methods/div.phpt new file mode 100644 index 0000000000000..0b93238fdbf30 --- /dev/null +++ b/ext/bcmath/tests/number/methods/div.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number div() +--EXTENSIONS-- +bcmath +--FILE-- +div($value2); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100.012 / 100: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "1.00012" + ["scale"]=> + int(5) +} + +100.012 / -30: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(16) "-3.3337333333333" + ["scale"]=> + int(13) +} + +100.012 / -20: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-5.0006" + ["scale"]=> + int(4) +} + +100.012 / 0.01: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(9) "10001.200" + ["scale"]=> + int(3) +} + +100.012 / -0.40: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-250.030" + ["scale"]=> + int(3) +} + +100.012 / 80.3: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(15) "1.2454794520547" + ["scale"]=> + int(13) +} + +100.012 / -50.6: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(16) "-1.9765217391304" + ["scale"]=> + int(13) +} + +-100.012 / 100: int +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "-1.00012" + ["scale"]=> + int(5) +} + +-100.012 / -30: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(15) "3.3337333333333" + ["scale"]=> + int(13) +} + +-100.012 / -20: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "5.0006" + ["scale"]=> + int(4) +} + +-100.012 / 0.01: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(10) "-10001.200" + ["scale"]=> + int(3) +} + +-100.012 / -0.40: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "250.030" + ["scale"]=> + int(3) +} + +-100.012 / 80.3: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(16) "-1.2454794520547" + ["scale"]=> + int(13) +} + +-100.012 / -50.6: object +object(BcMath\Number)#3 (2) { + ["value"]=> + string(15) "1.9765217391304" + ["scale"]=> + int(13) +} diff --git a/ext/bcmath/tests/number/methods/div_with_scale.phpt b/ext/bcmath/tests/number/methods/div_with_scale.phpt new file mode 100644 index 0000000000000..a9f6e696899f1 --- /dev/null +++ b/ext/bcmath/tests/number/methods/div_with_scale.phpt @@ -0,0 +1,39 @@ +--TEST-- +BcMath\Number div() with scale +--EXTENSIONS-- +bcmath +--FILE-- +div($value2, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value1, $value2, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/floor.phpt b/ext/bcmath/tests/number/methods/floor.phpt new file mode 100644 index 0000000000000..013482b635d32 --- /dev/null +++ b/ext/bcmath/tests/number/methods/floor.phpt @@ -0,0 +1,37 @@ +--TEST-- +BcMath\Number floor() +--EXTENSIONS-- +bcmath +--FILE-- +floor(); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($num, $func_ret, $method_ret); + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/mod.phpt b/ext/bcmath/tests/number/methods/mod.phpt new file mode 100644 index 0000000000000..18fc474a3401b --- /dev/null +++ b/ext/bcmath/tests/number/methods/mod.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number mod() +--EXTENSIONS-- +bcmath +--FILE-- +mod($value2); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100.012 % 100: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "0.012" + ["scale"]=> + int(3) +} + +100.012 % -30: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "10.012" + ["scale"]=> + int(3) +} + +100.012 % -20: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "0.012" + ["scale"]=> + int(3) +} + +100.012 % 0.01: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "0.002" + ["scale"]=> + int(3) +} + +100.012 % -0.40: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "0.012" + ["scale"]=> + int(3) +} + +100.012 % 80.3: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "19.712" + ["scale"]=> + int(3) +} + +100.012 % -50.6: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "49.412" + ["scale"]=> + int(3) +} + +-100.012 % 100: int +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-0.012" + ["scale"]=> + int(3) +} + +-100.012 % -30: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-10.012" + ["scale"]=> + int(3) +} + +-100.012 % -20: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-0.012" + ["scale"]=> + int(3) +} + +-100.012 % 0.01: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-0.002" + ["scale"]=> + int(3) +} + +-100.012 % -0.40: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-0.012" + ["scale"]=> + int(3) +} + +-100.012 % 80.3: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-19.712" + ["scale"]=> + int(3) +} + +-100.012 % -50.6: object +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "-49.412" + ["scale"]=> + int(3) +} diff --git a/ext/bcmath/tests/number/methods/mod_with_scale.phpt b/ext/bcmath/tests/number/methods/mod_with_scale.phpt new file mode 100644 index 0000000000000..5c842957e2bd4 --- /dev/null +++ b/ext/bcmath/tests/number/methods/mod_with_scale.phpt @@ -0,0 +1,39 @@ +--TEST-- +BcMath\Number mod() with scale +--EXTENSIONS-- +bcmath +--FILE-- +mod($value2, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value1, $value2, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/mul.phpt b/ext/bcmath/tests/number/methods/mul.phpt new file mode 100644 index 0000000000000..ce5f1e5071efb --- /dev/null +++ b/ext/bcmath/tests/number/methods/mul.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number mul() +--EXTENSIONS-- +bcmath +--FILE-- +mul($value2); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100.012 * 100: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(9) "10001.200" + ["scale"]=> + int(3) +} + +100.012 * -30: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(9) "-3000.360" + ["scale"]=> + int(3) +} + +100.012 * -20: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(9) "-2000.240" + ["scale"]=> + int(3) +} + +100.012 * 0.01: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "1.00012" + ["scale"]=> + int(5) +} + +100.012 * -0.40: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(9) "-40.00480" + ["scale"]=> + int(5) +} + +100.012 * 80.3: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(9) "8030.9636" + ["scale"]=> + int(4) +} + +100.012 * -50.6: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(10) "-5060.6072" + ["scale"]=> + int(4) +} + +-100.012 * 100: int +object(BcMath\Number)#3 (2) { + ["value"]=> + string(10) "-10001.200" + ["scale"]=> + int(3) +} + +-100.012 * -30: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "3000.360" + ["scale"]=> + int(3) +} + +-100.012 * -20: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "2000.240" + ["scale"]=> + int(3) +} + +-100.012 * 0.01: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-1.00012" + ["scale"]=> + int(5) +} + +-100.012 * -0.40: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "40.00480" + ["scale"]=> + int(5) +} + +-100.012 * 80.3: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(10) "-8030.9636" + ["scale"]=> + int(4) +} + +-100.012 * -50.6: object +object(BcMath\Number)#3 (2) { + ["value"]=> + string(9) "5060.6072" + ["scale"]=> + int(4) +} diff --git a/ext/bcmath/tests/number/methods/mul_with_scale.phpt b/ext/bcmath/tests/number/methods/mul_with_scale.phpt new file mode 100644 index 0000000000000..cb18c088b3c03 --- /dev/null +++ b/ext/bcmath/tests/number/methods/mul_with_scale.phpt @@ -0,0 +1,39 @@ +--TEST-- +BcMath\Number mul() with scale +--EXTENSIONS-- +bcmath +--FILE-- +mul($value2, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value1, $value2, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/pow.phpt b/ext/bcmath/tests/number/methods/pow.phpt new file mode 100644 index 0000000000000..535ceda7d710e --- /dev/null +++ b/ext/bcmath/tests/number/methods/pow.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number pow() +--EXTENSIONS-- +bcmath +--FILE-- +pow($exponent); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +12.5 ** 2: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "156.25" + ["scale"]=> + int(2) +} + +12.5 ** -3: int +object(BcMath\Number)#6 (2) { + ["value"]=> + string(8) "0.000512" + ["scale"]=> + int(6) +} + +12.5 ** -2: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "0.0064" + ["scale"]=> + int(4) +} + +12.5 ** 0: string +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12.5 ** 2: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "156.25" + ["scale"]=> + int(2) +} + +12.5 ** -2: object +object(BcMath\Number)#6 (2) { + ["value"]=> + string(6) "0.0064" + ["scale"]=> + int(4) +} + +12.5 ** 0: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12.5 ** 2: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "156.25" + ["scale"]=> + int(2) +} + +-12.5 ** -3: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(9) "-0.000512" + ["scale"]=> + int(6) +} + +-12.5 ** -2: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "0.0064" + ["scale"]=> + int(4) +} + +-12.5 ** 0: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12.5 ** 2: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "156.25" + ["scale"]=> + int(2) +} + +-12.5 ** -2: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "0.0064" + ["scale"]=> + int(4) +} + +-12.5 ** 0: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/methods/pow_with_scale.phpt b/ext/bcmath/tests/number/methods/pow_with_scale.phpt new file mode 100644 index 0000000000000..c33d40f72d38f --- /dev/null +++ b/ext/bcmath/tests/number/methods/pow_with_scale.phpt @@ -0,0 +1,39 @@ +--TEST-- +BcMath\Number pow() with scale +--EXTENSIONS-- +bcmath +--FILE-- +pow($exponent, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value, $exponent, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/powmod.phpt b/ext/bcmath/tests/number/methods/powmod.phpt new file mode 100644 index 0000000000000..71599823b42d6 --- /dev/null +++ b/ext/bcmath/tests/number/methods/powmod.phpt @@ -0,0 +1,276 @@ +--TEST-- +BcMath\Number powmod() +--EXTENSIONS-- +bcmath +--FILE-- +powmod($exponent, $mod); + var_dump($ret); + echo "\n"; + } + } +} +?> +--EXPECT-- +12, expo is 2(int), mod is 2(int): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 2(int), mod is 3(string): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 2(int), mod is 2(object): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 0(string), mod is 2(int): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12, expo is 0(string), mod is 3(string): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12, expo is 0(string), mod is 2(object): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12, expo is 3(string), mod is 2(int): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 3(string), mod is 3(string): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 3(string), mod is 2(object): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 2(object), mod is 2(int): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 2(object), mod is 3(string): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 2(object), mod is 2(object): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +12, expo is 0(object), mod is 2(int): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12, expo is 0(object), mod is 3(string): +object(BcMath\Number)#6 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +12, expo is 0(object), mod is 2(object): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 2(int), mod is 2(int): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 2(int), mod is 3(string): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 2(int), mod is 2(object): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 0(string), mod is 2(int): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 0(string), mod is 3(string): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 0(string), mod is 2(object): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 3(string), mod is 2(int): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 3(string), mod is 3(string): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 3(string), mod is 2(object): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 2(object), mod is 2(int): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 2(object), mod is 3(string): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 2(object), mod is 2(object): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-12, expo is 0(object), mod is 2(int): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 0(object), mod is 3(string): +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-12, expo is 0(object), mod is 2(object): +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/methods/powmod_arg_error.phpt b/ext/bcmath/tests/number/methods/powmod_arg_error.phpt new file mode 100644 index 0000000000000..796769e1e6c4f --- /dev/null +++ b/ext/bcmath/tests/number/methods/powmod_arg_error.phpt @@ -0,0 +1,68 @@ +--TEST-- +BcMath\Number powmod arg error +--EXTENSIONS-- +bcmath +--FILE-- +powmod($val, 1); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } +} + +echo "\n"; + +echo "========== check 2nd arg ==========\n"; +foreach ($args as [$val, $type]) { + echo "{$type}:\n"; + try { + $num->powmod(1, $val); + } catch (Error $e) { + echo $e->getMessage() . "\n"; + } +} +?> +--EXPECTF-- +========== check 1st arg ========== +non number str: +BcMath\Number::powmod(): Argument #1 ($exponent) is not well-formed +array: +BcMath\Number::powmod(): Argument #1 ($exponent) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::powmod(): Argument #1 ($exponent) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +null: + +Deprecated: BcMath\Number::powmod(): Passing null to parameter #1 ($exponent) of type BcMath\Number|string|int is deprecated in %s + +========== check 2nd arg ========== +non number str: +BcMath\Number::powmod(): Argument #2 ($modulus) is not well-formed +array: +BcMath\Number::powmod(): Argument #2 ($modulus) must be of type int, string, or BcMath\Number, array given +other object: +BcMath\Number::powmod(): Argument #2 ($modulus) must be of type int, string, or BcMath\Number, stdClass given +float: + +Deprecated: Implicit conversion from float 0.1 to int loses precision in %s +Modulo by zero +null: + +Deprecated: BcMath\Number::powmod(): Passing null to parameter #2 ($modulus) of type BcMath\Number|string|int is deprecated in %s +Modulo by zero diff --git a/ext/bcmath/tests/number/methods/powmod_with_scale.phpt b/ext/bcmath/tests/number/methods/powmod_with_scale.phpt new file mode 100644 index 0000000000000..aa2a8811026e2 --- /dev/null +++ b/ext/bcmath/tests/number/methods/powmod_with_scale.phpt @@ -0,0 +1,45 @@ +--TEST-- +BcMath\Number powmod() with scale +--EXTENSIONS-- +bcmath +--FILE-- +powmod($exponent, $mod, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value, $exponent, $mod, $scale, $func_ret, $method_ret); + } + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/round.phpt b/ext/bcmath/tests/number/methods/round.phpt new file mode 100644 index 0000000000000..e54d3f5c9a15d --- /dev/null +++ b/ext/bcmath/tests/number/methods/round.phpt @@ -0,0 +1,48 @@ +--TEST-- +BcMath\Number round() +--EXTENSIONS-- +bcmath +--FILE-- +round(0, $mode); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($number, $mode, $func_ret, $method_ret); + } + } +} + +foreach (RoundingMode::cases() as $mode) { + foreach ([ + '1.2345678', + '-1.2345678', + ] as $number) { + $func_ret = bcround($number, 5, $mode); + $method_ret = (new BcMath\Number($number))->round(5, $mode); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($number, $mode, $func_ret, $method_ret); + } + } +} + +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/sqrt.phpt b/ext/bcmath/tests/number/methods/sqrt.phpt new file mode 100644 index 0000000000000..a82eb74d9012b --- /dev/null +++ b/ext/bcmath/tests/number/methods/sqrt.phpt @@ -0,0 +1,37 @@ +--TEST-- +BcMath\Number sqrt() +--EXTENSIONS-- +bcmath +--FILE-- +sqrt(); + var_dump($method_ret); +} +?> +--EXPECT-- +object(BcMath\Number)#2 (2) { + ["value"]=> + string(33) "3892470.1850385973524458288799178" + ["scale"]=> + int(25) +} +object(BcMath\Number)#3 (2) { + ["value"]=> + string(26) "375820756799356.7439216735" + ["scale"]=> + int(10) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(40) "0.36361180901442945486553617684111499023" + ["scale"]=> + int(38) +} diff --git a/ext/bcmath/tests/number/methods/sqrt_with_scale.phpt b/ext/bcmath/tests/number/methods/sqrt_with_scale.phpt new file mode 100644 index 0000000000000..04a18d0f5d51d --- /dev/null +++ b/ext/bcmath/tests/number/methods/sqrt_with_scale.phpt @@ -0,0 +1,36 @@ +--TEST-- +BcMath\Number sqrt() with scale +--EXTENSIONS-- +bcmath +--FILE-- +sqrt($scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($radicant, $scale, $func_ret, $method_ret, ((string) $method_ret) === $func_ret); + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/methods/sub.phpt b/ext/bcmath/tests/number/methods/sub.phpt new file mode 100644 index 0000000000000..84f34033c10d6 --- /dev/null +++ b/ext/bcmath/tests/number/methods/sub.phpt @@ -0,0 +1,142 @@ +--TEST-- +BcMath\Number sub() +--EXTENSIONS-- +bcmath +--FILE-- +sub($value2); + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100.012 - 100: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "0.012" + ["scale"]=> + int(3) +} + +100.012 - -30: int +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "130.012" + ["scale"]=> + int(3) +} + +100.012 - -20: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "120.012" + ["scale"]=> + int(3) +} + +100.012 - 0.01: string +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "100.002" + ["scale"]=> + int(3) +} + +100.012 - -0.40: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "100.412" + ["scale"]=> + int(3) +} + +100.012 - 80.3: object +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "19.712" + ["scale"]=> + int(3) +} + +100.012 - -50.6: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "150.612" + ["scale"]=> + int(3) +} + +-100.012 - 100: int +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "-200.012" + ["scale"]=> + int(3) +} + +-100.012 - -30: int +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-70.012" + ["scale"]=> + int(3) +} + +-100.012 - -20: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "-80.012" + ["scale"]=> + int(3) +} + +-100.012 - 0.01: string +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-100.022" + ["scale"]=> + int(3) +} + +-100.012 - -0.40: string +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "-99.612" + ["scale"]=> + int(3) +} + +-100.012 - 80.3: object +object(BcMath\Number)#4 (2) { + ["value"]=> + string(8) "-180.312" + ["scale"]=> + int(3) +} + +-100.012 - -50.6: object +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "-49.412" + ["scale"]=> + int(3) +} diff --git a/ext/bcmath/tests/number/methods/sub_with_scale.phpt b/ext/bcmath/tests/number/methods/sub_with_scale.phpt new file mode 100644 index 0000000000000..cc86c84fc392f --- /dev/null +++ b/ext/bcmath/tests/number/methods/sub_with_scale.phpt @@ -0,0 +1,41 @@ +--TEST-- +BcMath\Number sub() with scale +--EXTENSIONS-- +bcmath +--FILE-- +sub($value2, $scale); + if ($method_ret->compare($func_ret) !== 0) { + echo "Result is incorrect.\n"; + var_dump($value1, $value2, $scale, $func_ret, $method_ret); + } + } + } +} +echo 'done!'; +?> +--EXPECT-- +done! diff --git a/ext/bcmath/tests/number/operators/add_int.phpt b/ext/bcmath/tests/number/operators/add_int.phpt new file mode 100644 index 0000000000000..518dcc696fca0 --- /dev/null +++ b/ext/bcmath/tests/number/operators/add_int.phpt @@ -0,0 +1,59 @@ +--TEST-- +BcMath\Number add int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 + 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "200" + ["scale"]=> + int(0) +} + +100 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +-20 + 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +-20 + -20 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(3) "-40" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/add_object.phpt b/ext/bcmath/tests/number/operators/add_object.phpt new file mode 100644 index 0000000000000..c20ec05a27515 --- /dev/null +++ b/ext/bcmath/tests/number/operators/add_object.phpt @@ -0,0 +1,154 @@ +--TEST-- +BcMath\Number add object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 + 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "200" + ["scale"]=> + int(0) +} + +100 + -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +100 + 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "100.01" + ["scale"]=> + int(2) +} + +100 + -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +-20 + 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +-20 + -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-40" + ["scale"]=> + int(0) +} + +-20 + 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +-20 + -0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "-20.40" + ["scale"]=> + int(2) +} + +0.01 + 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "100.01" + ["scale"]=> + int(2) +} + +0.01 + -20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +0.01 + 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.02" + ["scale"]=> + int(2) +} + +0.01 + -0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +-0.40 + 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +-0.40 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-20.40" + ["scale"]=> + int(2) +} + +-0.40 + 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +-0.40 + -0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.80" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/add_string.phpt b/ext/bcmath/tests/number/operators/add_string.phpt new file mode 100644 index 0000000000000..38ef3f0e2fe39 --- /dev/null +++ b/ext/bcmath/tests/number/operators/add_string.phpt @@ -0,0 +1,157 @@ +--TEST-- +BcMath\Number add string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 + 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "200" + ["scale"]=> + int(0) +} + +100 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +100 + 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "100.01" + ["scale"]=> + int(2) +} + +100 + -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +-20 + 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +-20 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "-40" + ["scale"]=> + int(0) +} + +-20 + 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +-20 + -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "-20.40" + ["scale"]=> + int(2) +} + +0.01 + 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "100.01" + ["scale"]=> + int(2) +} + +0.01 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +0.01 + 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.02" + ["scale"]=> + int(2) +} + +0.01 + -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +-0.40 + 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +-0.40 + -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-20.40" + ["scale"]=> + int(2) +} + +-0.40 + 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +-0.40 + -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "-0.80" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/calc_array.phpt b/ext/bcmath/tests/number/operators/calc_array.phpt new file mode 100644 index 0000000000000..31acfb3ad118c --- /dev/null +++ b/ext/bcmath/tests/number/operators/calc_array.phpt @@ -0,0 +1,52 @@ +--TEST-- +BcMath\Number calc array by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num - $array; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num * $array; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / $array; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % $array; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num ** $array; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Unsupported operand types: BcMath\Number + array +Unsupported operand types: BcMath\Number - array +Unsupported operand types: BcMath\Number * array +Unsupported operand types: BcMath\Number / array +Unsupported operand types: BcMath\Number % array +Unsupported operand types: BcMath\Number ** array diff --git a/ext/bcmath/tests/number/operators/calc_float.phpt b/ext/bcmath/tests/number/operators/calc_float.phpt new file mode 100644 index 0000000000000..9a9b2bb2cdec7 --- /dev/null +++ b/ext/bcmath/tests/number/operators/calc_float.phpt @@ -0,0 +1,27 @@ +--TEST-- +BcMath\Number calc float by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECTF-- +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s + +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s + +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s + +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s + +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s + +Deprecated: Implicit conversion from float 1.01 to int loses precision in %s diff --git a/ext/bcmath/tests/number/operators/calc_non_numeric_string.phpt b/ext/bcmath/tests/number/operators/calc_non_numeric_string.phpt new file mode 100644 index 0000000000000..5add03ffff326 --- /dev/null +++ b/ext/bcmath/tests/number/operators/calc_non_numeric_string.phpt @@ -0,0 +1,51 @@ +--TEST-- +BcMath\Number calc non-numeric string by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num - 'a'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num * 'a'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / 'a'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % 'a'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num ** 'a'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Number is not well-formed +Number is not well-formed +Number is not well-formed +Number is not well-formed +Number is not well-formed +Number is not well-formed diff --git a/ext/bcmath/tests/number/operators/calc_other_class.phpt b/ext/bcmath/tests/number/operators/calc_other_class.phpt new file mode 100644 index 0000000000000..5c6a11747defa --- /dev/null +++ b/ext/bcmath/tests/number/operators/calc_other_class.phpt @@ -0,0 +1,52 @@ +--TEST-- +BcMath\Number calc other class by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num - $other; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num * $other; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / $other; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % $other; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num ** $other; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Unsupported operand types: BcMath\Number + stdClass +Unsupported operand types: BcMath\Number - stdClass +Unsupported operand types: BcMath\Number * stdClass +Unsupported operand types: BcMath\Number / stdClass +Unsupported operand types: BcMath\Number % stdClass +Unsupported operand types: BcMath\Number ** stdClass diff --git a/ext/bcmath/tests/number/operators/calc_undef.phpt b/ext/bcmath/tests/number/operators/calc_undef.phpt new file mode 100644 index 0000000000000..7b05809c0568a --- /dev/null +++ b/ext/bcmath/tests/number/operators/calc_undef.phpt @@ -0,0 +1,58 @@ +--TEST-- +BcMath\Number calc undefined var by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num - $undef; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num * $undef; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / $undef; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % $undef; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num ** $undef; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECTF-- +Warning: Undefined variable $undef in %s + +Warning: Undefined variable $undef in %s + +Warning: Undefined variable $undef in %s + +Warning: Undefined variable $undef in %s +Division by zero + +Warning: Undefined variable $undef in %s +Modulo by zero + +Warning: Undefined variable $undef in %s diff --git a/ext/bcmath/tests/number/operators/compare.phpt b/ext/bcmath/tests/number/operators/compare.phpt new file mode 100644 index 0000000000000..a448de44eabd4 --- /dev/null +++ b/ext/bcmath/tests/number/operators/compare.phpt @@ -0,0 +1,195 @@ +--TEST-- +BcMath\Number compare by operator +--EXTENSIONS-- +bcmath +--FILE-- + {$value2}: " . ($value1 > $value2 ? 'true' : 'false') . "\n"; + echo "{$value1} >= {$value2}: " . ($value1 >= $value2 ? 'true' : 'false') . "\n"; + echo "{$value1} == {$value2}: " . ($value1 == $value2 ? 'true' : 'false') . "\n"; + echo "{$value1} <= {$value2}: " . ($value1 <= $value2 ? 'true' : 'false') . "\n"; + echo "{$value1} < {$value2}: " . ($value1 < $value2 ? 'true' : 'false') . "\n"; + + echo "\ninversion\n"; + echo "{$value2} > {$value1}: " . ($value2 > $value1 ? 'true' : 'false') . "\n"; + echo "{$value2} >= {$value1}: " . ($value2 >= $value1 ? 'true' : 'false') . "\n"; + echo "{$value2} == {$value1}: " . ($value2 == $value1 ? 'true' : 'false') . "\n"; + echo "{$value2} <= {$value1}: " . ($value2 <= $value1 ? 'true' : 'false') . "\n"; + echo "{$value2} < {$value1}: " . ($value2 < $value1 ? 'true' : 'false') . "\n"; + + echo "\n"; +} +?> +--EXPECT-- +========== with int 99 ========== +100.0000 > 99: true +100.0000 >= 99: true +100.0000 == 99: false +100.0000 <= 99: false +100.0000 < 99: false + +inversion +99 > 100.0000: false +99 >= 100.0000: false +99 == 100.0000: false +99 <= 100.0000: true +99 < 100.0000: true + +========== with string 99.9999 ========== +100.0000 > 99.9999: true +100.0000 >= 99.9999: true +100.0000 == 99.9999: false +100.0000 <= 99.9999: false +100.0000 < 99.9999: false + +inversion +99.9999 > 100.0000: false +99.9999 >= 100.0000: false +99.9999 == 100.0000: false +99.9999 <= 100.0000: true +99.9999 < 100.0000: true + +========== with object 99.9999 ========== +100.0000 > 99.9999: true +100.0000 >= 99.9999: true +100.0000 == 99.9999: false +100.0000 <= 99.9999: false +100.0000 < 99.9999: false + +inversion +99.9999 > 100.0000: false +99.9999 >= 100.0000: false +99.9999 == 100.0000: false +99.9999 <= 100.0000: true +99.9999 < 100.0000: true + +========== with int 100 ========== +100.0000 > 100: false +100.0000 >= 100: true +100.0000 == 100: true +100.0000 <= 100: true +100.0000 < 100: false + +inversion +100 > 100.0000: false +100 >= 100.0000: true +100 == 100.0000: true +100 <= 100.0000: true +100 < 100.0000: false + +========== with string 100 ========== +100.0000 > 100: false +100.0000 >= 100: true +100.0000 == 100: true +100.0000 <= 100: true +100.0000 < 100: false + +inversion +100 > 100.0000: false +100 >= 100.0000: true +100 == 100.0000: true +100 <= 100.0000: true +100 < 100.0000: false + +========== with string 100.0000 ========== +100.0000 > 100.0000: false +100.0000 >= 100.0000: true +100.0000 == 100.0000: true +100.0000 <= 100.0000: true +100.0000 < 100.0000: false + +inversion +100.0000 > 100.0000: false +100.0000 >= 100.0000: true +100.0000 == 100.0000: true +100.0000 <= 100.0000: true +100.0000 < 100.0000: false + +========== with object 100 ========== +100.0000 > 100: false +100.0000 >= 100: true +100.0000 == 100: true +100.0000 <= 100: true +100.0000 < 100: false + +inversion +100 > 100.0000: false +100 >= 100.0000: true +100 == 100.0000: true +100 <= 100.0000: true +100 < 100.0000: false + +========== with object 100.0000 ========== +100.0000 > 100.0000: false +100.0000 >= 100.0000: true +100.0000 == 100.0000: true +100.0000 <= 100.0000: true +100.0000 < 100.0000: false + +inversion +100.0000 > 100.0000: false +100.0000 >= 100.0000: true +100.0000 == 100.0000: true +100.0000 <= 100.0000: true +100.0000 < 100.0000: false + +========== with int 101 ========== +100.0000 > 101: false +100.0000 >= 101: false +100.0000 == 101: false +100.0000 <= 101: true +100.0000 < 101: true + +inversion +101 > 100.0000: true +101 >= 100.0000: true +101 == 100.0000: false +101 <= 100.0000: false +101 < 100.0000: false + +========== with string 100.00001 ========== +100.0000 > 100.00001: false +100.0000 >= 100.00001: false +100.0000 == 100.00001: false +100.0000 <= 100.00001: true +100.0000 < 100.00001: true + +inversion +100.00001 > 100.0000: true +100.00001 >= 100.0000: true +100.00001 == 100.0000: false +100.00001 <= 100.0000: false +100.00001 < 100.0000: false + +========== with object 100.00001 ========== +100.0000 > 100.00001: false +100.0000 >= 100.00001: false +100.0000 == 100.00001: false +100.0000 <= 100.00001: true +100.0000 < 100.00001: true + +inversion +100.00001 > 100.0000: true +100.00001 >= 100.0000: true +100.00001 == 100.0000: false +100.00001 <= 100.0000: false +100.00001 < 100.0000: false diff --git a/ext/bcmath/tests/number/operators/compound_assignment.phpt b/ext/bcmath/tests/number/operators/compound_assignment.phpt new file mode 100644 index 0000000000000..11dbd8d9274cd --- /dev/null +++ b/ext/bcmath/tests/number/operators/compound_assignment.phpt @@ -0,0 +1,115 @@ +--TEST-- +BcMath\Number operator compound assignment +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +========== add ========== +200 +250 +280 +old: 100 + +========== sub ========== +0 +-50 +-80 +old: 100 + +========== mul ========== +10000 +500000 +15000000 +old: 100 + +========== div ========== +1 +0.02 +0.000666666666 +old: 100 + +========== mod ========== +10 +10 +4 +old: 1000 + +========== pow ========== +100 +1000000 +1 +old: 10 diff --git a/ext/bcmath/tests/number/operators/decrement.phpt b/ext/bcmath/tests/number/operators/decrement.phpt new file mode 100644 index 0000000000000..9f1a08108363b --- /dev/null +++ b/ext/bcmath/tests/number/operators/decrement.phpt @@ -0,0 +1,93 @@ +--TEST-- +BcMath\Number decrement +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +========== 100-- ========== +$num: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "99" + ["scale"]=> + int(0) +} +$num_old: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "100" + ["scale"]=> + int(0) +} + +========== -20-- ========== +$num: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-21" + ["scale"]=> + int(0) +} +$num_old: +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "-20" + ["scale"]=> + int(0) +} + +========== 0.01-- ========== +$num: +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-0.99" + ["scale"]=> + int(2) +} +$num_old: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +========== -0.40-- ========== +$num: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-1.40" + ["scale"]=> + int(2) +} +$num_old: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.40" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/div_by_zero.phpt b/ext/bcmath/tests/number/operators/div_by_zero.phpt new file mode 100644 index 0000000000000..cadac7361a2fc --- /dev/null +++ b/ext/bcmath/tests/number/operators/div_by_zero.phpt @@ -0,0 +1,53 @@ +--TEST-- +BcMath\Number div by zero by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num / '0'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / (new BcMath\Number(0)); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +$zero = new BcMath\Number(0); + +try { + 100 / $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + '100' / $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num / $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Division by zero +Division by zero +Division by zero +Division by zero +Division by zero +Division by zero diff --git a/ext/bcmath/tests/number/operators/div_int.phpt b/ext/bcmath/tests/number/operators/div_int.phpt new file mode 100644 index 0000000000000..77ca4c97c0106 --- /dev/null +++ b/ext/bcmath/tests/number/operators/div_int.phpt @@ -0,0 +1,100 @@ +--TEST-- +BcMath\Number div int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 / 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 / -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "-5" + ["scale"]=> + int(0) +} + +100 / 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(13) "33.3333333333" + ["scale"]=> + int(10) +} + +-20 / 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "-0.2" + ["scale"]=> + int(1) +} + +-20 / -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 / 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(13) "-6.6666666666" + ["scale"]=> + int(10) +} + +3 / 100 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "0.03" + ["scale"]=> + int(2) +} + +3 / -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.15" + ["scale"]=> + int(2) +} + +3 / 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/div_object.phpt b/ext/bcmath/tests/number/operators/div_object.phpt new file mode 100644 index 0000000000000..277ba1cecdc7f --- /dev/null +++ b/ext/bcmath/tests/number/operators/div_object.phpt @@ -0,0 +1,227 @@ +--TEST-- +BcMath\Number div object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 / 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 / -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "-5" + ["scale"]=> + int(0) +} + +100 / 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 / -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "-250" + ["scale"]=> + int(0) +} + +100 / 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(13) "33.3333333333" + ["scale"]=> + int(10) +} + +-20 / 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "-0.2" + ["scale"]=> + int(1) +} + +-20 / -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 / 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 / -0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(2) "50" + ["scale"]=> + int(0) +} + +-20 / 3 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(13) "-6.6666666666" + ["scale"]=> + int(10) +} + +0.01 / 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 / -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "-0.0005" + ["scale"]=> + int(4) +} + +0.01 / 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +0.01 / -0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "-0.025" + ["scale"]=> + int(3) +} + +0.01 / 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(14) "0.003333333333" + ["scale"]=> + int(12) +} + +-0.40 / 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-0.004" + ["scale"]=> + int(3) +} + +-0.40 / -20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.02" + ["scale"]=> + int(2) +} + +-0.40 / 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-0.40 / -0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +-0.40 / 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(15) "-0.133333333333" + ["scale"]=> + int(12) +} + +3 / 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "0.03" + ["scale"]=> + int(2) +} + +3 / -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-0.15" + ["scale"]=> + int(2) +} + +3 / 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(3) "300" + ["scale"]=> + int(0) +} + +3 / -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "-7.5" + ["scale"]=> + int(1) +} + +3 / 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/div_string.phpt b/ext/bcmath/tests/number/operators/div_string.phpt new file mode 100644 index 0000000000000..313ac621fe967 --- /dev/null +++ b/ext/bcmath/tests/number/operators/div_string.phpt @@ -0,0 +1,230 @@ +--TEST-- +BcMath\Number div string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 / 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 / -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "-5" + ["scale"]=> + int(0) +} + +100 / 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 / -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "-250" + ["scale"]=> + int(0) +} + +100 / 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(13) "33.3333333333" + ["scale"]=> + int(10) +} + +-20 / 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "-0.2" + ["scale"]=> + int(1) +} + +-20 / -20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 / 0.01 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 / -0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "50" + ["scale"]=> + int(0) +} + +-20 / 3 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(13) "-6.6666666666" + ["scale"]=> + int(10) +} + +0.01 / 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 / -20 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "-0.0005" + ["scale"]=> + int(4) +} + +0.01 / 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +0.01 / -0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-0.025" + ["scale"]=> + int(3) +} + +0.01 / 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(14) "0.003333333333" + ["scale"]=> + int(12) +} + +-0.40 / 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-0.004" + ["scale"]=> + int(3) +} + +-0.40 / -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.02" + ["scale"]=> + int(2) +} + +-0.40 / 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-0.40 / -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +-0.40 / 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(15) "-0.133333333333" + ["scale"]=> + int(12) +} + +3 / 100 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "0.03" + ["scale"]=> + int(2) +} + +3 / -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.15" + ["scale"]=> + int(2) +} + +3 / 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "300" + ["scale"]=> + int(0) +} + +3 / -0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "-7.5" + ["scale"]=> + int(1) +} + +3 / 3 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/increment.phpt b/ext/bcmath/tests/number/operators/increment.phpt new file mode 100644 index 0000000000000..24cd7ad56571f --- /dev/null +++ b/ext/bcmath/tests/number/operators/increment.phpt @@ -0,0 +1,93 @@ +--TEST-- +BcMath\Number increment +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +========== 100++ ========== +$num: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "101" + ["scale"]=> + int(0) +} +$num_old: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "100" + ["scale"]=> + int(0) +} + +========== -20++ ========== +$num: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-19" + ["scale"]=> + int(0) +} +$num_old: +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "-20" + ["scale"]=> + int(0) +} + +========== 0.01++ ========== +$num: +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "1.01" + ["scale"]=> + int(2) +} +$num_old: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +========== -0.40++ ========== +$num: +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.60" + ["scale"]=> + int(2) +} +$num_old: +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.40" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/mod_by_zero.phpt b/ext/bcmath/tests/number/operators/mod_by_zero.phpt new file mode 100644 index 0000000000000..9c1e08f6a4dc3 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mod_by_zero.phpt @@ -0,0 +1,53 @@ +--TEST-- +BcMath\Number mod by zero by operator +--EXTENSIONS-- +bcmath +--FILE-- +getMessage() . "\n"; +} + +try { + $num % '0'; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % (new BcMath\Number(0)); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +$zero = new BcMath\Number(0); + +try { + 100 % $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + '100' % $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num % $zero; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Modulo by zero +Modulo by zero +Modulo by zero +Modulo by zero +Modulo by zero +Modulo by zero diff --git a/ext/bcmath/tests/number/operators/mod_int.phpt b/ext/bcmath/tests/number/operators/mod_int.phpt new file mode 100644 index 0000000000000..fbb63bf3ca191 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mod_int.phpt @@ -0,0 +1,100 @@ +--TEST-- +BcMath\Number mod int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 % 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % 9 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 % 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-20" + ["scale"]=> + int(0) +} + +-20 % -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-20 % 9 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "-2" + ["scale"]=> + int(0) +} + +9 % 100 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +9 % -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +9 % 9 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/mod_object.phpt b/ext/bcmath/tests/number/operators/mod_object.phpt new file mode 100644 index 0000000000000..85dba7497659d --- /dev/null +++ b/ext/bcmath/tests/number/operators/mod_object.phpt @@ -0,0 +1,154 @@ +--TEST-- +BcMath\Number mod object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 % 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +100 % -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +-20 % 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "-20" + ["scale"]=> + int(0) +} + +-20 % -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-20 % 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +-20 % -0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +0.01 % 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +0.01 % -20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +0.01 % 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +0.01 % -0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +-0.40 % 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.40" + ["scale"]=> + int(2) +} + +-0.40 % -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-0.40" + ["scale"]=> + int(2) +} + +-0.40 % 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +-0.40 % -0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/mod_string.phpt b/ext/bcmath/tests/number/operators/mod_string.phpt new file mode 100644 index 0000000000000..1c59d787bab10 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mod_string.phpt @@ -0,0 +1,100 @@ +--TEST-- +BcMath\Number mod string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 % 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 % 9 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 % 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-20" + ["scale"]=> + int(0) +} + +-20 % -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +-20 % 9 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "-2" + ["scale"]=> + int(0) +} + +9 % 100 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +9 % -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +9 % 9 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/mul_int.phpt b/ext/bcmath/tests/number/operators/mul_int.phpt new file mode 100644 index 0000000000000..ecd87210fa272 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mul_int.phpt @@ -0,0 +1,59 @@ +--TEST-- +BcMath\Number mul int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 * 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 * 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 * -20 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/mul_object.phpt b/ext/bcmath/tests/number/operators/mul_object.phpt new file mode 100644 index 0000000000000..33a52d551c690 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mul_object.phpt @@ -0,0 +1,154 @@ +--TEST-- +BcMath\Number mul object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 * 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 * -20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +100 * 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +100 * -0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-20 * 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 * -20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} + +-20 * 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-0.20" + ["scale"]=> + int(2) +} + +-20 * -0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "8.00" + ["scale"]=> + int(2) +} + +0.01 * 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +0.01 * -20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.20" + ["scale"]=> + int(2) +} + +0.01 * 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 * -0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(7) "-0.0040" + ["scale"]=> + int(4) +} + +-0.40 * 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-0.40 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "8.00" + ["scale"]=> + int(2) +} + +-0.40 * 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(7) "-0.0040" + ["scale"]=> + int(4) +} + +-0.40 * -0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "0.1600" + ["scale"]=> + int(4) +} diff --git a/ext/bcmath/tests/number/operators/mul_string.phpt b/ext/bcmath/tests/number/operators/mul_string.phpt new file mode 100644 index 0000000000000..a1c449e4eab63 --- /dev/null +++ b/ext/bcmath/tests/number/operators/mul_string.phpt @@ -0,0 +1,157 @@ +--TEST-- +BcMath\Number mul string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 * 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +100 * 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +100 * -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-20 * 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-2000" + ["scale"]=> + int(0) +} + +-20 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} + +-20 * 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.20" + ["scale"]=> + int(2) +} + +-20 * -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "8.00" + ["scale"]=> + int(2) +} + +0.01 * 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "1.00" + ["scale"]=> + int(2) +} + +0.01 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-0.20" + ["scale"]=> + int(2) +} + +0.01 * 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 * -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(7) "-0.0040" + ["scale"]=> + int(4) +} + +-0.40 * 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-40.00" + ["scale"]=> + int(2) +} + +-0.40 * -20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "8.00" + ["scale"]=> + int(2) +} + +-0.40 * 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(7) "-0.0040" + ["scale"]=> + int(4) +} + +-0.40 * -0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(6) "0.1600" + ["scale"]=> + int(4) +} diff --git a/ext/bcmath/tests/number/operators/pow_int.phpt b/ext/bcmath/tests/number/operators/pow_int.phpt new file mode 100644 index 0000000000000..6fbfd90f47ffc --- /dev/null +++ b/ext/bcmath/tests/number/operators/pow_int.phpt @@ -0,0 +1,156 @@ +--TEST-- +BcMath\Number pow int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 ** 2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 ** 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "1000000" + ["scale"]=> + int(0) +} + +100 ** 0 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 ** -1 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +100 ** -2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +-20 ** 2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} + +-20 ** 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-8000" + ["scale"]=> + int(0) +} + +-20 ** 0 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 ** -1 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-0.05" + ["scale"]=> + int(2) +} + +-20 ** -2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.0025" + ["scale"]=> + int(4) +} + +3 ** 2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +3 ** 3 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(2) "27" + ["scale"]=> + int(0) +} + +3 ** 0 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +3 ** -1 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(12) "0.3333333333" + ["scale"]=> + int(10) +} + +3 ** -2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(12) "0.1111111111" + ["scale"]=> + int(10) +} diff --git a/ext/bcmath/tests/number/operators/pow_object.phpt b/ext/bcmath/tests/number/operators/pow_object.phpt new file mode 100644 index 0000000000000..f0b18d8c7a7fd --- /dev/null +++ b/ext/bcmath/tests/number/operators/pow_object.phpt @@ -0,0 +1,235 @@ +--TEST-- +BcMath\Number pow object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 ** 2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 ** 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(7) "1000000" + ["scale"]=> + int(0) +} + +100 ** 0 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 ** -1 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +100 ** -2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +-20 ** 2 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} + +-20 ** 3 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-8000" + ["scale"]=> + int(0) +} + +-20 ** 0 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 ** -1 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-0.05" + ["scale"]=> + int(2) +} + +-20 ** -2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.0025" + ["scale"]=> + int(4) +} + +0.01 ** 2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 ** 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "0.000001" + ["scale"]=> + int(6) +} + +0.01 ** 0 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +0.01 ** -1 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "100.00" + ["scale"]=> + int(2) +} + +0.01 ** -2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "10000.00" + ["scale"]=> + int(2) +} + +-0.40 ** 2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.1600" + ["scale"]=> + int(4) +} + +-0.40 ** 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(9) "-0.064000" + ["scale"]=> + int(6) +} + +-0.40 ** 0 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-0.40 ** -1 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-2.50" + ["scale"]=> + int(2) +} + +-0.40 ** -2 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "6.25" + ["scale"]=> + int(2) +} + +3 ** 2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +3 ** 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "27" + ["scale"]=> + int(0) +} + +3 ** 0 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +3 ** -1 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(12) "0.3333333333" + ["scale"]=> + int(10) +} + +3 ** -2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(12) "0.1111111111" + ["scale"]=> + int(10) +} diff --git a/ext/bcmath/tests/number/operators/pow_string.phpt b/ext/bcmath/tests/number/operators/pow_string.phpt new file mode 100644 index 0000000000000..5b56e3af3efee --- /dev/null +++ b/ext/bcmath/tests/number/operators/pow_string.phpt @@ -0,0 +1,238 @@ +--TEST-- +BcMath\Number pow string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 ** 2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "10000" + ["scale"]=> + int(0) +} + +100 ** 3 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(7) "1000000" + ["scale"]=> + int(0) +} + +100 ** 0 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +100 ** -1 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "0.01" + ["scale"]=> + int(2) +} + +100 ** -2 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +-20 ** 2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "400" + ["scale"]=> + int(0) +} + +-20 ** 3 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "-8000" + ["scale"]=> + int(0) +} + +-20 ** 0 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-20 ** -1 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "-0.05" + ["scale"]=> + int(2) +} + +-20 ** -2 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.0025" + ["scale"]=> + int(4) +} + +0.01 ** 2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "0.0001" + ["scale"]=> + int(4) +} + +0.01 ** 3 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(8) "0.000001" + ["scale"]=> + int(6) +} + +0.01 ** 0 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +0.01 ** -1 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "100.00" + ["scale"]=> + int(2) +} + +0.01 ** -2 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(8) "10000.00" + ["scale"]=> + int(2) +} + +-0.40 ** 2 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "0.1600" + ["scale"]=> + int(4) +} + +-0.40 ** 3 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(9) "-0.064000" + ["scale"]=> + int(6) +} + +-0.40 ** 0 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +-0.40 ** -1 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "-2.50" + ["scale"]=> + int(2) +} + +-0.40 ** -2 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "6.25" + ["scale"]=> + int(2) +} + +3 ** 2 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "9" + ["scale"]=> + int(0) +} + +3 ** 3 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(2) "27" + ["scale"]=> + int(0) +} + +3 ** 0 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} + +3 ** -1 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(12) "0.3333333333" + ["scale"]=> + int(10) +} + +3 ** -2 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(12) "0.1111111111" + ["scale"]=> + int(10) +} diff --git a/ext/bcmath/tests/number/operators/sub_int.phpt b/ext/bcmath/tests/number/operators/sub_int.phpt new file mode 100644 index 0000000000000..0616edae2ec7d --- /dev/null +++ b/ext/bcmath/tests/number/operators/sub_int.phpt @@ -0,0 +1,59 @@ +--TEST-- +BcMath\Number sub int by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 - 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +20 - 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-80" + ["scale"]=> + int(0) +} + +20 - 20 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/operators/sub_object.phpt b/ext/bcmath/tests/number/operators/sub_object.phpt new file mode 100644 index 0000000000000..3887c511cedd9 --- /dev/null +++ b/ext/bcmath/tests/number/operators/sub_object.phpt @@ -0,0 +1,154 @@ +--TEST-- +BcMath\Number sub object by operator +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +100 - 100 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 - 20 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +100 - 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "99.99" + ["scale"]=> + int(2) +} + +100 - 0.40 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +20 - 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(3) "-80" + ["scale"]=> + int(0) +} + +20 - 20 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +20 - 0.01 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(5) "19.99" + ["scale"]=> + int(2) +} + +20 - 0.40 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(5) "19.60" + ["scale"]=> + int(2) +} + +0.01 - 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-99.99" + ["scale"]=> + int(2) +} + +0.01 - 20 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +0.01 - 0.01 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +0.01 - 0.40 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +0.40 - 100 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(6) "-99.60" + ["scale"]=> + int(2) +} + +0.40 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-19.60" + ["scale"]=> + int(2) +} + +0.40 - 0.01 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "0.39" + ["scale"]=> + int(2) +} + +0.40 - 0.40 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/operators/sub_string.phpt b/ext/bcmath/tests/number/operators/sub_string.phpt new file mode 100644 index 0000000000000..b5c5776766128 --- /dev/null +++ b/ext/bcmath/tests/number/operators/sub_string.phpt @@ -0,0 +1,157 @@ +--TEST-- +BcMath\Number sub string by operator +--EXTENSIONS-- +bcmath +--FILE-- +compare($ret2) !== 0) { + echo "Result is incorrect.\n"; + } + var_dump($ret); + echo "\n"; + } +} +?> +--EXPECT-- +100 - 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +100 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(2) "80" + ["scale"]=> + int(0) +} + +100 - 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "99.99" + ["scale"]=> + int(2) +} + +100 - 0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "99.60" + ["scale"]=> + int(2) +} + +20 - 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "-80" + ["scale"]=> + int(0) +} + +20 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} + +20 - 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(5) "19.99" + ["scale"]=> + int(2) +} + +20 - 0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "19.60" + ["scale"]=> + int(2) +} + +0.01 - 100 +object(BcMath\Number)#2 (2) { + ["value"]=> + string(6) "-99.99" + ["scale"]=> + int(2) +} + +0.01 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-19.99" + ["scale"]=> + int(2) +} + +0.01 - 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} + +0.01 - 0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(5) "-0.39" + ["scale"]=> + int(2) +} + +0.40 - 100 +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "-99.60" + ["scale"]=> + int(2) +} + +0.40 - 20 +object(BcMath\Number)#3 (2) { + ["value"]=> + string(6) "-19.60" + ["scale"]=> + int(2) +} + +0.40 - 0.01 +object(BcMath\Number)#4 (2) { + ["value"]=> + string(4) "0.39" + ["scale"]=> + int(2) +} + +0.40 - 0.40 +object(BcMath\Number)#5 (2) { + ["value"]=> + string(4) "0.00" + ["scale"]=> + int(2) +} diff --git a/ext/bcmath/tests/number/properties_isset_empty_exists.phpt b/ext/bcmath/tests/number/properties_isset_empty_exists.phpt new file mode 100644 index 0000000000000..b9783d89a7452 --- /dev/null +++ b/ext/bcmath/tests/number/properties_isset_empty_exists.phpt @@ -0,0 +1,136 @@ +--TEST-- +BcMath\Number properties isset, empty, exists +--EXTENSIONS-- +bcmath +--FILE-- + [ + 'value' => isset($zero->value), + 'scale' => isset($zero->scale), + ], + 'one' => [ + 'value' => isset($one->value), + 'scale' => isset($one->scale), + ], + 'has_frac' => [ + 'value' => isset($has_frac->value), + 'scale' => isset($has_frac->scale), + ], +]); +echo "\n"; + +echo "========== empty ==========\n"; +var_dump([ + 'zero' => [ + 'value' => empty($zero->value), + 'scale' => empty($zero->scale), + ], + 'one' => [ + 'value' => empty($one->value), + 'scale' => empty($one->scale), + ], + 'has_frac' => [ + 'value' => empty($has_frac->value), + 'scale' => empty($has_frac->scale), + ], +]); +echo "\n"; + +echo "========== property_exists ==========\n"; +var_dump([ + 'zero' => [ + 'value' => property_exists($zero, 'value'), + 'scale' => property_exists($zero, 'scale'), + ], + 'one' => [ + 'value' => property_exists($one, 'value'), + 'scale' => property_exists($one, 'scale'), + ], + 'has_frac' => [ + 'value' => property_exists($has_frac, 'value'), + 'scale' => property_exists($has_frac, 'scale'), + ], +]); +?> +--EXPECT-- +========== isset ========== +array(3) { + ["zero"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } + ["one"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } + ["has_frac"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } +} + +========== empty ========== +array(3) { + ["zero"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } + ["one"]=> + array(2) { + ["value"]=> + bool(false) + ["scale"]=> + bool(true) + } + ["has_frac"]=> + array(2) { + ["value"]=> + bool(false) + ["scale"]=> + bool(false) + } +} + +========== property_exists ========== +array(3) { + ["zero"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } + ["one"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } + ["has_frac"]=> + array(2) { + ["value"]=> + bool(true) + ["scale"]=> + bool(true) + } +} diff --git a/ext/bcmath/tests/number/properties_read.phpt b/ext/bcmath/tests/number/properties_read.phpt new file mode 100644 index 0000000000000..0ac4f5d90eb14 --- /dev/null +++ b/ext/bcmath/tests/number/properties_read.phpt @@ -0,0 +1,49 @@ +--TEST-- +BcMath\Number properties read +--EXTENSIONS-- +bcmath +--FILE-- +value}\n"; + echo "scale: {$num->scale}\n"; + echo "\n"; +} +?> +--EXPECT-- +value: 0 +scale: 0 + +value: 0.0 +scale: 1 + +value: 2 +scale: 0 + +value: 1234 +scale: 0 + +value: 12.0004 +scale: 4 + +value: 0.1230 +scale: 4 + +value: 1 +scale: 0 + +value: 12345 +scale: 0 diff --git a/ext/bcmath/tests/number/properties_unknown.phpt b/ext/bcmath/tests/number/properties_unknown.phpt new file mode 100644 index 0000000000000..cd1c13eb0c745 --- /dev/null +++ b/ext/bcmath/tests/number/properties_unknown.phpt @@ -0,0 +1,36 @@ +--TEST-- +BcMath\Number properties unknown +--EXTENSIONS-- +bcmath +--FILE-- +foo); + +try { + $num->foo = 1; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($num->foo); + +try { + $num->bar = 1; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump(isset($num->foo)); +?> +--EXPECTF-- +Warning: Undefined property: BcMath\Number::$foo in %s +NULL +Cannot create dynamic property BcMath\Number::$foo + +Warning: Undefined property: BcMath\Number::$foo in %s +NULL +Cannot create dynamic property BcMath\Number::$bar +bool(false) diff --git a/ext/bcmath/tests/number/properties_unset.phpt b/ext/bcmath/tests/number/properties_unset.phpt new file mode 100644 index 0000000000000..ce21350240bb5 --- /dev/null +++ b/ext/bcmath/tests/number/properties_unset.phpt @@ -0,0 +1,23 @@ +--TEST-- +BcMath\Number properties unset +--EXTENSIONS-- +bcmath +--FILE-- +value); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + unset($num->scale); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot unset readonly property BcMath\Number::$value +Cannot unset readonly property BcMath\Number::$scale diff --git a/ext/bcmath/tests/number/properties_write_error.phpt b/ext/bcmath/tests/number/properties_write_error.phpt new file mode 100644 index 0000000000000..03683c4c0926f --- /dev/null +++ b/ext/bcmath/tests/number/properties_write_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +BcMath\Number properties write error +--EXTENSIONS-- +bcmath +--FILE-- +value = 1; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $num->scale = 1; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Cannot modify readonly property BcMath\Number::$value +Cannot modify readonly property BcMath\Number::$scale diff --git a/ext/bcmath/tests/number/serialize.phpt b/ext/bcmath/tests/number/serialize.phpt new file mode 100644 index 0000000000000..0054b0795ae2c --- /dev/null +++ b/ext/bcmath/tests/number/serialize.phpt @@ -0,0 +1,32 @@ +--TEST-- +BcMath\Number serialize +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +O:13:"BcMath\Number":1:{s:5:"value";s:1:"0";} +O:13:"BcMath\Number":1:{s:5:"value";s:3:"0.0";} +O:13:"BcMath\Number":1:{s:5:"value";s:1:"2";} +O:13:"BcMath\Number":1:{s:5:"value";s:4:"1234";} +O:13:"BcMath\Number":1:{s:5:"value";s:7:"12.0004";} +O:13:"BcMath\Number":1:{s:5:"value";s:6:"0.1230";} +O:13:"BcMath\Number":1:{s:5:"value";s:1:"1";} +O:13:"BcMath\Number":1:{s:5:"value";s:5:"12345";} diff --git a/ext/bcmath/tests/number/unserialize.phpt b/ext/bcmath/tests/number/unserialize.phpt new file mode 100644 index 0000000000000..a7da815454b0d --- /dev/null +++ b/ext/bcmath/tests/number/unserialize.phpt @@ -0,0 +1,73 @@ +--TEST-- +BcMath\Number unserialize +--EXTENSIONS-- +bcmath +--FILE-- + +--EXPECT-- +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "0" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(3) "0.0" + ["scale"]=> + int(1) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "2" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(4) "1234" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(7) "12.0004" + ["scale"]=> + int(4) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(6) "0.1230" + ["scale"]=> + int(4) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(1) "1" + ["scale"]=> + int(0) +} +object(BcMath\Number)#1 (2) { + ["value"]=> + string(5) "12345" + ["scale"]=> + int(0) +} diff --git a/ext/bcmath/tests/number/unserialize_error.phpt b/ext/bcmath/tests/number/unserialize_error.phpt new file mode 100644 index 0000000000000..030ba1232d06a --- /dev/null +++ b/ext/bcmath/tests/number/unserialize_error.phpt @@ -0,0 +1,36 @@ +--TEST-- +BcMath\Number unserialize error +--EXTENSIONS-- +bcmath +--FILE-- +__unserialize(['value' => '5']); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +echo "\n"; +$cases = [ + 'O:13:"BcMath\Number":1:{s:5:"value";s:1:"a";}', + 'O:13:"BcMath\Number":1:{s:5:"value";s:0:"";}', + 'O:13:"BcMath\Number":0:{}', + 'O:13:"BcMath\Number":1:{s:5:"value";i:1;}', +]; + +foreach ($cases as $case) { + try { + unserialize($case); + } catch (Exception $e) { + echo $e->getMessage() . "\n"; + } +} +?> +--EXPECT-- +Cannot modify readonly property BcMath\Number::$value + +Invalid serialization data for BcMath\Number object +Invalid serialization data for BcMath\Number object +Invalid serialization data for BcMath\Number object +Invalid serialization data for BcMath\Number object