(a * b) reduced modulo 2**64, without ever overflowing a signed
64-bit integer.
Schoolbook multiplication on 16-bit limbs: each partial product is
below 232 and at most four of them plus a carry are accumulated, so
every intermediate stays below 235 and signed overflow is impossible
regardless of the sign of the inputs. Limbs are extracted with ibits
(bit-model, sign-safe) and the result is reassembled with ior/ishft.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | a | |||
| integer(kind=int64), | intent(in) | :: | b |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer(kind=int64), | private | :: | a0 | ||||
| integer(kind=int64), | private | :: | a1 | ||||
| integer(kind=int64), | private | :: | a2 | ||||
| integer(kind=int64), | private | :: | a3 | ||||
| integer(kind=int64), | private | :: | b0 | ||||
| integer(kind=int64), | private | :: | b1 | ||||
| integer(kind=int64), | private | :: | b2 | ||||
| integer(kind=int64), | private | :: | b3 | ||||
| integer(kind=int64), | private | :: | carry | ||||
| integer(kind=int64), | private | :: | r0 | ||||
| integer(kind=int64), | private | :: | r1 | ||||
| integer(kind=int64), | private | :: | r2 | ||||
| integer(kind=int64), | private | :: | r3 | ||||
| integer(kind=int64), | private | :: | t |
pure function u64_mul(a, b) result(r) !! `(a * b)` reduced modulo 2**64, without ever overflowing a signed !! 64-bit integer. !! !! Schoolbook multiplication on 16-bit limbs: each partial product is !! below 2**32 and at most four of them plus a carry are accumulated, so !! every intermediate stays below 2**35 and signed overflow is impossible !! regardless of the sign of the inputs. Limbs are extracted with `ibits` !! (bit-model, sign-safe) and the result is reassembled with `ior`/`ishft`. integer(int64), intent(in) :: a integer(int64), intent(in) :: b integer(int64) :: r integer(int64) :: a0, a1, a2, a3 integer(int64) :: b0, b1, b2, b3 integer(int64) :: t, carry integer(int64) :: r0, r1, r2, r3 a0 = ibits(a, 0, 16) a1 = ibits(a, 16, 16) a2 = ibits(a, 32, 16) a3 = ibits(a, 48, 16) b0 = ibits(b, 0, 16) b1 = ibits(b, 16, 16) b2 = ibits(b, 32, 16) b3 = ibits(b, 48, 16) t = a0*b0 r0 = iand(t, MASK16) carry = ibits(t, 16, 48) t = a0*b1 + a1*b0 + carry r1 = iand(t, MASK16) carry = ibits(t, 16, 48) t = a0*b2 + a1*b1 + a2*b0 + carry r2 = iand(t, MASK16) carry = ibits(t, 16, 48) t = a0*b3 + a1*b2 + a2*b1 + a3*b0 + carry r3 = iand(t, MASK16) r = ior(ior(ishft(r3, 48), ishft(r2, 32)), ior(ishft(r1, 16), r0)) end function u64_mul