Skip to content

Commit ead66ef

Browse files
committed
Refactored divide
1 parent 19e09bb commit ead66ef

File tree

2 files changed

+101
-144
lines changed

2 files changed

+101
-144
lines changed

ext/bcmath/libbcmath/src/convert.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,32 @@ static inline void bc_convert_to_vector(BC_VECTOR *n_vector, const char *nend, s
5757
}
5858
}
5959

60+
static inline void bc_convert_to_vector_with_zero_pad(BC_VECTOR *n_vector, const char *nend, size_t nlen, size_t zeros)
61+
{
62+
while (zeros >= BC_VECTOR_SIZE) {
63+
*n_vector = 0;
64+
n_vector++;
65+
zeros -= BC_VECTOR_SIZE;
66+
}
67+
68+
if (zeros > 0) {
69+
*n_vector = 0;
70+
BC_VECTOR base = BC_POW_10_LUT[zeros];
71+
size_t tmp_len = MIN(BC_VECTOR_SIZE - zeros, nlen);
72+
for (size_t i = 0; i < tmp_len; i++) {
73+
*n_vector += *nend * base;
74+
base *= BASE;
75+
nend--;
76+
}
77+
n_vector++;
78+
nlen -= tmp_len;
79+
}
80+
81+
if (nlen == 0) {
82+
return;
83+
}
84+
85+
bc_convert_to_vector(n_vector, nend, nlen);
86+
}
87+
6088
#endif

ext/bcmath/libbcmath/src/div.c

Lines changed: 73 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -251,58 +251,39 @@ static inline void bc_standard_div(
251251
}
252252

