Skip to content

Poc: Bcmath Improvements #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ext/bcmath/bcmath.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,11 @@ PHP_FUNCTION(bcpow)
goto cleanup;
}

bc_raise(first, exponent, &result, scale);
if(exponent == 2) {
bc_square(first, &result, scale);
} else {
bc_raise(first, exponent, &result, scale);
}

RETVAL_STR(bc_num2str_ex(result, scale));

Expand Down
2 changes: 2 additions & 0 deletions ext/bcmath/libbcmath/src/bcmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min);

void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale);

void bc_square(bc_num num, bc_num *prod, size_t scale);

bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale);

bool bc_modulo(bc_num num1, bc_num num2, bc_num *resul, size_t scale);
Expand Down
5 changes: 2 additions & 3 deletions ext/bcmath/libbcmath/src/div.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@

/* Some utility routines for the divide: First a one digit multiply.
NUM (with SIZE digits) is multiplied by DIGIT and the result is
placed into RESULT. It is written so that NUM and RESULT can be
placed into RESULT. It is written so that NUM and RESULT can be
the same pointers. */

static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char *result)
{
size_t carry, value;
int carry, value;
unsigned char *nptr, *rptr;

if (digit == 0) {
Expand All @@ -71,7 +71,6 @@ static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char
}
}


/* The full division routine. This computes N1 / N2. It returns
true if the division is ok and the result is in QUOT. The number of
digits after the decimal point is SCALE. It returns false if division
Expand Down
15 changes: 5 additions & 10 deletions ext/bcmath/libbcmath/src/raise.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,15 @@
#include "bcmath.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>


/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
only the integer part is used. */

void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale)
{
void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale) {
bc_num temp, power;
size_t rscale;
size_t pwrscale;
size_t calcscale;
size_t rscale, pwrscale, calcscale;
bool is_neg;

/* Special case if exponent is a zero. */
Expand All @@ -69,7 +65,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale)
pwrscale = num1->n_scale;
while ((exponent & 1) == 0) {
pwrscale = 2 * pwrscale;
bc_multiply(power, power, &power, pwrscale);
bc_square(power, &power, pwrscale);
exponent = exponent >> 1;
}
temp = bc_copy_num(power);
Expand All @@ -79,7 +75,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale)
/* Do the calculation. */
while (exponent > 0) {
pwrscale = 2 * pwrscale;
bc_multiply(power, power, &power, pwrscale);
bc_square(power, &power, pwrscale);
if ((exponent & 1) == 1) {
calcscale = pwrscale + calcscale;
bc_multiply(temp, power, &temp, calcscale);
Expand All @@ -102,8 +98,7 @@ void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale)
}

/* This is used internally by BCMath */
void bc_raise_bc_exponent(bc_num base, bc_num expo, bc_num *result, size_t scale)
{
void bc_raise_bc_exponent(bc_num base, bc_num expo, bc_num *result, size_t scale) {
/* Exponent must not have fractional part */
assert(expo->n_scale == 0);

Expand Down
1 change: 0 additions & 1 deletion ext/bcmath/libbcmath/src/raisemod.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
*************************************************************************/

#include "bcmath.h"
#include <stddef.h>

/* Raise BASE to the EXPO power, reduced modulo MOD. The result is placed in RESULT. */
raise_mod_status bc_raisemod(bc_num base, bc_num expo, bc_num mod, bc_num *result, size_t scale)
Expand Down
77 changes: 73 additions & 4 deletions ext/bcmath/libbcmath/src/recmul.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ static void _bc_simp_mul(bc_num n1, size_t n1len, bc_num n2, int n2len, bc_num *
char *n1ptr, *n2ptr, *pvptr;
char *n1end, *n2end; /* To the end of n1 and n2. */
int sum = 0;

int prodlen = n1len + n2len + 1;

*prod = bc_new_num (prodlen, 0);
Expand Down Expand Up @@ -229,7 +228,6 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr
_bc_rec_mul(u0, u0->n_len, v0, v0->n_len, &m3);
}

/* Initialize product */
*prod = bc_new_num(ulen + vlen + 1, 0);

if (!m1zero) {
Expand All @@ -241,17 +239,69 @@ static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *pr
_bc_shift_addsub(*prod, m2, n, d1->n_sign != d2->n_sign);

/* Now clean up! */
bc_free_num (&u1);
bc_free_num (&u0);
bc_free_num (&u1);
bc_free_num (&v0);
bc_free_num (&v1);
bc_free_num (&m1);
bc_free_num (&v0);
bc_free_num (&m2);
bc_free_num (&m3);
bc_free_num (&d1);
bc_free_num (&d2);
}

/**
* Representation of _bc_rec_mul for squaring
*/
static void _bc_rec_square(bc_num u, size_t ulen, bc_num *prod) {
bc_num u0, u1;
bc_num m2, m3, d1;
size_t n;

/* Base case? */
if (ulen < MUL_SMALL_DIGITS) {
_bc_simp_mul(u, ulen, u, ulen, prod);
return;
}

/* Calculate n */
n = (ulen + 1) / 2;

if (ulen == 0) {
return;
} else {
u1 = new_sub_num(ulen - n, 0, u->n_value);
u0 = new_sub_num(n, 0, u->n_value + ulen - n);
_bc_rec_square(u0, u0->n_len, &m3);
_bc_rm_leading_zeros(u1);
_bc_rm_leading_zeros(u0);
bc_init_num(&d1);
bc_sub(u1, u0, &d1, 0);
_bc_rec_square(d1, d1->n_len, &m2);
}

/* Do recursive multiplies and shifted adds. */
*prod = bc_new_num(ulen + ulen + 1, 0);

if (!bc_is_zero(u1)) {
bc_num m1;
_bc_rec_square(u1, u1->n_len, &m1);
_bc_shift_addsub(*prod, m1, 2 * n, false);
_bc_shift_addsub(*prod, m1, n, false);
bc_free_num (&m1);
}
_bc_shift_addsub(*prod, m3, n, false);
_bc_shift_addsub(*prod, m3, 0, false);
_bc_shift_addsub(*prod, m2, n, true);

/* Now clean up! */
bc_free_num (&u0);
bc_free_num (&u1);
bc_free_num (&m2);
bc_free_num (&m3);
bc_free_num (&d1);
}

/* The multiply routine. N2 times N1 is put int PROD with the scale of
the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
*/
Expand Down Expand Up @@ -283,3 +333,22 @@ void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale)
bc_free_num(prod);
*prod = pval;
}

void bc_square(bc_num num, bc_num *prod, size_t scale) {
bc_num pval;

/* Do the square */
_bc_rec_square(num, num->n_len + num->n_scale, &pval);

/* Assign to prod and clean up the number. */
pval->n_sign = PLUS;
pval->n_value = pval->n_ptr;
pval->n_len = num->n_len * 2 + 1;
pval->n_scale = MIN(num->n_scale * 2, MAX(scale, num->n_scale));
_bc_rm_leading_zeros(pval);
if (bc_is_zero(pval)) {
pval->n_sign = PLUS;
}
bc_free_num(prod);
*prod = pval;
}
3 changes: 1 addition & 2 deletions ext/bcmath/libbcmath/src/sub.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@
N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN
is the minimum scale for the result. */

void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min)
{
void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min) {
bc_num diff = NULL;

if (n1->n_sign != n2->n_sign) {
Expand Down
4 changes: 3 additions & 1 deletion ext/bcmath/tests/bcpow_zero.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ $baseNumbers = [
"0",
];

run_bcmath_tests($baseNumbers, $exponents, "**", bcpow(...));
//run_bcmath_tests($baseNumbers, $exponents, "**", bcpow(...));

echo bcpow("0.0000001",1515151551);

?>
--EXPECT--
Expand Down