Skip to content

ext/bcmath: optimized divmod() and mod() take 2 #18058

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

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
44 changes: 42 additions & 2 deletions ext/bcmath/libbcmath/src/div.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,12 @@ bool bc_divide_ex(bc_num numerator, bc_num divisor, bc_num *quot, bc_num *rem, s
numerator_size -= numerator_leading_zeros;

/* check and remove divisor leading zeros */
size_t divisor_leading_zeros = 0;
while (*divisorptr == 0) {
divisorptr++;
divisor_size--;
divisor_leading_zeros++;
}
divisor_size -= divisor_leading_zeros;

if (divisor_size > numerator_size) {
goto quot_zero;
Expand All @@ -443,8 +445,46 @@ bool bc_divide_ex(bc_num numerator, bc_num divisor, bc_num *quot, bc_num *rem, s
(*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing the high level explanation here on how you compute the remainder length

* If the calculation uses more digits than the scale of rem, writing the vector directly to rem
* will exceed the size, so calculate the excess size in advance.
*/
size_t rem_over_size = 0;

/**
* Conversely, there are cases where the vector does not fill the rem size.
* In this case, the size to be written is calculated in advance to determine the start position for writing to rem.
*/
size_t rem_write_size = 0;

size_t rem_size = 0;
size_t numerator_rem_len_diff = 0;
if (use_rem) {
/* TODO: create bc_num for rem */
size_t divisor_int_size = divisor->n_len > divisor_leading_zeros ? divisor->n_len - divisor_leading_zeros : 0;
size_t divisor_frac_size = divisor->n_scale > divisor_trailing_zeros ? divisor->n_scale - divisor_trailing_zeros : 0;
rem_scale = MIN(MAX(numerator->n_scale, divisor_frac_size), rem_scale);

*rem = bc_new_num_nonzeroed(divisor_int_size > 0 ? divisor_int_size : 1, rem_scale); // 1 is for 0
(*rem)->n_sign = numerator->n_sign;

if (divisor_frac_size > rem_scale) {
rem_over_size = divisor_frac_size - rem_scale;
rem_write_size = (*rem)->n_len + rem_scale;
} else {
if (divisor_frac_size > 0) {
rem_write_size = (*rem)->n_len + divisor_frac_size;
} else {
/* e.g. 123 % 30 */
rem_write_size = (*rem)->n_len - (divisor_trailing_zeros - divisor->n_scale);
}
}

rem_size = (*rem)->n_len + (*rem)->n_scale;
if (rem_size > rem_write_size) {
size_t copy_size = rem_size - rem_write_size;
numerator_rem_len_diff = numerator->n_len - (*rem)->n_len;
memcpy((*rem)->n_value + rem_write_size, numerator->n_value + rem_write_size + numerator_rem_len_diff, copy_size);
}
}

/* Size that can be read from numeratorptr */
Expand Down