| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package ssa |
| |
| import ( |
| "math/big" |
| "math/bits" |
| ) |
| |
| func Sdivisible(n uint, c int64) SdivisibleData { |
| d := uint64(c) |
| k := bits.TrailingZeros64(d) |
| d0 := d >> uint(k) // the odd portion of the divisor |
| |
| mask := ^uint64(0) >> (64 - n) |
| |
| // Calculate the multiplicative inverse via Newton's method. |
| // Quadratic convergence doubles the number of correct bits per iteration. |
| m := d0 // initial guess correct to 3-bits d0*d0 mod 8 == 1 |
| m = m * (2 - m*d0) // 6-bits |
| m = m * (2 - m*d0) // 12-bits |
| m = m * (2 - m*d0) // 24-bits |
| m = m * (2 - m*d0) // 48-bits |
| m = m * (2 - m*d0) // 96-bits >= 64-bits |
| m = m & mask |
| |
| a := ((mask >> 1) / d0) & -(1 << uint(k)) |
| max := (2 * a) >> uint(k) |
| |
| return SdivisibleData{ |
| K: int64(k), |
| M: m, |
| A: a, |
| Max: max, |
| } |
| } |
| |
| type SdivisibleData struct { |
| K int64 // trailingZeros(c) |
| M uint64 // m * (c>>k) mod 2^n == 1 multiplicative inverse of odd portion modulo 2^n |
| A uint64 // ⎣(2^(n-1) - 1)/ (c>>k)⎦ & -(1<<k) additive constant |
| Max uint64 // ⎣(2 a) / (1<<k)⎦ max value to for divisibility |
| } |
| |
| // For signed integers, a similar method follows. |
| // |
| // Given c > 1 and odd, compute m such that (c * m) mod 2^n == 1 |
| // Then if c divides x (x%c ==0), the quotient is given by q = x/c == x*m mod 2^n |
| // |
| // x can range from ⎡-2^(n-1)/c⎤ * c, ... -c, 0, c, ... ⎣(2^(n-1) - 1)/c⎦ * c |
| // Thus, x*m mod 2^n is ⎡-2^(n-1)/c⎤, ... -2, -1, 0, 1, 2, ... ⎣(2^(n-1) - 1)/c⎦ |
| // |
| // So, x is a multiple of c if and only if: |
| // ⎡-2^(n-1)/c⎤ <= x*m mod 2^n <= ⎣(2^(n-1) - 1)/c⎦ |
| // |
| // Since c > 1 and odd, this can be simplified by |
| // ⎡-2^(n-1)/c⎤ == ⎡(-2^(n-1) + 1)/c⎤ == -⎣(2^(n-1) - 1)/c⎦ |
| // |
| // -⎣(2^(n-1) - 1)/c⎦ <= x*m mod 2^n <= ⎣(2^(n-1) - 1)/c⎦ |
| // |
| // To extend this to even integers, consider c = d0 * 2^k where d0 is odd. |
| // We can test whether x is divisible by both d0 and 2^k. |
| // |
| // Let m be such that (d0 * m) mod 2^n == 1. |
| // Let q = x*m mod 2^n. Then c divides x if: |
| // |
| // -⎣(2^(n-1) - 1)/d0⎦ <= q <= ⎣(2^(n-1) - 1)/d0⎦ and q ends in at least k 0-bits |
| // |
| // To transform this to a single comparison, we use the following theorem (ZRS in Hacker's Delight). |
| // |
| // For a >= 0 the following conditions are equivalent: |
| // 1) -a <= x <= a and x ends in at least k 0-bits |
| // 2) RotRight(x+a', k) <= ⎣2a'/2^k⎦ |
| // |
| // Where a' = a & -2^k (a with its right k bits set to zero) |
| // |
| // To see that 1 & 2 are equivalent, note that -a <= x <= a is equivalent to |
| // -a' <= x <= a' if and only if x ends in at least k 0-bits. Adding -a' to each side gives, |
| // 0 <= x + a' <= 2a' and x + a' ends in at least k 0-bits if and only if x does since a' has |
| // k 0-bits by definition. We can use theorem ZRU above with x -> x + a' and a -> 2a' giving 1) == 2). |
| // |
| // Let m be such that (d0 * m) mod 2^n == 1. |
| // Let q = x*m mod 2^n. |
| // Let a' = ⎣(2^(n-1) - 1)/d0⎦ & -2^k |
| // |
| // Then the divisibility test is: |
| // |
| // RotRight(q+a', k) <= ⎣2a'/2^k⎦ |
| // |
| // Note that the calculation is performed using unsigned integers. |
| // Since a' can have n-1 bits, 2a' may have n bits and there is no risk of overflow. |
| |
| // SdivisibleOK reports whether we should strength reduce a signed n-bit divisibility check by c. |
| func SdivisibleOK(n uint, c int64) bool { |
| if c < 0 { |
| // Doesn't work for negative c. |
| return false |
| } |
| // Doesn't work for 0. |
| // Don't use it for powers of 2. |
| return c&(c-1) != 0 |
| } |
| |
| func SdivisibleOK16(c int16) bool { return SdivisibleOK(16, int64(c)) } |
| |
| func SdivisibleOK8(c int8) bool { return SdivisibleOK(8, int64(c)) } |
| |
| // Smagic computes the constants needed to strength reduce signed n-bit divides by the constant c. |
| // Must have c>0. |
| // The return values satisfy for all -2^(n-1) <= x < 2^(n-1) |
| // |
| // trunc(x / c) = x * m >> (n+s) + (x < 0 ? 1 : 0) |
| func Smagic(n uint, c int64) SmagicData { |
| C := new(big.Int).SetInt64(c) |
| s := C.BitLen() - 1 |
| M := big.NewInt(1) |
| M.Lsh(M, n+uint(s)) // 2^(n+s) |
| M.Add(M, C) // 2^(n+s)+c |
| M.Sub(M, big.NewInt(1)) // 2^(n+s)+c-1 |
| M.Div(M, C) // ⎡2^(n+s)/c⎤ |
| if M.Bit(int(n)) != 0 { |
| panic("n+1st bit is set") |
| } |
| if M.Bit(int(n-1)) == 0 { |
| panic("nth bit is not set") |
| } |
| m := M.Uint64() |
| return SmagicData{S: int64(s), M: m} |
| } |
| |
| type SmagicData struct { |
| S int64 // ⎡log2(c)⎤-1 |
| M uint64 // ⎡2^(n+s)/c⎤ |
| } |
| |
| // For signed division, we use a similar strategy. |
| // First, we enforce a positive c. |
| // x / c = -(x / (-c)) |
| // This will require an additional Neg op for c<0. |
| // |
| // If x is positive we're in a very similar state |
| // to the unsigned case above. We define: |
| // s = ⎡log2(c)⎤-1 |
| // m = ⎡2^(n+s)/c⎤ |
| // Then |
| // ⎣x / c⎦ = ⎣x * m / 2^(n+s)⎦ |
| // If x is negative we have |
| // ⎡x / c⎤ = ⎣x * m / 2^(n+s)⎦ + 1 |
| // (TODO: derivation?) |
| // |
| // The multiply is a bit odd, as it is a signed n-bit value |
| // times an unsigned n-bit value. For n smaller than the |
| // word size, we can extend x and m appropriately and use the |
| // signed multiply instruction. For n == word size, |
| // we must use the signed multiply high and correct |
| // the result by adding x*2^n. |
| // |
| // Adding 1 if x<0 is done by subtracting x>>(n-1). |
| |
| func SmagicOK(n uint, c int64) bool { |
| if c < 0 { |
| // Doesn't work for negative c. |
| return false |
| } |
| // Doesn't work for 0. |
| // Don't use it for powers of 2. |
| return c&(c-1) != 0 |
| } |
| |
| func Udivisible(n uint, c int64) UdivisibleData { |
| // Convert from ConstX auxint values to the real uint64 constant they represent. |
| d := uint64(c) << (64 - n) >> (64 - n) |
| |
| k := bits.TrailingZeros64(d) |
| d0 := d >> uint(k) // the odd portion of the divisor |
| |
| mask := ^uint64(0) >> (64 - n) |
| |
| // Calculate the multiplicative inverse via Newton's method. |
| // Quadratic convergence doubles the number of correct bits per iteration. |
| m := d0 // initial guess correct to 3-bits d0*d0 mod 8 == 1 |
| m = m * (2 - m*d0) // 6-bits |
| m = m * (2 - m*d0) // 12-bits |
| m = m * (2 - m*d0) // 24-bits |
| m = m * (2 - m*d0) // 48-bits |
| m = m * (2 - m*d0) // 96-bits >= 64-bits |
| m = m & mask |
| |
| max := mask / d |
| |
| return UdivisibleData{ |
| K: int64(k), |
| M: m, |
| Max: max, |
| } |
| } |
| |
| type UdivisibleData struct { |
| K int64 // trailingZeros(c) |
| M uint64 // m * (c>>k) mod 2^n == 1 multiplicative inverse of odd portion modulo 2^n |
| Max uint64 // ⎣(2^n - 1)/ c⎦ max value to for divisibility |
| } |
| |
| // Divisibility x%c == 0 can be checked more efficiently than directly computing |
| // the modulus x%c and comparing against 0. |
| // |
| // The same "Division by invariant integers using multiplication" paper |
| // by Granlund and Montgomery referenced above briefly mentions this method |
| // and it is further elaborated in "Hacker's Delight" by Warren Section 10-17 |
| // |
| // The first thing to note is that for odd integers, exact division can be computed |
| // by using the modular inverse with respect to the word size 2^n. |
| // |
| // Given c, compute m such that (c * m) mod 2^n == 1 |
| // Then if c divides x (x%c ==0), the quotient is given by q = x/c == x*m mod 2^n |
| // |
| // x can range from 0, c, 2c, 3c, ... ⎣(2^n - 1)/c⎦ * c the maximum multiple |
| // Thus, x*m mod 2^n is 0, 1, 2, 3, ... ⎣(2^n - 1)/c⎦ |
| // i.e. the quotient takes all values from zero up to max = ⎣(2^n - 1)/c⎦ |
| // |
| // If x is not divisible by c, then x*m mod 2^n must take some larger value than max. |
| // |
| // This gives x*m mod 2^n <= ⎣(2^n - 1)/c⎦ as a test for divisibility |
| // involving one multiplication and compare. |
| // |
| // To extend this to even integers, consider c = d0 * 2^k where d0 is odd. |
| // We can test whether x is divisible by both d0 and 2^k. |
| // For d0, the test is the same as above. Let m be such that m*d0 mod 2^n == 1 |
| // Then x*m mod 2^n <= ⎣(2^n - 1)/d0⎦ is the first test. |
| // The test for divisibility by 2^k is a check for k trailing zeroes. |
| // Note that since d0 is odd, m is odd and thus x*m will have the same number of |
| // trailing zeroes as x. So the two tests are, |
| // |
| // x*m mod 2^n <= ⎣(2^n - 1)/d0⎦ |
| // and x*m ends in k zero bits |
| // |
| // These can be combined into a single comparison by the following |
| // (theorem ZRU in Hacker's Delight) for unsigned integers. |
| // |
| // x <= a and x ends in k zero bits if and only if RotRight(x ,k) <= ⎣a/(2^k)⎦ |
| // Where RotRight(x ,k) is right rotation of x by k bits. |
| // |
| // To prove the first direction, x <= a -> ⎣x/(2^k)⎦ <= ⎣a/(2^k)⎦ |
| // But since x ends in k zeroes all the rotated bits would be zero too. |
| // So RotRight(x, k) == ⎣x/(2^k)⎦ <= ⎣a/(2^k)⎦ |
| // |
| // If x does not end in k zero bits, then RotRight(x, k) |
| // has some non-zero bits in the k highest bits. |
| // ⎣x/(2^k)⎦ has all zeroes in the k highest bits, |
| // so RotRight(x, k) > ⎣x/(2^k)⎦ |
| // |
| // Finally, if x > a and has k trailing zero bits, then RotRight(x, k) == ⎣x/(2^k)⎦ |
| // and ⎣x/(2^k)⎦ must be greater than ⎣a/(2^k)⎦, that is the top n-k bits of x must |
| // be greater than the top n-k bits of a because the rest of x bits are zero. |
| // |
| // So the two conditions about can be replaced with the single test |
| // |
| // RotRight(x*m mod 2^n, k) <= ⎣(2^n - 1)/c⎦ |
| // |
| // Where d0*2^k was replaced by c on the right hand side. |
| |
| // UdivisibleOK reports whether we should strength reduce an unsigned n-bit divisibility check by c. |
| func UdivisibleOK(n uint, c int64) bool { |
| // Convert from ConstX auxint values to the real uint64 constant they represent. |
| d := uint64(c) << (64 - n) >> (64 - n) |
| |
| // Doesn't work for 0. |
| // Don't use for powers of 2. |
| return d&(d-1) != 0 |
| } |
| |
| func UdivisibleOK16(c int16) bool { return UdivisibleOK(16, int64(c)) } |
| |
| func UdivisibleOK8(c int8) bool { return UdivisibleOK(8, int64(c)) } |
| |
| // Umagic computes the constants needed to strength reduce unsigned n-bit divides by the constant uint64(c). |
| // The return values satisfy for all 0 <= x < 2^n |
| // |
| // floor(x / uint64(c)) = x * (m + 2^n) >> (n+s) |
| func Umagic(n uint, c int64) UmagicData { |
| // Convert from ConstX auxint values to the real uint64 constant they represent. |
| d := uint64(c) << (64 - n) >> (64 - n) |
| |
| C := new(big.Int).SetUint64(d) |
| s := C.BitLen() |
| M := big.NewInt(1) |
| M.Lsh(M, n+uint(s)) // 2^(n+s) |
| M.Add(M, C) // 2^(n+s)+c |
| M.Sub(M, big.NewInt(1)) // 2^(n+s)+c-1 |
| M.Div(M, C) // ⎡2^(n+s)/c⎤ |
| if M.Bit(int(n)) != 1 { |
| panic("n+1st bit isn't set") |
| } |
| M.SetBit(M, int(n), 0) |
| m := M.Uint64() |
| return UmagicData{S: int64(s), M: m} |
| } |
| |
| type UmagicData struct { |
| S int64 // ⎡log2(c)⎤ |
| M uint64 // ⎡2^(n+s)/c⎤ - 2^n |
| } |