-
Notifications
You must be signed in to change notification settings - Fork 7.9k
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
base: master
Are you sure you want to change the base?
Conversation
345c1ed
to
d94dcc9
Compare
f0e9762
to
783c7e7
Compare
783c7e7
to
aa49dc2
Compare
…ctions to use it.
aa49dc2
to
d3a5713
Compare
Conflict resolved |
@@ -425,9 +425,6 @@ bool bc_divide_ex(bc_num numerator, bc_num divisor, bc_num *quot, bc_num *rem, s | |||
_bc_rm_leading_zeros(*quot); | |||
if (bc_is_zero(*quot)) { | |||
(*quot)->n_sign = PLUS; | |||
(*quot)->n_scale = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You no longer reset the scale in this case, but you only removed the leading zeros (on line 425) and not the trailing zeros. Can you explain please?
size_t quot_scale = scale; | ||
if (use_quot) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using a separate argument for use_quot, use_rem. Why not check if quot/rem is a NULL pointer?
_bc_rm_leading_zeros(*quot); | ||
if (bc_is_zero(*quot)) { | ||
(*quot)->n_sign = PLUS; | ||
(*quot)->n_scale = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess my previous question is answered because this line returned, but you should instead amend the previous commit so that it wasn't deleted in the first place. That keeps the history cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I think a line was accidentally removed when I rebased and merged in master.
I had only reviewed the final version of the code, so I didn’t notice that one of the intermediate commits included an unintended deletion.
@@ -111,4 +111,30 @@ static inline void bc_convert_vector_to_char(const BC_VECTOR *vector, char *nptr | |||
} | |||
} | |||
|
|||
static inline void bc_convert_vector_to_char_with_skip(const BC_VECTOR *vector, char *nptr, char *nend, size_t arr_size, size_t skip) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function either needs a better name or a doc block explaining what it does on a high level. What is skip and why is it necessary? I don't know at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, if BC_VECTOR = [7890, 3456, 12]
, and want to construct a char
array like 1234567
, need to skip three digits 890
in 7890
.
This kind of skipping is necessary when storing the rem
(from division) into a char
array, especially when the number of digits in BC_VECTOR
doesn’t match the required scale
for the rem
.
↑ Would this explanation be clear enough to convey the intent?
ext/bcmath/libbcmath/src/div.c
Outdated
@@ -255,7 +255,8 @@ static inline void bc_standard_div( | |||
static void bc_do_div( | |||
const char *numerator, size_t numerator_size, size_t numerator_readable_size, | |||
const char *divisor, size_t divisor_size, | |||
bc_num *quot, size_t quot_size | |||
bc_num *quot, size_t quot_size, | |||
bool use_quot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same remark about the quot NULL pointer instead of the bool
@@ -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; | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
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
*rem = bc_copy_num(BCG(_zero_)); | ||
return; | ||
} | ||
/* The values after this have already been copied, so just need to set them to 0. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied by whom?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About 10 lines above the line where this function is called, there’s the following line:
memcpy((*rem)->n_value + rem_write_size, numerator->n_value + rem_write_size + numerator_rem_len_diff, copy_size);
The intention here was that everything except the leading zeros has already been copied.
char *rptr = (*rem)->n_value; | ||
char *rend = rptr + rem_write_size - 1; | ||
|
||
size_t rem_arr_size = (rem_write_size + rem_over_size + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't we have a macro for the rounding-up divide ?
BC_VECTOR *rem_vectors = numerator_vectors; | ||
|
||
if (rem_over_size > 0) { | ||
bc_convert_vector_to_char_with_skip(rem_vectors, rptr, rend, rem_arr_size, rem_over_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't understand the skip
Overall, the way we calculate the number of digits in I’ll think about whether there’s a better approach, or at least a clearer way to explain it in comments. |
Benchmarks
1:
2:
3:
div
In theory, it will be slower because there are more branches, but it seems to make little difference.
1:
2:
3:
divmod
This is faster because there are no extra calculations involved.
1:
2:
3:
mod
It's faster for the same reasons as divmod, and it's even faster because it doesn't need to generate
bc_num
for quot.1:
2:
3: