@@ -2,57 +2,6 @@ module big
2
2
3
3
import math.bits
4
4
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
-
56
5
// help routines for cleaner code but inline for performance
57
6
// quicker than BitField.set_bit
58
7
@[direct_array_access; inline]
@@ -65,80 +14,112 @@ fn bit_set(mut a []u64, n int) {
65
14
a[byte_offset] |= mask
66
15
}
67
16
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)
85
24
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]
98
46
}
99
- a[index] - = (b[index - offset] + carry)
100
- a[index] = a[index] & max_digit
101
- carry = new_carry
102
47
}
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 }
105
53
}
106
- }
107
54
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
122
102
}
123
- }
124
103
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
+ }
137
117
}
118
+ shrink_tail_zeros (mut quotient)
119
+ shrink_tail_zeros (mut remainder)
138
120
}
139
121
140
- // for assert
141
122
@[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 )
144
125
}
0 commit comments