xref: /php-src/ext/bcmath/bcmath.c (revision 68247c02)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Andi Gutmans <andi@php.net>                                  |
14    +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 
23 #ifdef HAVE_BCMATH
24 
25 #include "php_ini.h"
26 #include "zend_exceptions.h"
27 #include "bcmath_arginfo.h"
28 #include "ext/standard/info.h"
29 #include "php_bcmath.h"
30 #include "libbcmath/src/bcmath.h"
31 
32 ZEND_DECLARE_MODULE_GLOBALS(bcmath)
33 static PHP_GINIT_FUNCTION(bcmath);
34 static PHP_GSHUTDOWN_FUNCTION(bcmath);
35 static PHP_MINIT_FUNCTION(bcmath);
36 static PHP_MSHUTDOWN_FUNCTION(bcmath);
37 static PHP_MINFO_FUNCTION(bcmath);
38 
39 zend_module_entry bcmath_module_entry = {
40 	STANDARD_MODULE_HEADER,
41 	"bcmath",
42 	ext_functions,
43 	PHP_MINIT(bcmath),
44 	PHP_MSHUTDOWN(bcmath),
45 	NULL,
46 	NULL,
47 	PHP_MINFO(bcmath),
48 	PHP_BCMATH_VERSION,
49 	PHP_MODULE_GLOBALS(bcmath),
50 	PHP_GINIT(bcmath),
51 	PHP_GSHUTDOWN(bcmath),
52 	NULL,
53 	STANDARD_MODULE_PROPERTIES_EX
54 };
55 
56 #ifdef COMPILE_DL_BCMATH
57 #ifdef ZTS
58 ZEND_TSRMLS_CACHE_DEFINE()
59 #endif
ZEND_GET_MODULE(bcmath)60 ZEND_GET_MODULE(bcmath)
61 #endif
62 
63 ZEND_INI_MH(OnUpdateScale)
64 {
65 	int *p;
66 	zend_long tmp;
67 
68 	tmp = zend_ini_parse_quantity_warn(new_value, entry->name);
69 	if (tmp < 0 || tmp > INT_MAX) {
70 		return FAILURE;
71 	}
72 
73 	p = (int *) ZEND_INI_GET_ADDR();
74 	*p = (int) tmp;
75 
76 	return SUCCESS;
77 }
78 
79 /* {{{ PHP_INI */
80 PHP_INI_BEGIN()
81 	STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateScale, bc_precision, zend_bcmath_globals, bcmath_globals)
PHP_INI_END()82 PHP_INI_END()
83 /* }}} */
84 
85 /* {{{ PHP_GINIT_FUNCTION */
86 static PHP_GINIT_FUNCTION(bcmath)
87 {
88 #if defined(COMPILE_DL_BCMATH) && defined(ZTS)
89 	ZEND_TSRMLS_CACHE_UPDATE();
90 #endif
91 	bcmath_globals->bc_precision = 0;
92 	bc_init_numbers();
93 }
94 /* }}} */
95 
96 /* {{{ PHP_GSHUTDOWN_FUNCTION */
PHP_GSHUTDOWN_FUNCTION(bcmath)97 static PHP_GSHUTDOWN_FUNCTION(bcmath)
98 {
99 	_bc_free_num_ex(&bcmath_globals->_zero_, 1);
100 	_bc_free_num_ex(&bcmath_globals->_one_, 1);
101 	_bc_free_num_ex(&bcmath_globals->_two_, 1);
102 }
103 /* }}} */
104 
105 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(bcmath)106 PHP_MINIT_FUNCTION(bcmath)
107 {
108 	REGISTER_INI_ENTRIES();
109 
110 	return SUCCESS;
111 }
112 /* }}} */
113 
114 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(bcmath)115 PHP_MSHUTDOWN_FUNCTION(bcmath)
116 {
117 	UNREGISTER_INI_ENTRIES();
118 
119 	return SUCCESS;
120 }
121 /* }}} */
122 
123 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(bcmath)124 PHP_MINFO_FUNCTION(bcmath)
125 {
126 	php_info_print_table_start();
127 	php_info_print_table_row(2, "BCMath support", "enabled");
128 	php_info_print_table_end();
129 	DISPLAY_INI_ENTRIES();
130 }
131 /* }}} */
132 
133 /* {{{ php_str2num
134    Convert to bc_num detecting scale */
php_str2num(bc_num * num,char * str)135 static zend_result php_str2num(bc_num *num, char *str)
136 {
137 	char *p;
138 
139 	if (!(p = strchr(str, '.'))) {
140 		if (!bc_str2num(num, str, 0)) {
141 			return FAILURE;
142 		}
143 
144 		return SUCCESS;
145 	}
146 
147 	if (!bc_str2num(num, str, strlen(p+1))) {
148 		return FAILURE;
149 	}
150 
151 	return SUCCESS;
152 }
153 /* }}} */
154 
155 /* {{{ Returns the sum of two arbitrary precision numbers */
PHP_FUNCTION(bcadd)156 PHP_FUNCTION(bcadd)
157 {
158 	zend_string *left, *right;
159 	zend_long scale_param;
160 	bool scale_param_is_null = 1;
161 	bc_num first, second, result;
162 	int scale;
163 
164 	ZEND_PARSE_PARAMETERS_START(2, 3)
165 		Z_PARAM_STR(left)
166 		Z_PARAM_STR(right)
167 		Z_PARAM_OPTIONAL
168 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
169 	ZEND_PARSE_PARAMETERS_END();
170 
171 	if (scale_param_is_null) {
172 		scale = BCG(bc_precision);
173 	} else if (scale_param < 0 || scale_param > INT_MAX) {
174 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
175 		RETURN_THROWS();
176 	} else {
177 		scale = (int) scale_param;
178 	}
179 
180 	bc_init_num(&first);
181 	bc_init_num(&second);
182 	bc_init_num(&result);
183 
184 	if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
185 		zend_argument_value_error(1, "is not well-formed");
186 		goto cleanup;
187 	}
188 
189 	if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
190 		zend_argument_value_error(2, "is not well-formed");
191 		goto cleanup;
192 	}
193 
194 	bc_add (first, second, &result, scale);
195 
196 	RETVAL_STR(bc_num2str_ex(result, scale));
197 
198 	cleanup: {
199 		bc_free_num(&first);
200 		bc_free_num(&second);
201 		bc_free_num(&result);
202 	};
203 }
204 /* }}} */
205 
206 /* {{{ Returns the difference between two arbitrary precision numbers */
PHP_FUNCTION(bcsub)207 PHP_FUNCTION(bcsub)
208 {
209 	zend_string *left, *right;
210 	zend_long scale_param;
211 	bool scale_param_is_null = 1;
212 	bc_num first, second, result;
213 	int scale;
214 
215 	ZEND_PARSE_PARAMETERS_START(2, 3)
216 		Z_PARAM_STR(left)
217 		Z_PARAM_STR(right)
218 		Z_PARAM_OPTIONAL
219 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
220 	ZEND_PARSE_PARAMETERS_END();
221 
222 	if (scale_param_is_null) {
223 		scale = BCG(bc_precision);
224 	} else if (scale_param < 0 || scale_param > INT_MAX) {
225 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
226 		RETURN_THROWS();
227 	} else {
228 		scale = (int) scale_param;
229 	}
230 
231 	bc_init_num(&first);
232 	bc_init_num(&second);
233 	bc_init_num(&result);
234 
235 	if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
236 		zend_argument_value_error(1, "is not well-formed");
237 		goto cleanup;
238 	}
239 
240 	if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
241 		zend_argument_value_error(2, "is not well-formed");
242 		goto cleanup;
243 	}
244 
245 	bc_sub (first, second, &result, scale);
246 
247 	RETVAL_STR(bc_num2str_ex(result, scale));
248 
249 	cleanup: {
250 		bc_free_num(&first);
251 		bc_free_num(&second);
252 		bc_free_num(&result);
253 	};
254 }
255 /* }}} */
256 
257 /* {{{ Returns the multiplication of two arbitrary precision numbers */
PHP_FUNCTION(bcmul)258 PHP_FUNCTION(bcmul)
259 {
260 	zend_string *left, *right;
261 	zend_long scale_param;
262 	bool scale_param_is_null = 1;
263 	bc_num first, second, result;
264 	int scale;
265 
266 	ZEND_PARSE_PARAMETERS_START(2, 3)
267 		Z_PARAM_STR(left)
268 		Z_PARAM_STR(right)
269 		Z_PARAM_OPTIONAL
270 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
271 	ZEND_PARSE_PARAMETERS_END();
272 
273 	if (scale_param_is_null) {
274 		scale = BCG(bc_precision);
275 	} else if (scale_param < 0 || scale_param > INT_MAX) {
276 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
277 		RETURN_THROWS();
278 	} else {
279 		scale = (int) scale_param;
280 	}
281 
282 	bc_init_num(&first);
283 	bc_init_num(&second);
284 	bc_init_num(&result);
285 
286 	if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
287 		zend_argument_value_error(1, "is not well-formed");
288 		goto cleanup;
289 	}
290 
291 	if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
292 		zend_argument_value_error(2, "is not well-formed");
293 		goto cleanup;
294 	}
295 
296 	bc_multiply (first, second, &result, scale);
297 
298 	RETVAL_STR(bc_num2str_ex(result, scale));
299 
300 	cleanup: {
301 		bc_free_num(&first);
302 		bc_free_num(&second);
303 		bc_free_num(&result);
304 	};
305 }
306 /* }}} */
307 
308 /* {{{ Returns the quotient of two arbitrary precision numbers (division) */
PHP_FUNCTION(bcdiv)309 PHP_FUNCTION(bcdiv)
310 {
311 	zend_string *left, *right;
312 	zend_long scale_param;
313 	bool scale_param_is_null = 1;
314 	bc_num first, second, result;
315 	int scale = BCG(bc_precision);
316 
317 	ZEND_PARSE_PARAMETERS_START(2, 3)
318 		Z_PARAM_STR(left)
319 		Z_PARAM_STR(right)
320 		Z_PARAM_OPTIONAL
321 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
322 	ZEND_PARSE_PARAMETERS_END();
323 
324 	if (scale_param_is_null) {
325 		scale = BCG(bc_precision);
326 	} else if (scale_param < 0 || scale_param > INT_MAX) {
327 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
328 		RETURN_THROWS();
329 	} else {
330 		scale = (int) scale_param;
331 	}
332 
333 	bc_init_num(&first);
334 	bc_init_num(&second);
335 	bc_init_num(&result);
336 
337 	if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
338 		zend_argument_value_error(1, "is not well-formed");
339 		goto cleanup;
340 	}
341 
342 	if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
343 		zend_argument_value_error(2, "is not well-formed");
344 		goto cleanup;
345 	}
346 
347 	if (!bc_divide(first, second, &result, scale)) {
348 		zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
349 		goto cleanup;
350 	}
351 
352 	RETVAL_STR(bc_num2str_ex(result, scale));
353 
354 	cleanup: {
355 		bc_free_num(&first);
356 		bc_free_num(&second);
357 		bc_free_num(&result);
358 	};
359 }
360 /* }}} */
361 
362 /* {{{ Returns the modulus of the two arbitrary precision operands */
PHP_FUNCTION(bcmod)363 PHP_FUNCTION(bcmod)
364 {
365 	zend_string *left, *right;
366 	zend_long scale_param;
367 	bool scale_param_is_null = 1;
368 	bc_num first, second, result;
369 	int scale = BCG(bc_precision);
370 
371 	ZEND_PARSE_PARAMETERS_START(2, 3)
372 		Z_PARAM_STR(left)
373 		Z_PARAM_STR(right)
374 		Z_PARAM_OPTIONAL
375 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
376 	ZEND_PARSE_PARAMETERS_END();
377 
378 	if (scale_param_is_null) {
379 		scale = BCG(bc_precision);
380 	} else if (scale_param < 0 || scale_param > INT_MAX) {
381 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
382 		RETURN_THROWS();
383 	} else {
384 		scale = (int) scale_param;
385 	}
386 
387 	bc_init_num(&first);
388 	bc_init_num(&second);
389 	bc_init_num(&result);
390 
391 	if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
392 		zend_argument_value_error(1, "is not well-formed");
393 		goto cleanup;
394 	}
395 
396 	if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
397 		zend_argument_value_error(2, "is not well-formed");
398 		goto cleanup;
399 	}
400 
401 	if (!bc_modulo(first, second, &result, scale)) {
402 		zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
403 		goto cleanup;
404 	}
405 
406 	RETVAL_STR(bc_num2str_ex(result, scale));
407 
408 	cleanup: {
409 		bc_free_num(&first);
410 		bc_free_num(&second);
411 		bc_free_num(&result);
412 	};
413 }
414 /* }}} */
415 
416 /* {{{ Returns the value of an arbitrary precision number raised to the power of another reduced by a modulus */
PHP_FUNCTION(bcpowmod)417 PHP_FUNCTION(bcpowmod)
418 {
419 	zend_string *base_str, *exponent_str, *modulus_str;
420 	zend_long scale_param;
421 	bool scale_param_is_null = 1;
422 	bc_num bc_base, bc_expo, bc_modulus, result;
423 	int scale = BCG(bc_precision);
424 
425 	ZEND_PARSE_PARAMETERS_START(3, 4)
426 		Z_PARAM_STR(base_str)
427 		Z_PARAM_STR(exponent_str)
428 		Z_PARAM_STR(modulus_str)
429 		Z_PARAM_OPTIONAL
430 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
431 	ZEND_PARSE_PARAMETERS_END();
432 
433 	if (scale_param_is_null) {
434 		scale = BCG(bc_precision);
435 	} else if (scale_param < 0 || scale_param > INT_MAX) {
436 		zend_argument_value_error(4, "must be between 0 and %d", INT_MAX);
437 		RETURN_THROWS();
438 	} else {
439 		scale = (int) scale_param;
440 	}
441 
442 	bc_init_num(&bc_base);
443 	bc_init_num(&bc_expo);
444 	bc_init_num(&bc_modulus);
445 	bc_init_num(&result);
446 
447 	if (php_str2num(&bc_base, ZSTR_VAL(base_str)) == FAILURE) {
448 		zend_argument_value_error(1, "is not well-formed");
449 		goto cleanup;
450 	}
451 
452 	if (php_str2num(&bc_expo, ZSTR_VAL(exponent_str)) == FAILURE) {
453 		zend_argument_value_error(2, "is not well-formed");
454 		goto cleanup;
455 	}
456 
457 	if (php_str2num(&bc_modulus, ZSTR_VAL(modulus_str)) == FAILURE) {
458 		zend_argument_value_error(3, "is not well-formed");
459 		goto cleanup;
460 	}
461 
462 	raise_mod_status status = bc_raisemod(bc_base, bc_expo, bc_modulus, &result, scale);
463 	switch (status) {
464 		case BASE_HAS_FRACTIONAL:
465 			zend_argument_value_error(1, "cannot have a fractional part");
466 			goto cleanup;
467 		case EXPO_HAS_FRACTIONAL:
468 			zend_argument_value_error(2, "cannot have a fractional part");
469 			goto cleanup;
470 		case EXPO_IS_NEGATIVE:
471 			zend_argument_value_error(2, "must be greater than or equal to 0");
472 			goto cleanup;
473 		case MOD_HAS_FRACTIONAL:
474 			zend_argument_value_error(3, "cannot have a fractional part");
475 			goto cleanup;
476 		case MOD_IS_ZERO:
477 			zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
478 			goto cleanup;
479 		case OK:
480 			RETVAL_STR(bc_num2str_ex(result, scale));
481 			break;
482 		EMPTY_SWITCH_DEFAULT_CASE();
483 	}
484 
485 	cleanup: {
486 		bc_free_num(&bc_base);
487 		bc_free_num(&bc_expo);
488 		bc_free_num(&bc_modulus);
489 		bc_free_num(&result);
490 	};
491 }
492 /* }}} */
493 
494 /* {{{ Returns the value of an arbitrary precision number raised to the power of another */
PHP_FUNCTION(bcpow)495 PHP_FUNCTION(bcpow)
496 {
497 	zend_string *base_str, *exponent_str;
498 	zend_long scale_param;
499 	bool scale_param_is_null = 1;
500 	bc_num first, bc_exponent, result;
501 	int scale = BCG(bc_precision);
502 
503 	ZEND_PARSE_PARAMETERS_START(2, 3)
504 		Z_PARAM_STR(base_str)
505 		Z_PARAM_STR(exponent_str)
506 		Z_PARAM_OPTIONAL
507 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
508 	ZEND_PARSE_PARAMETERS_END();
509 
510 	if (scale_param_is_null) {
511 		scale = BCG(bc_precision);
512 	} else if (scale_param < 0 || scale_param > INT_MAX) {
513 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
514 		RETURN_THROWS();
515 	} else {
516 		scale = (int) scale_param;
517 	}
518 
519 	bc_init_num(&first);
520 	bc_init_num(&bc_exponent);
521 	bc_init_num(&result);
522 
523 	if (php_str2num(&first, ZSTR_VAL(base_str)) == FAILURE) {
524 		zend_argument_value_error(1, "is not well-formed");
525 		goto cleanup;
526 	}
527 
528 	if (php_str2num(&bc_exponent, ZSTR_VAL(exponent_str)) == FAILURE) {
529 		zend_argument_value_error(2, "is not well-formed");
530 		goto cleanup;
531 	}
532 
533 	/* Check the exponent for scale digits and convert to a long. */
534 	if (bc_exponent->n_scale != 0) {
535 		zend_argument_value_error(2, "cannot have a fractional part");
536 		goto cleanup;
537 	}
538 	long exponent = bc_num2long(bc_exponent);
539 	if (exponent == 0 && (bc_exponent->n_len > 1 || bc_exponent->n_value[0] != 0)) {
540 		zend_argument_value_error(2, "is too large");
541 		goto cleanup;
542 	}
543 
544 	bc_raise(first, exponent, &result, scale);
545 
546 	RETVAL_STR(bc_num2str_ex(result, scale));
547 
548 	cleanup: {
549 		bc_free_num(&first);
550 		bc_free_num(&bc_exponent);
551 		bc_free_num(&result);
552 	};
553 }
554 /* }}} */
555 
556 /* {{{ Returns the square root of an arbitrary precision number */
PHP_FUNCTION(bcsqrt)557 PHP_FUNCTION(bcsqrt)
558 {
559 	zend_string *left;
560 	zend_long scale_param;
561 	bool scale_param_is_null = 1;
562 	bc_num result;
563 	int scale = BCG(bc_precision);
564 
565 	ZEND_PARSE_PARAMETERS_START(1, 2)
566 		Z_PARAM_STR(left)
567 		Z_PARAM_OPTIONAL
568 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
569 	ZEND_PARSE_PARAMETERS_END();
570 
571 	if (scale_param_is_null) {
572 		scale = BCG(bc_precision);
573 	} else if (scale_param < 0 || scale_param > INT_MAX) {
574 		zend_argument_value_error(2, "must be between 0 and %d", INT_MAX);
575 		RETURN_THROWS();
576 	} else {
577 		scale = (int) scale_param;
578 	}
579 
580 	bc_init_num(&result);
581 
582 	if (php_str2num(&result, ZSTR_VAL(left)) == FAILURE) {
583 		zend_argument_value_error(1, "is not well-formed");
584 		goto cleanup;
585 	}
586 
587 	if (bc_sqrt (&result, scale) != 0) {
588 		RETVAL_STR(bc_num2str_ex(result, scale));
589 	} else {
590 		zend_argument_value_error(1, "must be greater than or equal to 0");
591 	}
592 
593 	cleanup: {
594 		bc_free_num(&result);
595 	};
596 }
597 /* }}} */
598 
599 /* {{{ Compares two arbitrary precision numbers */
PHP_FUNCTION(bccomp)600 PHP_FUNCTION(bccomp)
601 {
602 	zend_string *left, *right;
603 	zend_long scale_param;
604 	bool scale_param_is_null = 1;
605 	bc_num first, second;
606 	int scale = BCG(bc_precision);
607 
608 	ZEND_PARSE_PARAMETERS_START(2, 3)
609 		Z_PARAM_STR(left)
610 		Z_PARAM_STR(right)
611 		Z_PARAM_OPTIONAL
612 		Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
613 	ZEND_PARSE_PARAMETERS_END();
614 
615 	if (scale_param_is_null) {
616 		scale = BCG(bc_precision);
617 	} else if (scale_param < 0 || scale_param > INT_MAX) {
618 		zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
619 		RETURN_THROWS();
620 	} else {
621 		scale = (int) scale_param;
622 	}
623 
624 	bc_init_num(&first);
625 	bc_init_num(&second);
626 
627 	if (!bc_str2num(&first, ZSTR_VAL(left), scale)) {
628 		zend_argument_value_error(1, "is not well-formed");
629 		goto cleanup;
630 	}
631 
632 	if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
633 		zend_argument_value_error(2, "is not well-formed");
634 		goto cleanup;
635 	}
636 
637 	RETVAL_LONG(bc_compare(first, second));
638 
639 	cleanup: {
640 		bc_free_num(&first);
641 		bc_free_num(&second);
642 	};
643 }
644 /* }}} */
645 
646 /* {{{ Sets default scale parameter for all bc math functions */
PHP_FUNCTION(bcscale)647 PHP_FUNCTION(bcscale)
648 {
649 	zend_long old_scale, new_scale;
650 	bool new_scale_is_null = 1;
651 
652 	ZEND_PARSE_PARAMETERS_START(0, 1)
653 		Z_PARAM_OPTIONAL
654 		Z_PARAM_LONG_OR_NULL(new_scale, new_scale_is_null)
655 	ZEND_PARSE_PARAMETERS_END();
656 
657 	old_scale = BCG(bc_precision);
658 
659 	if (!new_scale_is_null) {
660 		if (new_scale < 0 || new_scale > INT_MAX) {
661 			zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
662 			RETURN_THROWS();
663 		}
664 
665 		zend_string *ini_name = ZSTR_INIT_LITERAL("bcmath.scale", 0);
666 		zend_string *new_scale_str = zend_long_to_str(new_scale);
667 		zend_alter_ini_entry(ini_name, new_scale_str, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
668 		zend_string_release(new_scale_str);
669 		zend_string_release(ini_name);
670 	}
671 
672 	RETURN_LONG(old_scale);
673 }
674 /* }}} */
675 
676 
677 #endif
678