1 2 3 (* Copyright (c) 2011 Stefan Krah. All rights reserved. *) 4 5 6 ======================================================================== 7 Calculate (a * b) % p using the 80-bit x87 FPU 8 ======================================================================== 9 10 A description of the algorithm can be found in the apfloat manual by 11 Tommila [1]. 12 13 The proof follows an argument made by Granlund/Montgomery in [2]. 14 15 16 Definitions and assumptions: 17 ---------------------------- 18 19 The 80-bit extended precision format uses 64 bits for the significand: 20 21 (1) F = 64 22 23 The modulus is prime and less than 2**31: 24 25 (2) 2 <= p < 2**31 26 27 The factors are less than p: 28 29 (3) 0 <= a < p 30 (4) 0 <= b < p 31 32 The product a * b is less than 2**62 and is thus exact in 64 bits: 33 34 (5) n = a * b 35 36 The product can be represented in terms of quotient and remainder: 37 38 (6) n = q * p + r 39 40 Using (3), (4) and the fact that p is prime, the remainder is always 41 greater than zero: 42 43 (7) 0 <= q < p /\ 1 <= r < p 44 45 46 Strategy: 47 --------- 48 49 Precalculate the 80-bit long double inverse of p, with a maximum 50 relative error of 2**(1-F): 51 52 (8) pinv = (long double)1.0 / p 53 54 Calculate an estimate for q = floor(n/p). The multiplication has another 55 maximum relative error of 2**(1-F): 56 57 (9) qest = n * pinv 58 59 If we can show that q < qest < q+1, then trunc(qest) = q. It is then 60 easy to recover the remainder r. The complete algorithm is: 61 62 a) Set the control word to 64-bit precision and truncation mode. 63 64 b) n = a * b # Calculate exact product. 65 66 c) qest = n * pinv # Calculate estimate for the quotient. 67 68 d) q = (qest+2**63)-2**63 # Truncate qest to the exact quotient. 69 70 f) r = n - q * p # Calculate remainder. 71 72 73 Proof for q < qest < q+1: 74 ------------------------- 75 76 Using the cumulative error, the error bounds for qest are: 77 78 n n * (1 + 2**(1-F))**2 79 (9) --------------------- <= qest <= --------------------- 80 p * (1 + 2**(1-F))**2 p 81 82 83 Lemma 1: 84 -------- 85 n q * p + r 86 (10) q < --------------------- = --------------------- 87 p * (1 + 2**(1-F))**2 p * (1 + 2**(1-F))**2 88 89 90 Proof: 91 ~~~~~~ 92 93 (I) q * p * (1 + 2**(1-F))**2 < q * p + r 94 95 (II) q * p * 2**(2-F) + q * p * 2**(2-2*F) < r 96 97 Using (1) and (7), it is sufficient to show that: 98 99 (III) q * p * 2**(-62) + q * p * 2**(-126) < 1 <= r 100 101 (III) can easily be verified by substituting the largest possible 102 values p = 2**31-1 and q = 2**31-2. 103 104 The critical cases occur when r = 1, n = m * p + 1. These cases 105 can be exhaustively verified with a test program. 106 107 108 Lemma 2: 109 -------- 110 111 n * (1 + 2**(1-F))**2 (q * p + r) * (1 + 2**(1-F))**2 112 (11) --------------------- = ------------------------------- < q + 1 113 p p 114 115 Proof: 116 ~~~~~~ 117 118 (I) (q * p + r) + (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < q * p + p 119 120 (II) (q * p + r) * 2**(2-F) + (q * p + r) * 2**(2-2*F) < p - r 121 122 Using (1) and (7), it is sufficient to show that: 123 124 (III) (q * p + r) * 2**(-62) + (q * p + r) * 2**(-126) < 1 <= p - r 125 126 (III) can easily be verified by substituting the largest possible 127 values p = 2**31-1, q = 2**31-2 and r = 2**31-2. 128 129 The critical cases occur when r = (p - 1), n = m * p - 1. These cases 130 can be exhaustively verified with a test program. 131 132 133 [1] http://www.apfloat.org/apfloat/2.40/apfloat.pdf 134 [2] http://gmplib.org/~tege/divcnst-pldi94.pdf 135 [Section 7: "Use of floating point"] 136 137 138 139 (* Coq proof for (10) and (11) *) 140 141 Require Import ZArith. 142 Require Import QArith. 143 Require Import Qpower. 144 Require Import Qabs. 145 Require Import Psatz. 146 147 Open Scope Q_scope. 148 149 150 Ltac qreduce T := 151 rewrite <- (Qred_correct (T)); simpl (Qred (T)). 152 153 Theorem Qlt_move_right : 154 forall x y z:Q, x + z < y <-> x < y - z. 155 Proof. 156 intros. 157 split. 158 intros. 159 psatzl Q. 160 intros. 161 psatzl Q. 162 Qed. 163 164 Theorem Qlt_mult_by_z : 165 forall x y z:Q, 0 < z -> (x < y <-> x * z < y * z). 166 Proof. 167 intros. 168 split. 169 intros. 170 apply Qmult_lt_compat_r. trivial. trivial. 171 intros. 172 rewrite <- (Qdiv_mult_l x z). rewrite <- (Qdiv_mult_l y z). 173 apply Qmult_lt_compat_r. 174 apply Qlt_shift_inv_l. 175 trivial. psatzl Q. trivial. psatzl Q. psatzl Q. 176 Qed. 177 178 Theorem Qle_mult_quad : 179 forall (a b c d:Q), 180 0 <= a -> a <= c -> 181 0 <= b -> b <= d -> 182 a * b <= c * d. 183 intros. 184 psatz Q. 185 Qed. 186 187 188 Theorem q_lt_qest: 189 forall (p q r:Q), 190 (0 < p) -> (p <= (2#1)^31 - 1) -> 191 (0 <= q) -> (q <= p - 1) -> 192 (1 <= r) -> (r <= p - 1) -> 193 q < (q * p + r) / (p * (1 + (2#1)^(-63))^2). 194 Proof. 195 intros. 196 rewrite Qlt_mult_by_z with (z := (p * (1 + (2#1)^(-63))^2)). 197 198 unfold Qdiv. 199 rewrite <- Qmult_assoc. 200 rewrite (Qmult_comm (/ (p * (1 + (2 # 1) ^ (-63)) ^ 2)) (p * (1 + (2 # 1) ^ (-63)) ^ 2)). 201 rewrite Qmult_inv_r. 202 rewrite Qmult_1_r. 203 204 assert (q * (p * (1 + (2 # 1) ^ (-63)) ^ 2) == q * p + (q * p) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). 205 qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). 206 qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). 207 ring_simplify. 208 reflexivity. 209 rewrite H5. 210 211 rewrite Qplus_comm. 212 rewrite Qlt_move_right. 213 ring_simplify (q * p + r - q * p). 214 qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). 215 216 apply Qlt_le_trans with (y := 1). 217 rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). 218 ring_simplify. 219 220 apply Qle_lt_trans with (y := ((2 # 1) ^ 31 - (2#1)) * ((2 # 1) ^ 31 - 1)). 221 apply Qle_mult_quad. 222 assumption. psatzl Q. psatzl Q. psatzl Q. psatzl Q. psatzl Q. assumption. psatzl Q. psatzl Q. 223 Qed. 224 225 Theorem qest_lt_qplus1: 226 forall (p q r:Q), 227 (0 < p) -> (p <= (2#1)^31 - 1) -> 228 (0 <= q) -> (q <= p - 1) -> 229 (1 <= r) -> (r <= p - 1) -> 230 ((q * p + r) * (1 + (2#1)^(-63))^2) / p < q + 1. 231 Proof. 232 intros. 233 rewrite Qlt_mult_by_z with (z := p). 234 235 unfold Qdiv. 236 rewrite <- Qmult_assoc. 237 rewrite (Qmult_comm (/ p) p). 238 rewrite Qmult_inv_r. 239 rewrite Qmult_1_r. 240 241 assert ((q * p + r) * (1 + (2 # 1) ^ (-63)) ^ 2 == q * p + r + (q * p + r) * ((2 # 1) ^ (-62) + (2 # 1) ^ (-126))). 242 qreduce ((1 + (2 # 1) ^ (-63)) ^ 2). 243 qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). 244 ring_simplify. reflexivity. 245 rewrite H5. 246 247 rewrite <- Qplus_assoc. rewrite <- Qplus_comm. rewrite Qlt_move_right. 248 ring_simplify ((q + 1) * p - q * p). 249 250 rewrite <- Qplus_comm. rewrite Qlt_move_right. 251 252 apply Qlt_le_trans with (y := 1). 253 qreduce ((2 # 1) ^ (-62) + (2 # 1) ^ (-126)). 254 255 rewrite Qlt_mult_by_z with (z := 85070591730234615865843651857942052864 # 18446744073709551617). 256 ring_simplify. 257 258 ring_simplify in H0. 259 apply Qle_lt_trans with (y := (2147483646 # 1) * (2147483647 # 1) + (2147483646 # 1)). 260 261 apply Qplus_le_compat. 262 apply Qle_mult_quad. 263 assumption. psatzl Q. auto with qarith. assumption. psatzl Q. 264 auto with qarith. auto with qarith. 265 psatzl Q. psatzl Q. assumption. 266 Qed. 267 268 269 270