// 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) private static umagicData umagic(ulong n, long c) => func((_, panic, __) => { // Convert from ConstX auxint values to the real uint64 constant they represent. var d = uint64(c) << (int)((64L - n)) >> (int)((64L - n)); ptr <object> C = @new <big.Int>().SetUint64(d); var s = C.BitLen(); var M = big.NewInt(1L); M.Lsh(M, n + uint(s)); // 2^(n+s) M.Add(M, C); // 2^(n+s)+c M.Sub(M, big.NewInt(1L)); // 2^(n+s)+c-1 M.Div(M, C); // ⎡2^(n+s)/c⎤ if (M.Bit(int(n)) != 1L) { panic("n+1st bit isn't set"); } M.SetBit(M, int(n), 0L); var m = M.Uint64(); return(new umagicData(s: int64(s), m: m)); });
// magic 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) private static smagicData smagic(ulong n, long c) => func((_, panic, __) => { ptr <object> C = @new <big.Int>().SetInt64(c); var s = C.BitLen() - 1L; var M = big.NewInt(1L); M.Lsh(M, n + uint(s)); // 2^(n+s) M.Add(M, C); // 2^(n+s)+c M.Sub(M, big.NewInt(1L)); // 2^(n+s)+c-1 M.Div(M, C); // ⎡2^(n+s)/c⎤ if (M.Bit(int(n)) != 0L) { panic("n+1st bit is set"); } if (M.Bit(int(n - 1L)) == 0L) { panic("nth bit is not set"); } var m = M.Uint64(); return(new smagicData(s: int64(s), m: m)); });