The previous article introduced the comparison operation of large integers, today to talk about and bit-related operations.
★ Intro
The representation of large integers and related definitions This article describes how large integers are represented. To facilitate the following explanation, here is an example of a large integer given in the previous definition (32-bit system, each digit length is 32 bits):
Assuming that there is a bignum x, the decimal value is 1134924633606254832, the corresponding hexadecimal value is 0xfc00ff0f0f0f0f0, then according to the representation of a large integer, the 2^32 is represented as (each bit separated by commas):
(264245232,4042322160) i.e.: 1134924633606254832/(2^32) = 264245232, 1134924633606254832 mod (2^32) = 4042322160.
High-level binary representation: 0000 1111 1100 0000 0000 1111 1111 0000
Low-level binary representation: 1111 0000 1111 0000 1111 0000 1111 0000
★ Returns the bit bits of the specified subscript pos
the subscript (POS) Here is starting from the lowest of a large integer, and with 0 as the starting value, for example, the bit of the above Bignum x subscript 3 is 0 and the bit with the subscript 4 is 1.
Given a POS value, to find out where the corresponding bits are located, you can first find out which bits of the POS correspond to which digits of the large integer. For example, when pos = 38 o'clock, Pos/bil = 38/32 = 1,
Bil (bits in limbs) is a bit length of bits, and the 32-bit system has a 32 bil. This means that the bit bits corresponding to the POS are in the second digit of the large integer x (corresponding to the array cell with the subscript 1). Find the approximate location, it is necessary to determine the location in the digital position, which can be done by the remainder operation: pos% BiL = 32 MoD = 6, so that the number of 6-bit right shift and 1 to do the logic and operation, you can get pos corresponding to the bit value of 1 (corresponding to the red mark). (0000 1111 1100 0000 0000 1111 1111 0000,1111 0000 1111 0000 1111 0000 1111 0000)
Boolean bn_get_bit (const bignum *x, const size_t POS) { boolean bit; POS is zero base number if (X->alloc * BiL <= POS) return 0; bit = (X->dp[pos/bil] >> (POS & (BiL-1))) & 1; return bit;}
in the 2 complement operation, the calculation of a mod (2^n) is equivalent to A and (2^n-1).
★ Set the location of the POS to the setting of the value of the bit
as in the previous principle, find the location of the POS corresponding bit. Suppose pos = 35, then offset = Pos/bil = 1, mod = Pos/bil = 3. After finding the corresponding position, the value of the bit should be emptied first, the specific practice is: Shift 1 to the Left mod = 3 bits, and then reverse, then the binary operation results will be 1111 1111 1111 1111 1111 1111 1111 0111, and the second digit of the large integer (corresponding array subscript 1 ), and the value of the bit is emptied. Then the function passes in the Boolean type value to the left mod = 3 bit after the second digit with the large integer is done or the operation can set the new bit.
int Bn_set_bit (bignum *x, const size_t POS, Boolean value) { int ret = 0; size_t offset, mod; POS is zero base number if (value! = TRUE && Value! = FALSE) return bn_invalid_input; offset = Pos/bil; MoD = pos & (biL-1); if (POS >= x->alloc * BiL) { if (value = = FALSE) return 0,//If the POS exceeds the assigned digits and value is 0, then no action is required because the high position defaults to 0, otherwise the precision needs to be increased. Bn_check (Bn_grow (x, offset + 1)); } X->dp[offset] &= ~ ((bn_digit) 1 << MoD); X->dp[offset] |= ((bn_digit) (value) << mod); x->used = x->alloc; If the accuracy of the bignum increases, it is necessary to check the effective digits from the leftmost digits to the right to ensure that the used value is correct. Bn_clamp (x); Compress extra bits clean: return ret;}
★ Returns the number of valid bits
A valid bit is the middle of all the bits that start from the left of the first bit that is not 0 to the far right bit . For example, in this article, except for the top four bits of the highest bit, the others are valid bits, and the number of valid bits is 60. As previously mentioned, the following algorithm can be easily obtained:
size_t BN_MSB (const bignum *x) { size_t I, J; i = x->used-1; for (j = BiL; j > 0; j--) if (((X->dp[i] >> (j-1) & 1)! = 0) break ; return BiL * i + j;}
The meaning of this algorithm is that it can calculate the actual bit size of a bignum, although it is simple, but it will be used many times in the later algorithm.
★ Returns the number of the least significant bits before 0
/strong>
The least significant bit is the first bit that is not 0 from the right, and in this case the least significant bit of Bignum X is the bit that is labeled 4 from the right in the low digits. The number of previous 0 is 4. So it's easy to write the following algorithm:
size_t bn_lsb (const bignum *x) { size_t I, J; for (i = 0; i < x->used; i++) { if (x->dp[i]! = 0) {for (j = 0; J < BiL; J + +) { if (((X->dp[i) >> j) & 1)! = 0) return I * BiL + j;}} } return 0;}
for an integer p > 0, it can be expressed in the following form: p = q * 2^r, where q is an odd number, for example, 9 * 2^2, R = 2. The significance of the BN_LSB algorithm is that the value of R can be computed by calculating the number of the first 0 of the least significant bit. Although this algorithm is also very simple, but it will be in the calculation of greatest common divisor algorithm in the future.
★ Returns the byte size of the Bignum
It is important to note that this operation does not return bignum the amount of memory that is consumed, for example, Bignum X, even though the initial allocation of 3 units of memory, its byte size is still 8 byte. To calculate the byte size of the bignum, simply divide the bit size of X by 7 by 8. The goal of adding 7 is to avoid a byte that is less than 8 when the bit is not a multiple of x.
size_t bn_size (const bignum *x) { return ((BN_MSB (x) + 7) >> 3);}
★ Summary
The relative operation principle of the large integer digits is not difficult, but if the structure of the bignum is not defined at first, such as using decimal, then it is quite troublesome to operate, which again illustrates the importance of binary thinking in programming. The next article will describe the shift operation for large integers.
Large integer algorithm [04] bit operation