mirror of
https://github.com/golang/go
synced 2024-10-04 13:21:22 -06:00
122 lines
2.5 KiB
Go
122 lines
2.5 KiB
Go
|
// Copyright 2009 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.
|
||
|
|
||
|
// Fast versions of the routines in this file are in fast.arith.s.
|
||
|
// Simply replace this file with arith.s (renamed from fast.arith.s)
|
||
|
// and the bignum package will build and run on a platform that
|
||
|
// supports the assembly routines.
|
||
|
|
||
|
package bignum
|
||
|
|
||
|
import "unsafe"
|
||
|
|
||
|
// z1<<64 + z0 = x*y
|
||
|
func Mul128(x, y uint64) (z1, z0 uint64) {
|
||
|
// Split x and y into 2 halfwords each, multiply
|
||
|
// the halfwords separately while avoiding overflow,
|
||
|
// and return the product as 2 words.
|
||
|
|
||
|
const (
|
||
|
W = uint(unsafe.Sizeof(x))*8;
|
||
|
W2 = W/2;
|
||
|
B2 = 1<<W2;
|
||
|
M2 = B2-1;
|
||
|
)
|
||
|
|
||
|
if x < y {
|
||
|
x, y = y, x
|
||
|
}
|
||
|
|
||
|
if x < B2 {
|
||
|
// y < B2 because y <= x
|
||
|
// sub-digits of x and y are (0, x) and (0, y)
|
||
|
// z = z[0] = x*y
|
||
|
z0 = x*y;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if y < B2 {
|
||
|
// sub-digits of x and y are (x1, x0) and (0, y)
|
||
|
// x = (x1*B2 + x0)
|
||
|
// y = (y1*B2 + y0)
|
||
|
x1, x0 := x>>W2, x&M2;
|
||
|
|
||
|
// x*y = t2*B2*B2 + t1*B2 + t0
|
||
|
t0 := x0*y;
|
||
|
t1 := x1*y;
|
||
|
|
||
|
// compute result digits but avoid overflow
|
||
|
// z = z[1]*B + z[0] = x*y
|
||
|
z0 = t1<<W2 + t0;
|
||
|
z1 = (t1 + t0>>W2) >> W2;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// general case
|
||
|
// sub-digits of x and y are (x1, x0) and (y1, y0)
|
||
|
// x = (x1*B2 + x0)
|
||
|
// y = (y1*B2 + y0)
|
||
|
x1, x0 := x>>W2, x&M2;
|
||
|
y1, y0 := y>>W2, y&M2;
|
||
|
|
||
|
// x*y = t2*B2*B2 + t1*B2 + t0
|
||
|
t0 := x0*y0;
|
||
|
t1 := x1*y0 + x0*y1;
|
||
|
t2 := x1*y1;
|
||
|
|
||
|
// compute result digits but avoid overflow
|
||
|
// z = z[1]*B + z[0] = x*y
|
||
|
z0 = t1<<W2 + t0;
|
||
|
z1 = t2 + (t1 + t0>>W2) >> W2;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
// z1<<64 + z0 = x*y + c
|
||
|
func MulAdd128(x, y, c uint64) (z1, z0 uint64) {
|
||
|
// Split x and y into 2 halfwords each, multiply
|
||
|
// the halfwords separately while avoiding overflow,
|
||
|
// and return the product as 2 words.
|
||
|
|
||
|
const (
|
||
|
W = uint(unsafe.Sizeof(x))*8;
|
||
|
W2 = W/2;
|
||
|
B2 = 1<<W2;
|
||
|
M2 = B2-1;
|
||
|
)
|
||
|
|
||
|
// TODO(gri) Should implement special cases for faster execution.
|
||
|
|
||
|
// general case
|
||
|
// sub-digits of x, y, and c are (x1, x0), (y1, y0), (c1, c0)
|
||
|
// x = (x1*B2 + x0)
|
||
|
// y = (y1*B2 + y0)
|
||
|
x1, x0 := x>>W2, x&M2;
|
||
|
y1, y0 := y>>W2, y&M2;
|
||
|
c1, c0 := c>>W2, c&M2;
|
||
|
|
||
|
// x*y + c = t2*B2*B2 + t1*B2 + t0
|
||
|
t0 := x0*y0 + c0;
|
||
|
t1 := x1*y0 + x0*y1 + c1;
|
||
|
t2 := x1*y1;
|
||
|
|
||
|
// compute result digits but avoid overflow
|
||
|
// z = z[1]*B + z[0] = x*y
|
||
|
z0 = t1<<W2 + t0;
|
||
|
z1 = t2 + (t1 + t0>>W2) >> W2;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
// q = (x1<<64 + x0)/y + r
|
||
|
func Div128(x1, x0, y uint64) (q, r uint64) {
|
||
|
if x1 == 0 {
|
||
|
q, r = x0/y, x0%y;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// TODO(gri) Implement general case.
|
||
|
panic("Div128 not implemented for x > 1<<64-1");
|
||
|
}
|