@@ -2,57 +2,6 @@ module big
22
33import math.bits
44
5- // suppose operand_a bigger than operand_b and both not null.
6- // Both quotient and remaider are allocated but of length 0
7- @[direct_array_access]
8- fn binary_divide_array_by_array (operand_a []u64 , operand_b []u64 , mut quotient []u64 , mut remainder []u64 ) {
9- remainder << operand_a
10-
11- len_diff := operand_a.len - operand_b.len
12- $if debug {
13- assert len_diff > = 0
14- }
15-
16- // we must do in place shift and operations.
17- mut divisor := []u64 {cap: operand_b.len}
18- for _ in 0 .. len_diff {
19- divisor << u64 (0 )
20- }
21- divisor << operand_b
22- for _ in 0 .. len_diff + 1 {
23- quotient << u64 (0 )
24- }
25-
26- lead_zer_remainder := u32 (bits.leading_zeros_64 (remainder.last ()) - (64 - digit_bits))
27- lead_zer_divisor := u32 (bits.leading_zeros_64 (divisor.last ()) - (64 - digit_bits))
28- bit_offset := (u32 (digit_bits) * u32 (len_diff)) + (lead_zer_divisor - lead_zer_remainder)
29-
30- // align
31- if lead_zer_remainder < lead_zer_divisor {
32- left_shift_in_place (mut divisor, lead_zer_divisor - lead_zer_remainder)
33- } else if lead_zer_remainder > lead_zer_divisor {
34- left_shift_in_place (mut remainder, lead_zer_remainder - lead_zer_divisor)
35- }
36-
37- $if debug {
38- assert left_align_p (divisor[divisor.len - 1 ], remainder[remainder.len - 1 ])
39- }
40- for bit_idx := int (bit_offset); bit_idx > = 0 ; bit_idx-- {
41- if greater_equal_from_end (remainder, divisor) {
42- bit_set (mut quotient, bit_idx)
43- subtract_align_last_byte_in_place (mut remainder, divisor)
44- }
45- right_shift_in_place (mut divisor, 1 )
46- }
47-
48- // adjust
49- if lead_zer_remainder > lead_zer_divisor {
50- right_shift_in_place (mut remainder, lead_zer_remainder - lead_zer_divisor)
51- }
52- shrink_tail_zeros (mut remainder)
53- shrink_tail_zeros (mut quotient)
54- }
55-
565// help routines for cleaner code but inline for performance
576// quicker than BitField.set_bit
587@[direct_array_access; inline]
@@ -65,80 +14,112 @@ fn bit_set(mut a []u64, n int) {
6514 a[byte_offset] |= mask
6615}
6716
68- // a.len is greater or equal to b.len
69- // returns true if a >= b (completed with zeroes)
70- @[direct_array_access; inline]
71- fn greater_equal_from_end (a []u64 , b []u64 ) bool {
72- $if debug {
73- assert a.len > = b.len
74- }
75- offset := a.len - b.len
76- for index := a.len - 1 ; index > = offset; index-- {
77- if a[index] > b[index - offset] {
78- return true
79- } else if a[index] < b[index - offset] {
80- return false
81- }
82- }
83- return true
84- }
17+ @[direct_array_access]
18+ fn knuth_divide_array_by_array (operand_a []u64 , operand_b []u64 , mut quotient []u64 , mut remainder []u64 ) {
19+ m := operand_a.len - operand_b.len
20+ n := operand_b.len
21+ mut u := []u64 {len: operand_a.len + 1 }
22+ mut v := []u64 {len: n}
23+ leading_zeros := bits.leading_zeros_64 (operand_b.last ()) - (64 - digit_bits)
8524
86- // a := a - b supposed a >= b
87- // attention the b operand is align with the a operand before the subtraction
88- @[direct_array_access; inline]
89- fn subtract_align_last_byte_in_place (mut a []u64 , b []u64 ) {
90- mut carry := u64 (0 )
91- mut new_carry := u64 (0 )
92- offset := a.len - b.len
93- for index := a.len - b.len; index < a.len; index++ {
94- if a[index] < (b[index - offset] + carry) || (b[index - offset] == max_digit && carry > 0 ) {
95- new_carry = 1
96- } else {
97- new_carry = 0
25+ if leading_zeros > 0 {
26+ mut carry := u64 (0 )
27+ amount := digit_bits - leading_zeros
28+ for i in 0 .. operand_a.len {
29+ temp := (operand_a[i] << leading_zeros) | carry
30+ u[i] = temp & max_digit
31+ carry = operand_a[i] >> amount
32+ }
33+ u[operand_a.len] = carry
34+ carry = 0
35+ for i in 0 .. operand_b.len {
36+ temp := (operand_b[i] << leading_zeros) | carry
37+ v[i] = temp & max_digit
38+ carry = operand_b[i] >> amount
39+ }
40+ } else {
41+ for i in 0 .. operand_a.len {
42+ u[i] = operand_a[i]
43+ }
44+ for i in 0 .. operand_b.len {
45+ v[i] = operand_b[i]
9846 }
99- a[index] - = (b[index - offset] + carry)
100- a[index] = a[index] & max_digit
101- carry = new_carry
10247 }
103- $if debug {
104- assert carry == 0
48+
49+ if remainder.len > = (n + 1 ) {
50+ remainder.trim (n + 1 )
51+ } else {
52+ remainder = []u64 {len: n + 1 }
10553 }
106- }
10754
108- // logical left shift
109- // there is no overflow. We know that the last bits are zero
110- // and that n <= `digit_bits`
111- @[direct_array_access; inline]
112- fn left_shift_in_place (mut a []u64 , n u32 ) {
113- mut carry := u64 (0 )
114- mut prec_carry := u64 (0 )
115- mask := ((u64 (1 ) << n) - 1 ) << (digit_bits - n)
116- for index in 0 .. a.len {
117- prec_carry = carry >> (digit_bits - n)
118- carry = a[index] & mask
119- a[index] << = n
120- a[index] = a[index] & max_digit
121- a[index] |= prec_carry
55+ v_n_1 := v[n - 1 ]
56+ v_n_2 := v[n - 2 ]
57+ for j := m; j > = 0 ; j-- {
58+ u_j_n := u[j + n]
59+ u_j_n_1 := u[j + n - 1 ]
60+ u_j_n_2 := u[j + n - 2 ]
61+
62+ mut qhat, mut rhat := bits.div_64 (u_j_n >> (64 - digit_bits), (u_j_n << digit_bits) | u_j_n_1 ,
63+ v_n_1 )
64+ mut x1 , mut x2 := bits.mul_64 (qhat, v_n_2 )
65+ x2 = x2 & max_digit
66+ x1 = (x1 << (64 - digit_bits)) | (x2 >> digit_bits)
67+ for greater_than (x1 , x2 , rhat, u_j_n_2 ) {
68+ qhat--
69+ prev := rhat
70+ rhat + = v_n_1
71+ if rhat < prev {
72+ break
73+ }
74+ x1 , x2 = bits.mul_64 (qhat, v_n_2 )
75+ x2 = x2 & max_digit
76+ x1 = (x1 << (64 - digit_bits)) | (x2 >> digit_bits)
77+ }
78+ mut carry := u64 (0 )
79+ for i in 0 .. n {
80+ hi , lo := bits.mul_add_64 (v[i], qhat, carry)
81+ remainder[i] = lo & max_digit
82+ carry = (hi << (64 - digit_bits)) | (lo >> digit_bits)
83+ }
84+ remainder[n] = carry
85+
86+ mut borrow := u64 (0 )
87+ for i in 0 .. n + 1 {
88+ result := u[j + i] - remainder[i] - borrow
89+ u[j + i] = result & max_digit
90+ borrow = (result >> digit_bits) & 1
91+ }
92+ if borrow == 1 {
93+ qhat--
94+ carry = u64 (0 )
95+ for i in 0 .. n {
96+ sum := u[j + i] + v[i] + carry
97+ u[j + i] = sum & max_digit
98+ carry = sum >> digit_bits
99+ }
100+ }
101+ quotient[j] = qhat
122102 }
123- }
124103
125- // logical right shift without control because these digits have already been
126- // shift left before
127- @[direct_array_access; inline]
128- fn right_shift_in_place (mut a []u64 , n u32 ) {
129- mut carry := u64 (0 )
130- mut prec_carry := u64 (0 )
131- mask := (u64 (1 ) << n) - 1
132- for index := a.len - 1 ; index > = 0 ; index-- {
133- carry = a[index] & mask
134- a[index] >> = n
135- a[index] |= prec_carry << (digit_bits - n)
136- prec_carry = carry
104+ remainder.delete_last ()
105+ if leading_zeros > 0 {
106+ mut carry := u64 (0 )
107+ max_leading_digit := (u64 (1 ) << leading_zeros) - 1
108+ for i := n - 1 ; i > = 0 ; i-- {
109+ current_limb := u[i]
110+ remainder[i] = (current_limb >> leading_zeros) | carry
111+ carry = (current_limb & max_leading_digit) << (digit_bits - leading_zeros)
112+ }
113+ } else {
114+ for i in 0 .. n {
115+ remainder[i] = u[i]
116+ }
137117 }
118+ shrink_tail_zeros (mut quotient)
119+ shrink_tail_zeros (mut remainder)
138120}
139121
140- // for assert
141122@[inline]
142- fn left_align_p (a u64 , b u64 ) bool {
143- return bits. leading_zeros_64 (a) == bits. leading_zeros_64 (b )
123+ fn greater_than (x 1 u64 , x 2 u64 , y 1 u64 , y 2 u64 ) bool {
124+ return x 1 > y 1 || ( x1 == y 1 && x 2 > y 2 )
144125}
0 commit comments