253253
static void bc_do_div(
254-
const char *numerator, size_t numerator_readable_len, size_t numerator_bottom_extension,
255-
const char *divisor, size_t divisor_len, bc_num *quot, size_t quot_len
254+
const char *numerator, size_t numerator_size, size_t numerator_readable_size,
255+
const char *divisor, size_t divisor_size,
256+
bc_num *quot, size_t quot_size
256257
) {
257-
size_t divisor_arr_size = (divisor_len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;
258-
size_t numerator_arr_size = (numerator_readable_len + numerator_bottom_extension + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;
258+
size_t numerator_arr_size = (numerator_size + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;
259+
size_t divisor_arr_size = (divisor_size + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE;
259260
size_t quot_arr_size = numerator_arr_size - divisor_arr_size + 1;
260-
size_t quot_real_arr_size = MIN(quot_arr_size, (quot_len + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE);
261+
size_t quot_real_arr_size = MIN(quot_arr_size, (quot_size + BC_VECTOR_SIZE - 1) / BC_VECTOR_SIZE);
261262

262263
BC_VECTOR *numerator_vectors = safe_emalloc(numerator_arr_size + divisor_arr_size + quot_arr_size, sizeof(BC_VECTOR), 0);
263264
BC_VECTOR *divisor_vectors = numerator_vectors + numerator_arr_size;
264265
BC_VECTOR *quot_vectors = divisor_vectors + divisor_arr_size;
265266

266-
/* Fill with zeros and convert as many vector elements as needed */
267-
size_t numerator_vector_count = 0;
268-
while (numerator_bottom_extension >= BC_VECTOR_SIZE) {
269-
numerator_vectors[numerator_vector_count] = 0;
270-
numerator_bottom_extension -= BC_VECTOR_SIZE;
271-
numerator_vector_count++;
272-
}
273-
274-
size_t numerator_bottom_read_len = BC_VECTOR_SIZE - numerator_bottom_extension;
275-
276-
size_t base;
277-
size_t numerator_read = 0;
278-
if (numerator_bottom_read_len < BC_VECTOR_SIZE) {
279-
numerator_read = MIN(numerator_bottom_read_len, numerator_readable_len);
280-
base = BC_POW_10_LUT[numerator_bottom_extension];
281-
numerator_vectors[numerator_vector_count] = 0;
282-
for (size_t i = 0; i < numerator_read; i++) {
283-
numerator_vectors[numerator_vector_count] += *numerator * base;
284-
base *= BASE;
285-
numerator--;
286-
}
287-
numerator_vector_count++;
288-
}
267+
size_t numerator_extension = numerator_size > numerator_readable_size ? numerator_size - numerator_readable_size : 0;
289268

290269
/* Bulk convert numerator and divisor to vectors */
291-
if (numerator_readable_len > numerator_read) {
292-
bc_convert_to_vector(numerator_vectors + numerator_vector_count, numerator, numerator_readable_len - numerator_read);
293-
}
294-
bc_convert_to_vector(divisor_vectors, divisor, divisor_len);
270+
size_t numerator_use_size = numerator_size - numerator_extension;
271+
const char *numerator_end = numerator + numerator_use_size - 1;
272+
bc_convert_to_vector_with_zero_pad(numerator_vectors, numerator_end, numerator_use_size, numerator_extension);
273+
274+
const char *divisor_end = divisor + divisor_size - 1;
275+
bc_convert_to_vector(divisor_vectors, divisor_end, divisor_size);
295276

296277
/* Do the division */
297278
if (divisor_arr_size == 1) {
298279
bc_fast_div(numerator_vectors, numerator_arr_size, divisor_vectors[0], quot_vectors, quot_arr_size);
299280
} else {
300-
bc_standard_div(numerator_vectors, numerator_arr_size, divisor_vectors, divisor_arr_size, divisor_len, quot_vectors, quot_arr_size);
281+
bc_standard_div(numerator_vectors, numerator_arr_size, divisor_vectors, divisor_arr_size, divisor_size, quot_vectors, quot_arr_size);
301282
}
302283

303284
/* Convert to bc_num */
304285
char *qptr = (*quot)->n_value;
305-
char *qend = qptr + quot_len - 1;
286+
char *qend = qptr + (*quot)->n_len + (*quot)->n_scale - 1;
306287

307288
size_t i;
308289
for (i = 0; i < quot_real_arr_size - 1; i++) {
@@ -332,166 +313,114 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale)
332313
}
333314

334315
bc_free_num(quot);
316+
size_t quot_scale = scale;
335317

336318
/* If numerator is zero, the quotient is always zero. */
337319
if (bc_is_zero(numerator)) {
338-
*quot = bc_copy_num(BCG(_zero_));
339-
return true;
320+
goto quot_zero;
340321
}
341322

342323
/* If divisor is 1 / -1, the quotient's n_value is equal to numerator's n_value. */
343324
if (_bc_do_compare(divisor, BCG(_one_), divisor->n_scale, false) == BCMATH_EQUAL) {
344-
size_t quot_scale = MIN(numerator->n_scale, scale);
325+
quot_scale = MIN(numerator->n_scale, quot_scale);
345326
*quot = bc_new_num_nonzeroed(numerator->n_len, quot_scale);
346327
char *qptr = (*quot)->n_value;
347328
memcpy(qptr, numerator->n_value, numerator->n_len + quot_scale);
348329
(*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
349-
_bc_rm_leading_zeros(*quot);
350330
return true;
351331
}
352332

353333
char *numeratorptr = numerator->n_value;
354-
char *numeratorend = numeratorptr + numerator->n_len + numerator->n_scale - 1;
355-
size_t numerator_len = numerator->n_len;
356-
size_t numerator_scale = numerator->n_scale;
334+
size_t numerator_size = numerator->n_len + quot_scale + divisor->n_scale;
357335

358336
char *divisorptr = divisor->n_value;
359-
char *divisorend = divisorptr + divisor->n_len + divisor->n_scale - 1;
360-
size_t divisor_len = divisor->n_len;
361-
size_t divisor_scale = divisor->n_scale;
362-
size_t divisor_int_right_zeros = 0;
363-
364-
/* remove divisor trailing zeros */
365-
while (*divisorend == 0 && divisor_scale > 0) {
366-
divisorend--;
367-
divisor_scale--;
368-
}
369-
while (*divisorend == 0) {
370-
divisorend--;
371-
divisor_int_right_zeros++;
372-
}
337+
size_t divisor_size = divisor->n_len + divisor->n_scale;
373338

374-
if (*numeratorptr == 0 && numerator_len == 1) {
339+
/* check and remove numerator leading zeros */
340+
size_t numerator_leading_zeros = 0;
341+
while (*numeratorptr == 0) {
375342
numeratorptr++;
376-
numerator_len = 0;
343+
numerator_leading_zeros++;
377344
}
378-
379-
size_t numerator_top_extension = 0;
380-
size_t numerator_bottom_extension = 0;
381-
if (divisor_scale > 0) {
382-
/*
383-
* e.g. divisor_scale = 4
384-
* divisor = .0002, to be 2 or divisor = 200.001, to be 200001
385-
* numerator = .03, to be 300 or numerator = .000003, to be .03
386-
* numerator may become longer than the original data length due to the addition of
387-
* trailing zeros in the integer part.
388-
*/
389-
numerator_len += divisor_scale;
390-
numerator_bottom_extension = numerator_scale < divisor_scale ? divisor_scale - numerator_scale : 0;
391-
numerator_scale = numerator_scale > divisor_scale ? numerator_scale - divisor_scale : 0;
392-
divisor_len += divisor_scale;
393-
divisor_scale = 0;
394-
} else if (divisor_int_right_zeros > 0) {
395-
/*
396-
* e.g. divisor_int_right_zeros = 4
397-
* divisor = 2000, to be 2
398-
* numerator = 30, to be .03 or numerator = 30000, to be 30
399-
* Also, numerator may become longer than the original data length due to the addition of
400-
* leading zeros in the fractional part.
401-
*/
402-
numerator_top_extension = numerator_len < divisor_int_right_zeros ? divisor_int_right_zeros - numerator_len : 0;
403-
numerator_len = numerator_len > divisor_int_right_zeros ? numerator_len - divisor_int_right_zeros : 0;
404-
numerator_scale += divisor_int_right_zeros;
405-
divisor_len -= divisor_int_right_zeros;
406-
divisor_scale = 0;
345+
if (numerator_size > numerator_leading_zeros) {
346+
numerator_size -= numerator_leading_zeros;
347+
} else {
348+
goto quot_zero;
407349
}
408350

409-
/* remove numerator leading zeros */
410-
while (*numeratorptr == 0 && numerator_len > 0) {
411-
numeratorptr++;
412-
numerator_len--;
413-
}
414-
/* remove divisor leading zeros */
351+
/* check and remove divisor leading zeros */
415352
while (*divisorptr == 0) {
416353
divisorptr++;
417-
divisor_len--;
354+
divisor_size--;
418355
}
419356

420-
/* Considering the scale specification, the quotient is always 0 if this condition is met */
421-
if (divisor_len > numerator_len + scale) {
422-
*quot = bc_copy_num(BCG(_zero_));
423-
return true;
357+
if (divisor_size > numerator_size) {
358+
goto quot_zero;
424359
}
425360

426-
/* Length of numerator data that can be read */
427-
size_t numerator_readable_len = numeratorend - numeratorptr + 1;
428-
429-
/* set scale to numerator */
430-
if (numerator_scale > scale) {
431-
size_t scale_diff = numerator_scale - scale;
432-
if (numerator_bottom_extension > scale_diff) {
433-
numerator_bottom_extension -= scale_diff;
434-
} else {
435-
numerator_bottom_extension = 0;
436-
if (EXPECTED(numerator_readable_len > scale_diff)) {
437-
numerator_readable_len -= scale_diff;
438-
numeratorend -= scale_diff;
439-
} else {
440-
numerator_readable_len = 0;
441-
numeratorend = numeratorptr;
442-
}
361+
/* check and remove divisor trailing zeros. The divisor is not 0, so leave only one digit */
362+
size_t divisor_trailing_zeros = 0;
363+
for (size_t i = divisor_size - 1; i > 0; i--) {
364+
if (divisorptr[i] != 0) {
365+
break;
443366
}
444-
numerator_top_extension = MIN(numerator_top_extension, scale);
367+
divisor_trailing_zeros++;
368+
}
369+
divisor_size -= divisor_trailing_zeros;
370+
371+
if (numerator_size > divisor_trailing_zeros) {
372+
numerator_size -= divisor_trailing_zeros;
445373
} else {
446-
numerator_bottom_extension += scale - numerator_scale;
374+
goto quot_zero;
447375
}
448-
numerator_scale = scale;
449376

450-
if (divisor_len > numerator_readable_len + numerator_bottom_extension) {
451-
*quot = bc_copy_num(BCG(_zero_));
452-
return true;
377+
size_t quot_size = numerator_size - divisor_size + 1; // numerator_size >= divisor_size
378+
if (quot_size > quot_scale) {
379+
*quot = bc_new_num_nonzeroed(quot_size - quot_scale, quot_scale);
380+
} else {
381+
*quot = bc_new_num_nonzeroed(1, quot_scale); // 1 is for 0
453382
}
454383

455-
/* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */
456-
if (divisor_len == 1 && *divisorptr == 1) {
457-
if (numerator_len == 0) {
458-
numerator_len = 1;
459-
numerator_top_extension++;
460-
}
461-
size_t quot_scale = numerator_scale > numerator_bottom_extension ? numerator_scale - numerator_bottom_extension : 0;
462-
numerator_bottom_extension = numerator_scale < numerator_bottom_extension ? numerator_bottom_extension - numerator_scale : 0;
384+
/* Size that can be read from numeratorptr */
385+
size_t numerator_readable_size = numerator->n_len + numerator->n_scale - numerator_leading_zeros;
463386

464-
*quot = bc_new_num_nonzeroed(numerator_len, quot_scale);
387+
/* If divisor is 1 here, return the result of adjusting the decimal point position of numerator. */
388+
if (divisor_size == 1 && *divisorptr == 1) {
465389
char *qptr = (*quot)->n_value;
466-
for (size_t i = 0; i < numerator_top_extension; i++) {
390+
if (quot_size <= quot_scale) {
391+
/* int is 0 */
467392
*qptr++ = 0;
393+
for (size_t i = quot_size; i < quot_scale; i++) {
394+
*qptr++ = 0;
395+
}
468396
}
469-
memcpy(qptr, numeratorptr, numerator_readable_len);
470-
qptr += numerator_readable_len;
471-
for (size_t i = 0; i < numerator_bottom_extension; i++) {
397+
size_t numerator_use_size = quot_size > numerator_readable_size ? numerator_readable_size : quot_size;
398+
memcpy(qptr, numeratorptr, numerator_use_size);
399+
qptr += numerator_use_size;
400+
for (size_t i = 0; i < quot_size - numerator_use_size; i++) {
472401
*qptr++ = 0;
473402
}
474403
(*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
475404
return true;
476405
}
477406

478-
size_t quot_full_len;
479-
if (divisor_len > numerator_len) {
480-
*quot = bc_new_num_nonzeroed(1, scale);
481-
quot_full_len = 1 + scale;
482-
} else {
483-
*quot = bc_new_num_nonzeroed(numerator_len - divisor_len + 1, scale);
484-
quot_full_len = numerator_len - divisor_len + 1 + scale;
485-
}
486-
487407
/* do divide */
488-
bc_do_div(numeratorend, numerator_readable_len, numerator_bottom_extension, divisorend, divisor_len, quot, quot_full_len);
408+
bc_do_div(
409+
numeratorptr, numerator_size, numerator_readable_size,
410+
divisorptr, divisor_size,
411+
quot, quot_size
412+
);
413+
489414
_bc_rm_leading_zeros(*quot);
490415
if (bc_is_zero(*quot)) {
491-
(*quot)->n_sign = PLUS;
416+
bc_free_num(quot);
417+
goto quot_zero;
492418
} else {
493419
(*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS;
494420
}
421+
return true;
495422

423+
quot_zero:
424+
*quot = bc_copy_num(BCG(_zero_));
496425
return true;
497426
}

0 commit comments

Comments
 (0)