Skip to content

Commit 75c2594

Browse files
committed
Apply refcount optimisation to rational and number as well
1 parent a4cbc5b commit 75c2594

File tree

13 files changed

+490
-104
lines changed

13 files changed

+490
-104
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# PHP Decimal Extension
22

3-
[![Build Status](https://travis-ci.org/php-decimal/ext-decimal.svg?branch=master)](https://travis-ci.org/php-decimal/ext-decimal)
3+
[![Build Status](https://travis-ci.org/php-decimal/ext-decimal.svg?branch=2.0)](https://travis-ci.org/php-decimal/ext-decimal)
44
[![Build status](https://ci.appveyor.com/api/projects/status/lg5nw5tqgpmv1c33?svg=true)](https://ci.appveyor.com/project/rtheunissen/php-decimal)
5-
[![PECL](https://img.shields.io/badge/PECL-2.0.0-blue.svg)](https://pecl.php.net/package/decimal)
5+
[![PECL](https://img.shields.io/badge/PECL-2.0.0-alpha-blue.svg)](https://pecl.php.net/package/decimal)
66

77
Correctly-rounded, arbitrary-precision decimal arithmetic for PHP 7
88

benchmarks.php

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ function benchmark(string $action, array $calculations)
8080
echo "time: " . number_format($runtime, 4) . "\t";
8181
echo "result: " . $result;
8282
}
83+
84+
echo "\n";
8385
}
8486
}
8587

@@ -98,18 +100,18 @@ function benchmark(string $action, array $calculations)
98100
DECIMAL => function(array $values): string {
99101
$result = Decimal::valueOf("0", 100);
100102
foreach ($values as $value) {
101-
$result = $result->add($value);
103+
$result += $value;
102104
}
103105
return (string) $result;
104106
},
105107

106-
// RATIONAL => function(array $values): string {
107-
// $result = Rational::valueOf("0");
108-
// foreach ($values as $value) {
109-
// $result = $result + $value;
110-
// }
111-
// return (string) $result;
112-
// },
108+
RATIONAL => function(array $values): string {
109+
$result = Rational::valueOf("0");
110+
foreach ($values as $value) {
111+
$result += $value;
112+
}
113+
return (string) $result;
114+
},
113115
]);
114116

115117
// /**
@@ -170,31 +172,31 @@ function benchmark(string $action, array $calculations)
170172
// },
171173
// ]);
172174

173-
// /**
174-
// * DIVIDE
175-
// */
176-
// benchmark("div", [
177-
// // BC_MATH => function(array $values): string {
178-
// // $result = '1';
179-
// // foreach ($values as $value) {
180-
// // $result = @bcdiv($result, $value, 50);
181-
// // }
182-
// // return (string) $result;
183-
// // },
175+
/**
176+
* DIVIDE
177+
*/
178+
benchmark("div", [
179+
BC_MATH => function(array $values): string {
180+
$result = '1';
181+
foreach ($values as $value) {
182+
$result = @bcdiv($result, $value, 50);
183+
}
184+
return (string) $result;
185+
},
184186

185-
// // DECIMAL => function(array $values): string {
186-
// // $result = Decimal::valueOf('1', 100);
187-
// // foreach ($values as $value) {
188-
// // $result = $result / $value;
189-
// // }
190-
// // return (string) $result;
191-
// // },
187+
DECIMAL => function(array $values): string {
188+
$result = Decimal::valueOf('1', 100);
189+
foreach ($values as $value) {
190+
$result /= $value;
191+
}
192+
return (string) $result;
193+
},
192194

193-
// RATIONAL => function(array $values): string {
194-
// $result = Rational::valueOf("1");
195-
// foreach ($values as $value) {
196-
// $result = $result / $value;
197-
// }
198-
// return (string) $result;
199-
// },
200-
// ]);
195+
RATIONAL => function(array $values): string {
196+
$result = Rational::valueOf("1");
197+
foreach ($values as $value) {
198+
$result /= $value;
199+
}
200+
return (string) $result;
201+
},
202+
]);

package.xml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<name>decimal</name>
44
<channel>pecl.php.net</channel>
55
<summary>Arbitrary precision floating-point decimal</summary>
6-
<description>Adds support for correctly-rounded arbitrary precision decimal floating-point arithmetic in PHP 7</description>
6+
<description>Correctly-rounded arbitrary precision decimal floating-point arithmetic in PHP 7</description>
77
<lead>
88
<name>Rudi Theunissen</name>
99
<user>rtheunissen</user>
@@ -17,15 +17,17 @@
1717
<api>2.0.0</api>
1818
</version>
1919
<stability>
20-
<release>stable</release>
21-
<api>stable</api>
20+
<release>alpha</release>
21+
<api>alpha</api>
2222
</stability>
2323
<license uri="https://opensource.org/licenses/MIT">MIT License</license>
2424
<notes>
2525
- Default decimal precision changed from 28 to 34.
2626
- Decimal operations now use the **minimum** precision of all operands.
2727
- Added `Decimal\Rational` implementation for rational numbers (fractions).
28-
- Added `Decimal\Number` abstract.
28+
- Added `Decimal\Number` abstract class.
29+
- Performance improvements, reduced object allocations.
30+
- Private constructors, static initializers via `valueOf`.
2931
</notes>
3032
<contents>
3133
<dir name="/">

src/decimal.c

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -384,22 +384,6 @@ static php_decimal_success_t php_decimal_cast_object(zval *obj, zval *result, in
384384
}
385385
}
386386

387-
/**
388-
* Determines the decimal object to use for the result of an operation.
389-
*/
390-
static php_decimal_t *php_decimal_get_result_store(zval *obj)
391-
{
392-
/* Create a new decimal if something else relies on this decimal? */
393-
if (Z_REFCOUNT_P(obj) > 1) {
394-
return php_decimal();
395-
}
396-
397-
/* No other reference to $this, so we can re-use it as the result? */
398-
Z_ADDREF_P(obj);
399-
400-
return Z_DECIMAL_P(obj);
401-
}
402-
403387
/**
404388
* Operator overloading.
405389
*
@@ -425,12 +409,7 @@ static php_decimal_success_t php_decimal_do_operation(zend_uchar opcode, zval *r
425409
* intermediary. The goal is to avoid unnecessary allocations.
426410
*
427411
* If either the value we are writing to is unknown or it is referenced by
428-
* something else, we have no choice but to allocate a new decimal object.
429-
*
430-
* TODO: Explain why the zval copy is necessary here. Are we creating a copy
431-
* so that we don't overwrite op1 when we set the result?
432-
*
433-
* TODO: Apply this to rational and number as well?
412+
* something else, we have no choice but to allocate a new object.
434413
*/
435414
if (op1 == result) {
436415
if (EXPECTED(Z_IS_DECIMAL_P(op1)) && Z_REFCOUNT_P(op1) == 1) {
@@ -450,12 +429,10 @@ static php_decimal_success_t php_decimal_do_operation(zend_uchar opcode, zval *r
450429

451430
/* Operation failed - return success to avoid casting. */
452431
if (UNEXPECTED(EG(exception))) {
453-
zval_ptr_dtor(result);
454-
ZVAL_NULL(result);
432+
php_decimal_set_nan(PHP_DECIMAL_MPD(res));
455433
return SUCCESS;
456434
}
457435

458-
/* TODO see above: why is the zval copy necessary here? */
459436
if (op1 == &op1_copy) {
460437
zval_dtor(op1);
461438
}
@@ -468,18 +445,35 @@ static php_decimal_success_t php_decimal_do_operation(zend_uchar opcode, zval *r
468445
/* PARAMETER PARSING */
469446
/******************************************************************************/
470447

448+
/**
449+
* Determines the decimal object to use for the result of an operation.
450+
*/
451+
static php_decimal_t *php_decimal_get_result_store(zval *obj)
452+
{
453+
/* Create a new decimal if something else relies on this decimal? */
454+
if (Z_REFCOUNT_P(obj) > 1) {
455+
return php_decimal();
456+
}
457+
458+
/* No other reference to $this, so we can re-use it as the result? */
459+
Z_ADDREF_P(obj);
460+
461+
return Z_DECIMAL_P(obj);
462+
}
463+
471464
/**
472465
* Parse a decimal binary operation (op1 OP op2).
473466
*/
474467
#define PHP_DECIMAL_PARSE_AND_DO_BINARY_OP(binary_op) do { \
475468
php_decimal_t *res = php_decimal_get_result_store(getThis()); \
469+
zval *op1 = getThis(); \
476470
zval *op2 = NULL; \
477471
\
478472
PHP_DECIMAL_PARSE_PARAMS(1, 1) \
479473
Z_PARAM_ZVAL(op2) \
480474
PHP_DECIMAL_PARSE_PARAMS_END() \
481475
\
482-
php_decimal_do_binary_op(binary_op, res, getThis(), op2); \
476+
php_decimal_do_binary_op(binary_op, res, op1, op2); \
483477
RETURN_DECIMAL(res); \
484478
} while (0)
485479

src/math.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -514,12 +514,15 @@ void php_decimal_radd(
514514
) {
515515
uint32_t status = 0;
516516

517+
PHP_DECIMAL_TEMP_MPD(tmp);
518+
517519
/* a/b + c/d = (a*d + b*c) / (b*d) */
518-
mpd_qmul(rden, den1, num2, MAX_CONTEXT, &status); /* b*c */
519-
mpd_qfma(rnum, num1, den2, rden, MAX_CONTEXT, &status); /* a*d + b*c */
520+
mpd_qmul(&tmp, den1, num2, MAX_CONTEXT, &status); /* b*c */
521+
mpd_qfma(rnum, num1, den2, &tmp, MAX_CONTEXT, &status); /* a*d + b*c */
520522
mpd_qmul(rden, den1, den2, MAX_CONTEXT, &status); /* b*d */
521523

522524
php_decimal_rational_simplify(rnum, rden);
525+
mpd_del(&tmp);
523526
}
524527

525528
void php_decimal_rsub(
@@ -532,13 +535,16 @@ void php_decimal_rsub(
532535
) {
533536
uint32_t status = 0;
534537

538+
PHP_DECIMAL_TEMP_MPD(tmp);
539+
535540
/* a/b - c/d = (a*d - b*c) / (b*d) */
536-
mpd_qmul (rnum, den1, num2, MAX_CONTEXT, &status); /* b*c */
537-
mpd_negate(rnum, rnum, &status); /* */
538-
mpd_qfma (rnum, num1, den2, rnum, MAX_CONTEXT, &status); /* a*d - b*c */
541+
mpd_qmul (&tmp, den1, num2, MAX_CONTEXT, &status); /* b*c */
542+
mpd_negate(&tmp, &tmp, &status); /* */
543+
mpd_qfma (rnum, num1, den2, &tmp, MAX_CONTEXT, &status); /* a*d - b*c */
539544
mpd_qmul (rden, den1, den2, MAX_CONTEXT, &status); /* b*d */
540545

541546
php_decimal_rational_simplify(rnum, rden);
547+
mpd_del(&tmp);
542548
}
543549

544550
void php_decimal_rmul(
@@ -734,10 +740,13 @@ void php_decimal_rshiftl(
734740
) {
735741
uint32_t status = 0;
736742

743+
PHP_DECIMAL_TEMP_MPD(tmp);
744+
737745
/* We can assume that den2 is 1 - can only shift by integer */
738-
mpd_qdivint(rnum, num2, den2, MAX_CONTEXT, &status);
739-
mpd_qscaleb(rnum, num1, rnum, MAX_CONTEXT, &status);
746+
mpd_qdivint(&tmp, num2, den2, MAX_CONTEXT, &status);
747+
mpd_qscaleb(rnum, num1, &tmp, MAX_CONTEXT, &status);
740748
mpd_qcopy (rden, den1, &status);
749+
mpd_del(&tmp);
741750

742751
php_decimal_rational_normalize(rnum, rden);
743752
php_decimal_rational_simplify(rnum, rden);
@@ -753,11 +762,14 @@ void php_decimal_rshiftr(
753762
) {
754763
uint32_t status = 0;
755764

765+
PHP_DECIMAL_TEMP_MPD(tmp);
766+
756767
/* We can assume that den2 is 1 - can only shift by integer */
757-
mpd_qdivint(rnum, num2, den2, MAX_CONTEXT, &status);
758-
mpd_negate (rnum, rnum, &status);
759-
mpd_qscaleb(rnum, num1, rnum, MAX_CONTEXT, &status);
768+
mpd_qdivint(&tmp, num2, den2, MAX_CONTEXT, &status);
769+
mpd_negate (&tmp, &tmp, &status);
770+
mpd_qscaleb(rnum, num1, &tmp, MAX_CONTEXT, &status);
760771
mpd_qcopy (rden, den1, &status);
772+
mpd_del(&tmp);
761773

762774
php_decimal_rational_normalize(rnum, rden);
763775
php_decimal_rational_simplify(rnum, rden);

0 commit comments

Comments
 (0)