1.10 Updates (#4218)
This commit is contained in:
parent
d034d8040a
commit
7a6f582168
|
@ -7,7 +7,7 @@ services:
|
|||
- docker
|
||||
|
||||
go:
|
||||
- "1.9"
|
||||
- "1.10.1"
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
|
|
|
@ -59,8 +59,8 @@ Developing Vault
|
|||
--------------------
|
||||
|
||||
If you wish to work on Vault itself or any of its built-in systems, you'll
|
||||
first need [Go](https://www.golang.org) installed on your machine (version 1.9+
|
||||
is *required*).
|
||||
first need [Go](https://www.golang.org) installed on your machine (version
|
||||
1.10.1+ is *required*).
|
||||
|
||||
For local dev first make sure Go is properly installed, including setting up a
|
||||
[GOPATH](https://golang.org/doc/code.html#GOPATH). Next, clone this repository
|
||||
|
|
|
@ -439,28 +439,12 @@ func validateConnState(roots *x509.CertPool, cs *tls.ConnectionState) ([][]*x509
|
|||
}
|
||||
}
|
||||
|
||||
var chains [][]*x509.Certificate
|
||||
var err error
|
||||
switch {
|
||||
case len(certs[0].DNSNames) > 0:
|
||||
for _, dnsName := range certs[0].DNSNames {
|
||||
opts.DNSName = dnsName
|
||||
chains, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
if _, ok := err.(x509.UnknownAuthorityError); ok {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.New("failed to verify client's certificate: " + err.Error())
|
||||
}
|
||||
}
|
||||
default:
|
||||
chains, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
if _, ok := err.(x509.UnknownAuthorityError); ok {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.New("failed to verify client's certificate: " + err.Error())
|
||||
chains, err := certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
if _, ok := err.(x509.UnknownAuthorityError); ok {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, errors.New("failed to verify client's certificate: " + err.Error())
|
||||
}
|
||||
|
||||
return chains, nil
|
||||
|
|
|
@ -1394,7 +1394,7 @@ func convertRespToPKCS8(resp *logical.Response) error {
|
|||
return errwrap.Wrapf("error converting response to pkcs8: error parsing previous key: {{err}}", err)
|
||||
}
|
||||
|
||||
keyData, err = certutil.MarshalPKCS8PrivateKey(signer)
|
||||
keyData, err = x509.MarshalPKCS8PrivateKey(signer)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error converting response to pkcs8: error marshaling pkcs8 key: {{err}}", err)
|
||||
}
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
// Copyright 2011 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 certutil
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
||||
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||
|
||||
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
)
|
||||
|
||||
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
|
||||
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
|
||||
// and RFC 5208.
|
||||
type pkcs8 struct {
|
||||
Version int
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
PrivateKey []byte
|
||||
// optional attributes omitted.
|
||||
}
|
||||
|
||||
type ecPrivateKey struct {
|
||||
Version int
|
||||
PrivateKey []byte
|
||||
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
|
||||
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
|
||||
}
|
||||
|
||||
// MarshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form.
|
||||
// The following key types are supported: *rsa.PrivateKey, *ecdsa.PublicKey.
|
||||
// Unsupported key types result in an error.
|
||||
//
|
||||
// See RFC 5208.
|
||||
func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) {
|
||||
var privKey pkcs8
|
||||
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
privKey.Algo = pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidPublicKeyRSA,
|
||||
Parameters: asn1.NullRawValue,
|
||||
}
|
||||
privKey.PrivateKey = x509.MarshalPKCS1PrivateKey(k)
|
||||
|
||||
case *ecdsa.PrivateKey:
|
||||
oid, ok := oidFromNamedCurve(k.Curve)
|
||||
if !ok {
|
||||
return nil, errors.New("x509: unknown curve while marshalling to PKCS#8")
|
||||
}
|
||||
|
||||
oidBytes, err := asn1.Marshal(oid)
|
||||
if err != nil {
|
||||
return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
|
||||
}
|
||||
|
||||
privKey.Algo = pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidPublicKeyECDSA,
|
||||
Parameters: asn1.RawValue{
|
||||
FullBytes: oidBytes,
|
||||
},
|
||||
}
|
||||
|
||||
if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil {
|
||||
return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("x509: unknown key type while marshalling PKCS#8: %T", key)
|
||||
}
|
||||
|
||||
return asn1.Marshal(privKey)
|
||||
}
|
||||
|
||||
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
|
||||
switch curve {
|
||||
case elliptic.P224():
|
||||
return oidNamedCurveP224, true
|
||||
case elliptic.P256():
|
||||
return oidNamedCurveP256, true
|
||||
case elliptic.P384():
|
||||
return oidNamedCurveP384, true
|
||||
case elliptic.P521():
|
||||
return oidNamedCurveP521, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// marshalECPrivateKey marshals an EC private key into ASN.1, DER format and
|
||||
// sets the curve ID to the given OID, or omits it if OID is nil.
|
||||
func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) {
|
||||
privateKeyBytes := key.D.Bytes()
|
||||
paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
|
||||
copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
|
||||
|
||||
return asn1.Marshal(ecPrivateKey{
|
||||
Version: 1,
|
||||
PrivateKey: paddedPrivateKey,
|
||||
NamedCurveOID: oid,
|
||||
PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
|
||||
})
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
// Copyright 2011 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 certutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Generated using:
|
||||
// openssl genrsa 1024 | openssl pkcs8 -topk8 -nocrypt
|
||||
var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
|
||||
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name secp224r1 | openssl pkcs8 -topk8 -nocrypt
|
||||
var pkcs8P224PrivateKeyHex = `3078020100301006072a8648ce3d020106052b810400210461305f020101041cca3d72b3e88fed2684576dad9b80a9180363a5424986900e3abcab3fa13c033a0004f8f2a6372872a4e61263ed893afb919576a4cacfecd6c081a2cbc76873cf4ba8530703c6042b3a00e2205087e87d2435d2e339e25702fae1`
|
||||
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name secp256r1 | openssl pkcs8 -topk8 -nocrypt
|
||||
var pkcs8P256PrivateKeyHex = `308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420dad6b2f49ca774c36d8ae9517e935226f667c929498f0343d2424d0b9b591b43a14403420004b9c9b90095476afe7b860d8bd43568cab7bcb2eed7b8bf2fa0ce1762dd20b04193f859d2d782b1e4cbfd48492f1f533113a6804903f292258513837f07fda735`
|
||||
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name secp384r1 | openssl pkcs8 -topk8 -nocrypt
|
||||
var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104309bf832f6aaaeacb78ce47ffb15e6fd0fd48683ae79df6eca39bfb8e33829ac94aa29d08911568684c2264a08a4ceb679a164036200049070ad4ed993c7770d700e9f6dc2baa83f63dd165b5507f98e8ff29b5d2e78ccbe05c8ddc955dbf0f7497e8222cfa49314fe4e269459f8e880147f70d785e530f2939e4bf9f838325bb1a80ad4cf59272ae0e5efe9a9dc33d874492596304bd3`
|
||||
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt
|
||||
//
|
||||
// Note that OpenSSL will truncate the private key if it can (i.e. it emits it
|
||||
// like an integer, even though it's an OCTET STRING field). Thus if you
|
||||
// regenerate this you may, randomly, find that it's a byte shorter than
|
||||
// expected and the Go test will fail to recreate it exactly.
|
||||
var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea`
|
||||
|
||||
func TestPKCS8(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
keyHex string
|
||||
keyType reflect.Type
|
||||
curve elliptic.Curve
|
||||
}{
|
||||
{
|
||||
name: "RSA private key",
|
||||
keyHex: pkcs8RSAPrivateKeyHex,
|
||||
keyType: reflect.TypeOf(&rsa.PrivateKey{}),
|
||||
},
|
||||
{
|
||||
name: "P-224 private key",
|
||||
keyHex: pkcs8P224PrivateKeyHex,
|
||||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
|
||||
curve: elliptic.P224(),
|
||||
},
|
||||
{
|
||||
name: "P-256 private key",
|
||||
keyHex: pkcs8P256PrivateKeyHex,
|
||||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
|
||||
curve: elliptic.P256(),
|
||||
},
|
||||
{
|
||||
name: "P-384 private key",
|
||||
keyHex: pkcs8P384PrivateKeyHex,
|
||||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
|
||||
curve: elliptic.P384(),
|
||||
},
|
||||
{
|
||||
name: "P-521 private key",
|
||||
keyHex: pkcs8P521PrivateKeyHex,
|
||||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
|
||||
curve: elliptic.P521(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
derBytes, err := hex.DecodeString(test.keyHex)
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to decode hex: %s", test.name, err)
|
||||
continue
|
||||
}
|
||||
privKey, err := x509.ParsePKCS8PrivateKey(derBytes)
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to decode PKCS#8: %s", test.name, err)
|
||||
continue
|
||||
}
|
||||
if reflect.TypeOf(privKey) != test.keyType {
|
||||
t.Errorf("%s: decoded PKCS#8 returned unexpected key type: %T", test.name, privKey)
|
||||
continue
|
||||
}
|
||||
if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC && ecKey.Curve != test.curve {
|
||||
t.Errorf("%s: decoded PKCS#8 returned unexpected curve %#v", test.name, ecKey.Curve)
|
||||
continue
|
||||
}
|
||||
reserialised, err := MarshalPKCS8PrivateKey(privKey)
|
||||
if err != nil {
|
||||
t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err)
|
||||
continue
|
||||
}
|
||||
if !bytes.Equal(derBytes, reserialised) {
|
||||
t.Errorf("%s: marshalled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,11 +4,10 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"math/big"
|
||||
paths "path"
|
||||
"strings"
|
||||
|
||||
big "github.com/hashicorp/golang-math-big/big"
|
||||
|
||||
"github.com/hashicorp/golang-lru"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
|
|
@ -10,7 +10,7 @@ RUN apt-get update -y && apt-get install --no-install-recommends -y -q \
|
|||
git mercurial bzr \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV GOVERSION 1.9.3
|
||||
ENV GOVERSION 1.10.1
|
||||
RUN mkdir /goroot && mkdir /gopath
|
||||
RUN curl https://storage.googleapis.com/golang/go${GOVERSION}.linux-amd64.tar.gz \
|
||||
| tar xvzf - -C /goroot --strip-components=1
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,17 +0,0 @@
|
|||
// generated by stringer -type=Accuracy; DO NOT EDIT
|
||||
|
||||
package big
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _Accuracy_name = "BelowExactAbove"
|
||||
|
||||
var _Accuracy_index = [...]uint8{0, 5, 10, 15}
|
||||
|
||||
func (i Accuracy) String() string {
|
||||
i -= -1
|
||||
if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
|
||||
return fmt.Sprintf("Accuracy(%d)", i+-1)
|
||||
}
|
||||
return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file provides Go implementations of elementary multi-precision
|
||||
// arithmetic operations on word vectors. Needed for platforms without
|
||||
// assembly implementations of these routines.
|
||||
|
||||
package big
|
||||
|
||||
import "math/bits"
|
||||
|
||||
// A Word represents a single digit of a multi-precision unsigned integer.
|
||||
type Word uint
|
||||
|
||||
const (
|
||||
_S = _W / 8 // word size in bytes
|
||||
|
||||
_W = bits.UintSize // word size in bits
|
||||
_B = 1 << _W // digit base
|
||||
_M = _B - 1 // digit mask
|
||||
|
||||
_W2 = _W / 2 // half word size in bits
|
||||
_B2 = 1 << _W2 // half digit base
|
||||
_M2 = _B2 - 1 // half digit mask
|
||||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Elementary operations on words
|
||||
//
|
||||
// These operations are used by the vector operations below.
|
||||
|
||||
// z1<<_W + z0 = x+y+c, with c == 0 or 1
|
||||
func addWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
yc := y + c
|
||||
z0 = x + yc
|
||||
if z0 < x || yc < y {
|
||||
z1 = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x-y-c, with c == 0 or 1
|
||||
func subWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
yc := y + c
|
||||
z0 = x - yc
|
||||
if z0 > x || yc < y {
|
||||
z1 = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x*y
|
||||
// Adapted from Warren, Hacker's Delight, p. 132.
|
||||
func mulWW_g(x, y Word) (z1, z0 Word) {
|
||||
x0 := x & _M2
|
||||
x1 := x >> _W2
|
||||
y0 := y & _M2
|
||||
y1 := y >> _W2
|
||||
w0 := x0 * y0
|
||||
t := x1*y0 + w0>>_W2
|
||||
w1 := t & _M2
|
||||
w2 := t >> _W2
|
||||
w1 += x0 * y1
|
||||
z1 = x1*y1 + w2 + w1>>_W2
|
||||
z0 = x * y
|
||||
return
|
||||
}
|
||||
|
||||
// z1<<_W + z0 = x*y + c
|
||||
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
z1, zz0 := mulWW_g(x, y)
|
||||
if z0 = zz0 + c; z0 < zz0 {
|
||||
z1++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// nlz returns the number of leading zeros in x.
|
||||
// Wraps bits.LeadingZeros call for convenience.
|
||||
func nlz(x Word) uint {
|
||||
return uint(bits.LeadingZeros(uint(x)))
|
||||
}
|
||||
|
||||
// q = (u1<<_W + u0 - r)/y
|
||||
// Adapted from Warren, Hacker's Delight, p. 152.
|
||||
func divWW_g(u1, u0, v Word) (q, r Word) {
|
||||
if u1 >= v {
|
||||
return 1<<_W - 1, 1<<_W - 1
|
||||
}
|
||||
|
||||
s := nlz(v)
|
||||
v <<= s
|
||||
|
||||
vn1 := v >> _W2
|
||||
vn0 := v & _M2
|
||||
un32 := u1<<s | u0>>(_W-s)
|
||||
un10 := u0 << s
|
||||
un1 := un10 >> _W2
|
||||
un0 := un10 & _M2
|
||||
q1 := un32 / vn1
|
||||
rhat := un32 - q1*vn1
|
||||
|
||||
for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
|
||||
q1--
|
||||
rhat += vn1
|
||||
if rhat >= _B2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
un21 := un32*_B2 + un1 - q1*v
|
||||
q0 := un21 / vn1
|
||||
rhat = un21 - q0*vn1
|
||||
|
||||
for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
|
||||
q0--
|
||||
rhat += vn1
|
||||
if rhat >= _B2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
|
||||
}
|
||||
|
||||
// Keep for performance debugging.
|
||||
// Using addWW_g is likely slower.
|
||||
const use_addWW_g = false
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi + yi + c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func subVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi - yi - c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], c, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi + c
|
||||
z[i] = zi
|
||||
c = xi &^ zi >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], c, 0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi - c
|
||||
z[i] = zi
|
||||
c = (zi &^ xi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shlVU_g(z, x []Word, s uint) (c Word) {
|
||||
if n := len(z); n > 0 {
|
||||
ŝ := _W - s
|
||||
w1 := x[n-1]
|
||||
c = w1 >> ŝ
|
||||
for i := n - 1; i > 0; i-- {
|
||||
w := w1
|
||||
w1 = x[i-1]
|
||||
z[i] = w<<s | w1>>ŝ
|
||||
}
|
||||
z[0] = w1 << s
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shrVU_g(z, x []Word, s uint) (c Word) {
|
||||
if n := len(z); n > 0 {
|
||||
ŝ := _W - s
|
||||
w1 := x[0]
|
||||
c = w1 << ŝ
|
||||
for i := 0; i < n-1; i++ {
|
||||
w := w1
|
||||
w1 = x[i+1]
|
||||
z[i] = w>>s | w1<<ŝ
|
||||
}
|
||||
z[n-1] = w1 >> s
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
|
||||
c = r
|
||||
for i := range z {
|
||||
c, z[i] = mulAddWWW_g(x[i], y, c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
|
||||
func addMulVVW_g(z, x []Word, y Word) (c Word) {
|
||||
for i := range z {
|
||||
z1, z0 := mulAddWWW_g(x[i], y, z[i])
|
||||
c, z[i] = addWW_g(z0, c, 0)
|
||||
c += z1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
|
||||
r = xn
|
||||
for i := len(z) - 1; i >= 0; i-- {
|
||||
z[i], r = divWW_g(r, x[i], y)
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
MOVL x+0(FP), AX
|
||||
MULL y+4(FP)
|
||||
MOVL DX, z1+8(FP)
|
||||
MOVL AX, z0+12(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWW(x1, x0, y Word) (q, r Word)
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
MOVL x1+0(FP), DX
|
||||
MOVL x0+4(FP), AX
|
||||
DIVL y+8(FP)
|
||||
MOVL AX, q+12(FP)
|
||||
MOVL DX, r+16(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addVV(z, x, y []Word) (c Word)
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), CX
|
||||
MOVL z_len+4(FP), BP
|
||||
MOVL $0, BX // i = 0
|
||||
MOVL $0, DX // c = 0
|
||||
JMP E1
|
||||
|
||||
L1: MOVL (SI)(BX*4), AX
|
||||
ADDL DX, DX // restore CF
|
||||
ADCL (CX)(BX*4), AX
|
||||
SBBL DX, DX // save CF
|
||||
MOVL AX, (DI)(BX*4)
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E1: CMPL BX, BP // i < n
|
||||
JL L1
|
||||
|
||||
NEGL DX
|
||||
MOVL DX, c+36(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVV(z, x, y []Word) (c Word)
|
||||
// (same as addVV except for SBBL instead of ADCL and label names)
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), CX
|
||||
MOVL z_len+4(FP), BP
|
||||
MOVL $0, BX // i = 0
|
||||
MOVL $0, DX // c = 0
|
||||
JMP E2
|
||||
|
||||
L2: MOVL (SI)(BX*4), AX
|
||||
ADDL DX, DX // restore CF
|
||||
SBBL (CX)(BX*4), AX
|
||||
SBBL DX, DX // save CF
|
||||
MOVL AX, (DI)(BX*4)
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E2: CMPL BX, BP // i < n
|
||||
JL L2
|
||||
|
||||
NEGL DX
|
||||
MOVL DX, c+36(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), AX // c = y
|
||||
MOVL z_len+4(FP), BP
|
||||
MOVL $0, BX // i = 0
|
||||
JMP E3
|
||||
|
||||
L3: ADDL (SI)(BX*4), AX
|
||||
MOVL AX, (DI)(BX*4)
|
||||
SBBL AX, AX // save CF
|
||||
NEGL AX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E3: CMPL BX, BP // i < n
|
||||
JL L3
|
||||
|
||||
MOVL AX, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), AX // c = y
|
||||
MOVL z_len+4(FP), BP
|
||||
MOVL $0, BX // i = 0
|
||||
JMP E4
|
||||
|
||||
L4: MOVL (SI)(BX*4), DX
|
||||
SUBL AX, DX
|
||||
MOVL DX, (DI)(BX*4)
|
||||
SBBL AX, AX // save CF
|
||||
NEGL AX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E4: CMPL BX, BP // i < n
|
||||
JL L4
|
||||
|
||||
MOVL AX, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shlVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
MOVL z_len+4(FP), BX // i = z
|
||||
SUBL $1, BX // i--
|
||||
JL X8b // i < 0 (n <= 0)
|
||||
|
||||
// n > 0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL s+24(FP), CX
|
||||
MOVL (SI)(BX*4), AX // w1 = x[n-1]
|
||||
MOVL $0, DX
|
||||
SHLL CX, DX:AX // w1>>ŝ
|
||||
MOVL DX, c+28(FP)
|
||||
|
||||
CMPL BX, $0
|
||||
JLE X8a // i <= 0
|
||||
|
||||
// i > 0
|
||||
L8: MOVL AX, DX // w = w1
|
||||
MOVL -4(SI)(BX*4), AX // w1 = x[i-1]
|
||||
SHLL CX, DX:AX // w<<s | w1>>ŝ
|
||||
MOVL DX, (DI)(BX*4) // z[i] = w<<s | w1>>ŝ
|
||||
SUBL $1, BX // i--
|
||||
JG L8 // i > 0
|
||||
|
||||
// i <= 0
|
||||
X8a: SHLL CX, AX // w1<<s
|
||||
MOVL AX, (DI) // z[0] = w1<<s
|
||||
RET
|
||||
|
||||
X8b: MOVL $0, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shrVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
MOVL z_len+4(FP), BP
|
||||
SUBL $1, BP // n--
|
||||
JL X9b // n < 0 (n <= 0)
|
||||
|
||||
// n > 0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL s+24(FP), CX
|
||||
MOVL (SI), AX // w1 = x[0]
|
||||
MOVL $0, DX
|
||||
SHRL CX, DX:AX // w1<<ŝ
|
||||
MOVL DX, c+28(FP)
|
||||
|
||||
MOVL $0, BX // i = 0
|
||||
JMP E9
|
||||
|
||||
// i < n-1
|
||||
L9: MOVL AX, DX // w = w1
|
||||
MOVL 4(SI)(BX*4), AX // w1 = x[i+1]
|
||||
SHRL CX, DX:AX // w>>s | w1<<ŝ
|
||||
MOVL DX, (DI)(BX*4) // z[i] = w>>s | w1<<ŝ
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E9: CMPL BX, BP
|
||||
JL L9 // i < n-1
|
||||
|
||||
// i >= n-1
|
||||
X9a: SHRL CX, AX // w1>>s
|
||||
MOVL AX, (DI)(BP*4) // z[n-1] = w1>>s
|
||||
RET
|
||||
|
||||
X9b: MOVL $0, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), BP
|
||||
MOVL r+28(FP), CX // c = r
|
||||
MOVL z_len+4(FP), BX
|
||||
LEAL (DI)(BX*4), DI
|
||||
LEAL (SI)(BX*4), SI
|
||||
NEGL BX // i = -n
|
||||
JMP E5
|
||||
|
||||
L5: MOVL (SI)(BX*4), AX
|
||||
MULL BP
|
||||
ADDL CX, AX
|
||||
ADCL $0, DX
|
||||
MOVL AX, (DI)(BX*4)
|
||||
MOVL DX, CX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E5: CMPL BX, $0 // i < 0
|
||||
JL L5
|
||||
|
||||
MOVL CX, c+32(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL x+12(FP), SI
|
||||
MOVL y+24(FP), BP
|
||||
MOVL z_len+4(FP), BX
|
||||
LEAL (DI)(BX*4), DI
|
||||
LEAL (SI)(BX*4), SI
|
||||
NEGL BX // i = -n
|
||||
MOVL $0, CX // c = 0
|
||||
JMP E6
|
||||
|
||||
L6: MOVL (SI)(BX*4), AX
|
||||
MULL BP
|
||||
ADDL CX, AX
|
||||
ADCL $0, DX
|
||||
ADDL AX, (DI)(BX*4)
|
||||
ADCL $0, DX
|
||||
MOVL DX, CX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E6: CMPL BX, $0 // i < 0
|
||||
JL L6
|
||||
|
||||
MOVL CX, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
MOVL z+0(FP), DI
|
||||
MOVL xn+12(FP), DX // r = xn
|
||||
MOVL x+16(FP), SI
|
||||
MOVL y+28(FP), CX
|
||||
MOVL z_len+4(FP), BX // i = z
|
||||
JMP E7
|
||||
|
||||
L7: MOVL (SI)(BX*4), AX
|
||||
DIVL CX
|
||||
MOVL AX, (DI)(BX*4)
|
||||
|
||||
E7: SUBL $1, BX // i--
|
||||
JGE L7 // i >= 0
|
||||
|
||||
MOVL DX, r+32(FP)
|
||||
RET
|
|
@ -1,450 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
MOVQ x+0(FP), AX
|
||||
MULQ y+8(FP)
|
||||
MOVQ DX, z1+16(FP)
|
||||
MOVQ AX, z0+24(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWW(x1, x0, y Word) (q, r Word)
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
MOVQ x1+0(FP), DX
|
||||
MOVQ x0+8(FP), AX
|
||||
DIVQ y+16(FP)
|
||||
MOVQ AX, q+24(FP)
|
||||
MOVQ DX, r+32(FP)
|
||||
RET
|
||||
|
||||
// The carry bit is saved with SBBQ Rx, Rx: if the carry was set, Rx is -1, otherwise it is 0.
|
||||
// It is restored with ADDQ Rx, Rx: if Rx was -1 the carry is set, otherwise it is cleared.
|
||||
// This is faster than using rotate instructions.
|
||||
|
||||
// func addVV(z, x, y []Word) (c Word)
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), DI
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), R9
|
||||
MOVQ z+0(FP), R10
|
||||
|
||||
MOVQ $0, CX // c = 0
|
||||
MOVQ $0, SI // i = 0
|
||||
|
||||
// s/JL/JMP/ below to disable the unrolled loop
|
||||
SUBQ $4, DI // n -= 4
|
||||
JL V1 // if n < 0 goto V1
|
||||
|
||||
U1: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
ADCQ 0(R9)(SI*8), R11
|
||||
ADCQ 8(R9)(SI*8), R12
|
||||
ADCQ 16(R9)(SI*8), R13
|
||||
ADCQ 24(R9)(SI*8), R14
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
JGE U1 // if n >= 0 goto U1
|
||||
|
||||
V1: ADDQ $4, DI // n += 4
|
||||
JLE E1 // if n <= 0 goto E1
|
||||
|
||||
L1: // n > 0
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
ADCQ 0(R9)(SI*8), R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L1 // if n > 0 goto L1
|
||||
|
||||
E1: NEGQ CX
|
||||
MOVQ CX, c+72(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
// func subVV(z, x, y []Word) (c Word)
|
||||
// (same as addVV except for SBBQ instead of ADCQ and label names)
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), DI
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), R9
|
||||
MOVQ z+0(FP), R10
|
||||
|
||||
MOVQ $0, CX // c = 0
|
||||
MOVQ $0, SI // i = 0
|
||||
|
||||
// s/JL/JMP/ below to disable the unrolled loop
|
||||
SUBQ $4, DI // n -= 4
|
||||
JL V2 // if n < 0 goto V2
|
||||
|
||||
U2: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
SBBQ 0(R9)(SI*8), R11
|
||||
SBBQ 8(R9)(SI*8), R12
|
||||
SBBQ 16(R9)(SI*8), R13
|
||||
SBBQ 24(R9)(SI*8), R14
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
JGE U2 // if n >= 0 goto U2
|
||||
|
||||
V2: ADDQ $4, DI // n += 4
|
||||
JLE E2 // if n <= 0 goto E2
|
||||
|
||||
L2: // n > 0
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
SBBQ 0(R9)(SI*8), R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L2 // if n > 0 goto L2
|
||||
|
||||
E2: NEGQ CX
|
||||
MOVQ CX, c+72(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
// func addVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), DI
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), CX // c = y
|
||||
MOVQ z+0(FP), R10
|
||||
|
||||
MOVQ $0, SI // i = 0
|
||||
|
||||
// s/JL/JMP/ below to disable the unrolled loop
|
||||
SUBQ $4, DI // n -= 4
|
||||
JL V3 // if n < 4 goto V3
|
||||
|
||||
U3: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
ADDQ CX, R11
|
||||
ADCQ $0, R12
|
||||
ADCQ $0, R13
|
||||
ADCQ $0, R14
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
JGE U3 // if n >= 0 goto U3
|
||||
|
||||
V3: ADDQ $4, DI // n += 4
|
||||
JLE E3 // if n <= 0 goto E3
|
||||
|
||||
L3: // n > 0
|
||||
ADDQ 0(R8)(SI*8), CX
|
||||
MOVQ CX, 0(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L3 // if n > 0 goto L3
|
||||
|
||||
E3: MOVQ CX, c+56(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
// func subVW(z, x []Word, y Word) (c Word)
|
||||
// (same as addVW except for SUBQ/SBBQ instead of ADDQ/ADCQ and label names)
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), DI
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), CX // c = y
|
||||
MOVQ z+0(FP), R10
|
||||
|
||||
MOVQ $0, SI // i = 0
|
||||
|
||||
// s/JL/JMP/ below to disable the unrolled loop
|
||||
SUBQ $4, DI // n -= 4
|
||||
JL V4 // if n < 4 goto V4
|
||||
|
||||
U4: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
SUBQ CX, R11
|
||||
SBBQ $0, R12
|
||||
SBBQ $0, R13
|
||||
SBBQ $0, R14
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
JGE U4 // if n >= 0 goto U4
|
||||
|
||||
V4: ADDQ $4, DI // n += 4
|
||||
JLE E4 // if n <= 0 goto E4
|
||||
|
||||
L4: // n > 0
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
SUBQ CX, R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L4 // if n > 0 goto L4
|
||||
|
||||
E4: MOVQ CX, c+56(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
// func shlVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), BX // i = z
|
||||
SUBQ $1, BX // i--
|
||||
JL X8b // i < 0 (n <= 0)
|
||||
|
||||
// n > 0
|
||||
MOVQ z+0(FP), R10
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ s+48(FP), CX
|
||||
MOVQ (R8)(BX*8), AX // w1 = x[n-1]
|
||||
MOVQ $0, DX
|
||||
SHLQ CX, DX:AX // w1>>ŝ
|
||||
MOVQ DX, c+56(FP)
|
||||
|
||||
CMPQ BX, $0
|
||||
JLE X8a // i <= 0
|
||||
|
||||
// i > 0
|
||||
L8: MOVQ AX, DX // w = w1
|
||||
MOVQ -8(R8)(BX*8), AX // w1 = x[i-1]
|
||||
SHLQ CX, DX:AX // w<<s | w1>>ŝ
|
||||
MOVQ DX, (R10)(BX*8) // z[i] = w<<s | w1>>ŝ
|
||||
SUBQ $1, BX // i--
|
||||
JG L8 // i > 0
|
||||
|
||||
// i <= 0
|
||||
X8a: SHLQ CX, AX // w1<<s
|
||||
MOVQ AX, (R10) // z[0] = w1<<s
|
||||
RET
|
||||
|
||||
X8b: MOVQ $0, c+56(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shrVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
MOVQ z_len+8(FP), R11
|
||||
SUBQ $1, R11 // n--
|
||||
JL X9b // n < 0 (n <= 0)
|
||||
|
||||
// n > 0
|
||||
MOVQ z+0(FP), R10
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ s+48(FP), CX
|
||||
MOVQ (R8), AX // w1 = x[0]
|
||||
MOVQ $0, DX
|
||||
SHRQ CX, DX:AX // w1<<ŝ
|
||||
MOVQ DX, c+56(FP)
|
||||
|
||||
MOVQ $0, BX // i = 0
|
||||
JMP E9
|
||||
|
||||
// i < n-1
|
||||
L9: MOVQ AX, DX // w = w1
|
||||
MOVQ 8(R8)(BX*8), AX // w1 = x[i+1]
|
||||
SHRQ CX, DX:AX // w>>s | w1<<ŝ
|
||||
MOVQ DX, (R10)(BX*8) // z[i] = w>>s | w1<<ŝ
|
||||
ADDQ $1, BX // i++
|
||||
|
||||
E9: CMPQ BX, R11
|
||||
JL L9 // i < n-1
|
||||
|
||||
// i >= n-1
|
||||
X9a: SHRQ CX, AX // w1>>s
|
||||
MOVQ AX, (R10)(R11*8) // z[n-1] = w1>>s
|
||||
RET
|
||||
|
||||
X9b: MOVQ $0, c+56(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
MOVQ z+0(FP), R10
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), R9
|
||||
MOVQ r+56(FP), CX // c = r
|
||||
MOVQ z_len+8(FP), R11
|
||||
MOVQ $0, BX // i = 0
|
||||
|
||||
CMPQ R11, $4
|
||||
JL E5
|
||||
|
||||
U5: // i+4 <= n
|
||||
// regular loop body unrolled 4x
|
||||
MOVQ (0*8)(R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ AX, (0*8)(R10)(BX*8)
|
||||
MOVQ DX, CX
|
||||
MOVQ (1*8)(R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ AX, (1*8)(R10)(BX*8)
|
||||
MOVQ DX, CX
|
||||
MOVQ (2*8)(R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ AX, (2*8)(R10)(BX*8)
|
||||
MOVQ DX, CX
|
||||
MOVQ (3*8)(R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ AX, (3*8)(R10)(BX*8)
|
||||
MOVQ DX, CX
|
||||
ADDQ $4, BX // i += 4
|
||||
|
||||
LEAQ 4(BX), DX
|
||||
CMPQ DX, R11
|
||||
JLE U5
|
||||
JMP E5
|
||||
|
||||
L5: MOVQ (R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ AX, (R10)(BX*8)
|
||||
MOVQ DX, CX
|
||||
ADDQ $1, BX // i++
|
||||
|
||||
E5: CMPQ BX, R11 // i < n
|
||||
JL L5
|
||||
|
||||
MOVQ CX, c+64(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
MOVQ z+0(FP), R10
|
||||
MOVQ x+24(FP), R8
|
||||
MOVQ y+48(FP), R9
|
||||
MOVQ z_len+8(FP), R11
|
||||
MOVQ $0, BX // i = 0
|
||||
MOVQ $0, CX // c = 0
|
||||
MOVQ R11, R12
|
||||
ANDQ $-2, R12
|
||||
CMPQ R11, $2
|
||||
JAE A6
|
||||
JMP E6
|
||||
|
||||
A6:
|
||||
MOVQ (R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ (R10)(BX*8), AX
|
||||
ADCQ $0, DX
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ DX, CX
|
||||
MOVQ AX, (R10)(BX*8)
|
||||
|
||||
MOVQ (8)(R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ (8)(R10)(BX*8), AX
|
||||
ADCQ $0, DX
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
MOVQ DX, CX
|
||||
MOVQ AX, (8)(R10)(BX*8)
|
||||
|
||||
ADDQ $2, BX
|
||||
CMPQ BX, R12
|
||||
JL A6
|
||||
JMP E6
|
||||
|
||||
L6: MOVQ (R8)(BX*8), AX
|
||||
MULQ R9
|
||||
ADDQ CX, AX
|
||||
ADCQ $0, DX
|
||||
ADDQ AX, (R10)(BX*8)
|
||||
ADCQ $0, DX
|
||||
MOVQ DX, CX
|
||||
ADDQ $1, BX // i++
|
||||
|
||||
E6: CMPQ BX, R11 // i < n
|
||||
JL L6
|
||||
|
||||
MOVQ CX, c+56(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
MOVQ z+0(FP), R10
|
||||
MOVQ xn+24(FP), DX // r = xn
|
||||
MOVQ x+32(FP), R8
|
||||
MOVQ y+56(FP), R9
|
||||
MOVQ z_len+8(FP), BX // i = z
|
||||
JMP E7
|
||||
|
||||
L7: MOVQ (R8)(BX*8), AX
|
||||
DIVQ R9
|
||||
MOVQ AX, (R10)(BX*8)
|
||||
|
||||
E7: SUBQ $1, BX // i--
|
||||
JGE L7 // i >= 0
|
||||
|
||||
MOVQ DX, r+64(FP)
|
||||
RET
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
JMP ·mulWW_g(SB)
|
||||
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
JMP ·divWW_g(SB)
|
||||
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
JMP ·addVV_g(SB)
|
||||
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
JMP ·subVV_g(SB)
|
||||
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
JMP ·addVW_g(SB)
|
||||
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
JMP ·subVW_g(SB)
|
||||
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
JMP ·shlVU_g(SB)
|
||||
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
JMP ·shrVU_g(SB)
|
||||
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
JMP ·mulAddVWW_g(SB)
|
||||
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
JMP ·addMulVVW_g(SB)
|
||||
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
JMP ·divWVW_g(SB)
|
|
@ -1,294 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// func addVV(z, x, y []Word) (c Word)
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
ADD.S $0, R0 // clear carry flag
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R4
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
ADD R4<<2, R1, R4
|
||||
B E1
|
||||
L1:
|
||||
MOVW.P 4(R2), R5
|
||||
MOVW.P 4(R3), R6
|
||||
ADC.S R6, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
E1:
|
||||
TEQ R1, R4
|
||||
BNE L1
|
||||
|
||||
MOVW $0, R0
|
||||
MOVW.CS $1, R0
|
||||
MOVW R0, c+36(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVV(z, x, y []Word) (c Word)
|
||||
// (same as addVV except for SBC instead of ADC and label names)
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
SUB.S $0, R0 // clear borrow flag
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R4
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
ADD R4<<2, R1, R4
|
||||
B E2
|
||||
L2:
|
||||
MOVW.P 4(R2), R5
|
||||
MOVW.P 4(R3), R6
|
||||
SBC.S R6, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
E2:
|
||||
TEQ R1, R4
|
||||
BNE L2
|
||||
|
||||
MOVW $0, R0
|
||||
MOVW.CC $1, R0
|
||||
MOVW R0, c+36(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R4
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
ADD R4<<2, R1, R4
|
||||
TEQ R1, R4
|
||||
BNE L3a
|
||||
MOVW R3, c+28(FP)
|
||||
RET
|
||||
L3a:
|
||||
MOVW.P 4(R2), R5
|
||||
ADD.S R3, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
B E3
|
||||
L3:
|
||||
MOVW.P 4(R2), R5
|
||||
ADC.S $0, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
E3:
|
||||
TEQ R1, R4
|
||||
BNE L3
|
||||
|
||||
MOVW $0, R0
|
||||
MOVW.CS $1, R0
|
||||
MOVW R0, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R4
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
ADD R4<<2, R1, R4
|
||||
TEQ R1, R4
|
||||
BNE L4a
|
||||
MOVW R3, c+28(FP)
|
||||
RET
|
||||
L4a:
|
||||
MOVW.P 4(R2), R5
|
||||
SUB.S R3, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
B E4
|
||||
L4:
|
||||
MOVW.P 4(R2), R5
|
||||
SBC.S $0, R5
|
||||
MOVW.P R5, 4(R1)
|
||||
E4:
|
||||
TEQ R1, R4
|
||||
BNE L4
|
||||
|
||||
MOVW $0, R0
|
||||
MOVW.CC $1, R0
|
||||
MOVW R0, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shlVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
MOVW z_len+4(FP), R5
|
||||
TEQ $0, R5
|
||||
BEQ X7
|
||||
|
||||
MOVW z+0(FP), R1
|
||||
MOVW x+12(FP), R2
|
||||
ADD R5<<2, R2, R2
|
||||
ADD R5<<2, R1, R5
|
||||
MOVW s+24(FP), R3
|
||||
TEQ $0, R3 // shift 0 is special
|
||||
BEQ Y7
|
||||
ADD $4, R1 // stop one word early
|
||||
MOVW $32, R4
|
||||
SUB R3, R4
|
||||
MOVW $0, R7
|
||||
|
||||
MOVW.W -4(R2), R6
|
||||
MOVW R6<<R3, R7
|
||||
MOVW R6>>R4, R6
|
||||
MOVW R6, c+28(FP)
|
||||
B E7
|
||||
|
||||
L7:
|
||||
MOVW.W -4(R2), R6
|
||||
ORR R6>>R4, R7
|
||||
MOVW.W R7, -4(R5)
|
||||
MOVW R6<<R3, R7
|
||||
E7:
|
||||
TEQ R1, R5
|
||||
BNE L7
|
||||
|
||||
MOVW R7, -4(R5)
|
||||
RET
|
||||
|
||||
Y7: // copy loop, because shift 0 == shift 32
|
||||
MOVW.W -4(R2), R6
|
||||
MOVW.W R6, -4(R5)
|
||||
TEQ R1, R5
|
||||
BNE Y7
|
||||
|
||||
X7:
|
||||
MOVW $0, R1
|
||||
MOVW R1, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shrVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
MOVW z_len+4(FP), R5
|
||||
TEQ $0, R5
|
||||
BEQ X6
|
||||
|
||||
MOVW z+0(FP), R1
|
||||
MOVW x+12(FP), R2
|
||||
ADD R5<<2, R1, R5
|
||||
MOVW s+24(FP), R3
|
||||
TEQ $0, R3 // shift 0 is special
|
||||
BEQ Y6
|
||||
SUB $4, R5 // stop one word early
|
||||
MOVW $32, R4
|
||||
SUB R3, R4
|
||||
MOVW $0, R7
|
||||
|
||||
// first word
|
||||
MOVW.P 4(R2), R6
|
||||
MOVW R6>>R3, R7
|
||||
MOVW R6<<R4, R6
|
||||
MOVW R6, c+28(FP)
|
||||
B E6
|
||||
|
||||
// word loop
|
||||
L6:
|
||||
MOVW.P 4(R2), R6
|
||||
ORR R6<<R4, R7
|
||||
MOVW.P R7, 4(R1)
|
||||
MOVW R6>>R3, R7
|
||||
E6:
|
||||
TEQ R1, R5
|
||||
BNE L6
|
||||
|
||||
MOVW R7, 0(R1)
|
||||
RET
|
||||
|
||||
Y6: // copy loop, because shift 0 == shift 32
|
||||
MOVW.P 4(R2), R6
|
||||
MOVW.P R6, 4(R1)
|
||||
TEQ R1, R5
|
||||
BNE Y6
|
||||
|
||||
X6:
|
||||
MOVW $0, R1
|
||||
MOVW R1, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
MOVW $0, R0
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R5
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
MOVW r+28(FP), R4
|
||||
ADD R5<<2, R1, R5
|
||||
B E8
|
||||
|
||||
// word loop
|
||||
L8:
|
||||
MOVW.P 4(R2), R6
|
||||
MULLU R6, R3, (R7, R6)
|
||||
ADD.S R4, R6
|
||||
ADC R0, R7
|
||||
MOVW.P R6, 4(R1)
|
||||
MOVW R7, R4
|
||||
E8:
|
||||
TEQ R1, R5
|
||||
BNE L8
|
||||
|
||||
MOVW R4, c+32(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
MOVW $0, R0
|
||||
MOVW z+0(FP), R1
|
||||
MOVW z_len+4(FP), R5
|
||||
MOVW x+12(FP), R2
|
||||
MOVW y+24(FP), R3
|
||||
ADD R5<<2, R1, R5
|
||||
MOVW $0, R4
|
||||
B E9
|
||||
|
||||
// word loop
|
||||
L9:
|
||||
MOVW.P 4(R2), R6
|
||||
MULLU R6, R3, (R7, R6)
|
||||
ADD.S R4, R6
|
||||
ADC R0, R7
|
||||
MOVW 0(R1), R4
|
||||
ADD.S R4, R6
|
||||
ADC R0, R7
|
||||
MOVW.P R6, 4(R1)
|
||||
MOVW R7, R4
|
||||
E9:
|
||||
TEQ R1, R5
|
||||
BNE L9
|
||||
|
||||
MOVW R4, c+28(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
// ARM has no multiword division, so use portable code.
|
||||
B ·divWVW_g(SB)
|
||||
|
||||
|
||||
// func divWW(x1, x0, y Word) (q, r Word)
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
// ARM has no multiword division, so use portable code.
|
||||
B ·divWW_g(SB)
|
||||
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
MOVW x+0(FP), R1
|
||||
MOVW y+4(FP), R2
|
||||
MULLU R1, R2, (R4, R3)
|
||||
MOVW R4, z1+8(FP)
|
||||
MOVW R3, z0+12(FP)
|
||||
RET
|
|
@ -1,167 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// TODO: Consider re-implementing using Advanced SIMD
|
||||
// once the assembler supports those instructions.
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
MOVD x+0(FP), R0
|
||||
MOVD y+8(FP), R1
|
||||
MUL R0, R1, R2
|
||||
UMULH R0, R1, R3
|
||||
MOVD R3, z1+16(FP)
|
||||
MOVD R2, z0+24(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func divWW(x1, x0, y Word) (q, r Word)
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
B ·divWW_g(SB) // ARM64 has no multiword division
|
||||
|
||||
|
||||
// func addVV(z, x, y []Word) (c Word)
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
MOVD z+0(FP), R3
|
||||
MOVD z_len+8(FP), R0
|
||||
MOVD x+24(FP), R1
|
||||
MOVD y+48(FP), R2
|
||||
ADDS $0, R0 // clear carry flag
|
||||
loop:
|
||||
CBZ R0, done // careful not to touch the carry flag
|
||||
MOVD.P 8(R1), R4
|
||||
MOVD.P 8(R2), R5
|
||||
ADCS R4, R5
|
||||
MOVD.P R5, 8(R3)
|
||||
SUB $1, R0
|
||||
B loop
|
||||
done:
|
||||
CSET HS, R0 // extract carry flag
|
||||
MOVD R0, c+72(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVV(z, x, y []Word) (c Word)
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
MOVD z+0(FP), R3
|
||||
MOVD z_len+8(FP), R0
|
||||
MOVD x+24(FP), R1
|
||||
MOVD y+48(FP), R2
|
||||
CMP R0, R0 // set carry flag
|
||||
loop:
|
||||
CBZ R0, done // careful not to touch the carry flag
|
||||
MOVD.P 8(R1), R4
|
||||
MOVD.P 8(R2), R5
|
||||
SBCS R5, R4
|
||||
MOVD.P R4, 8(R3)
|
||||
SUB $1, R0
|
||||
B loop
|
||||
done:
|
||||
CSET LO, R0 // extract carry flag
|
||||
MOVD R0, c+72(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
MOVD z+0(FP), R3
|
||||
MOVD z_len+8(FP), R0
|
||||
MOVD x+24(FP), R1
|
||||
MOVD y+48(FP), R2
|
||||
CBZ R0, return_y
|
||||
MOVD.P 8(R1), R4
|
||||
ADDS R2, R4
|
||||
MOVD.P R4, 8(R3)
|
||||
SUB $1, R0
|
||||
loop:
|
||||
CBZ R0, done // careful not to touch the carry flag
|
||||
MOVD.P 8(R1), R4
|
||||
ADCS $0, R4
|
||||
MOVD.P R4, 8(R3)
|
||||
SUB $1, R0
|
||||
B loop
|
||||
done:
|
||||
CSET HS, R0 // extract carry flag
|
||||
MOVD R0, c+56(FP)
|
||||
RET
|
||||
return_y: // z is empty; copy y to c
|
||||
MOVD R2, c+56(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func subVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
MOVD z+0(FP), R3
|
||||
MOVD z_len+8(FP), R0
|
||||
MOVD x+24(FP), R1
|
||||
MOVD y+48(FP), R2
|
||||
CBZ R0, rety
|
||||
MOVD.P 8(R1), R4
|
||||
SUBS R2, R4
|
||||
MOVD.P R4, 8(R3)
|
||||
SUB $1, R0
|
||||
loop:
|
||||
CBZ R0, done // careful not to touch the carry flag
|
||||
MOVD.P 8(R1), R4
|
||||
SBCS $0, R4
|
||||
MOVD.P R4, 8(R3)
|
||||
SUB $1, R0
|
||||
B loop
|
||||
done:
|
||||
CSET LO, R0 // extract carry flag
|
||||
MOVD R0, c+56(FP)
|
||||
RET
|
||||
rety: // z is empty; copy y to c
|
||||
MOVD R2, c+56(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func shlVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
B ·shlVU_g(SB)
|
||||
|
||||
|
||||
// func shrVU(z, x []Word, s uint) (c Word)
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
B ·shrVU_g(SB)
|
||||
|
||||
|
||||
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
MOVD z+0(FP), R1
|
||||
MOVD z_len+8(FP), R0
|
||||
MOVD x+24(FP), R2
|
||||
MOVD y+48(FP), R3
|
||||
MOVD r+56(FP), R4
|
||||
loop:
|
||||
CBZ R0, done
|
||||
MOVD.P 8(R2), R5
|
||||
UMULH R5, R3, R7
|
||||
MUL R5, R3, R6
|
||||
ADDS R4, R6
|
||||
ADC $0, R7
|
||||
MOVD.P R6, 8(R1)
|
||||
MOVD R7, R4
|
||||
SUB $1, R0
|
||||
B loop
|
||||
done:
|
||||
MOVD R4, c+64(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
B ·addMulVVW_g(SB)
|
||||
|
||||
|
||||
// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
B ·divWVW_g(SB)
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright 2010 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
package big
|
||||
|
||||
// implemented in arith_$GOARCH.s
|
||||
func mulWW(x, y Word) (z1, z0 Word)
|
||||
func divWW(x1, x0, y Word) (q, r Word)
|
||||
func addVV(z, x, y []Word) (c Word)
|
||||
func subVV(z, x, y []Word) (c Word)
|
||||
func addVW(z, x []Word, y Word) (c Word)
|
||||
func subVW(z, x []Word, y Word) (c Word)
|
||||
func shlVU(z, x []Word, s uint) (c Word)
|
||||
func shrVU(z, x []Word, s uint) (c Word)
|
||||
func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// +build math_big_pure_go
|
||||
|
||||
package big
|
||||
|
||||
func mulWW(x, y Word) (z1, z0 Word) {
|
||||
return mulWW_g(x, y)
|
||||
}
|
||||
|
||||
func divWW(x1, x0, y Word) (q, r Word) {
|
||||
return divWW_g(x1, x0, y)
|
||||
}
|
||||
|
||||
func addVV(z, x, y []Word) (c Word) {
|
||||
return addVV_g(z, x, y)
|
||||
}
|
||||
|
||||
func subVV(z, x, y []Word) (c Word) {
|
||||
return subVV_g(z, x, y)
|
||||
}
|
||||
|
||||
func addVW(z, x []Word, y Word) (c Word) {
|
||||
return addVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func subVW(z, x []Word, y Word) (c Word) {
|
||||
return subVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func shlVU(z, x []Word, s uint) (c Word) {
|
||||
return shlVU_g(z, x, s)
|
||||
}
|
||||
|
||||
func shrVU(z, x []Word, s uint) (c Word) {
|
||||
return shrVU_g(z, x, s)
|
||||
}
|
||||
|
||||
func mulAddVWW(z, x []Word, y, r Word) (c Word) {
|
||||
return mulAddVWW_g(z, x, y, r)
|
||||
}
|
||||
|
||||
func addMulVVW(z, x []Word, y Word) (c Word) {
|
||||
return addMulVVW_g(z, x, y)
|
||||
}
|
||||
|
||||
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
|
||||
return divWVW_g(z, xn, x, y)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !math_big_pure_go
|
||||
|
||||
package big
|
||||
|
||||
func addVV_check(z, x, y []Word) (c Word)
|
||||
func addVV_vec(z, x, y []Word) (c Word)
|
||||
func addVV_novec(z, x, y []Word) (c Word)
|
||||
func subVV_check(z, x, y []Word) (c Word)
|
||||
func subVV_vec(z, x, y []Word) (c Word)
|
||||
func subVV_novec(z, x, y []Word) (c Word)
|
||||
func addVW_check(z, x []Word, y Word) (c Word)
|
||||
func addVW_vec(z, x []Word, y Word) (c Word)
|
||||
func addVW_novec(z, x []Word, y Word) (c Word)
|
||||
func subVW_check(z, x []Word, y Word) (c Word)
|
||||
func subVW_vec(z, x []Word, y Word) (c Word)
|
||||
func subVW_novec(z, x []Word, y Word) (c Word)
|
||||
func hasVectorFacility() bool
|
||||
|
||||
var hasVX = hasVectorFacility()
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// +build !math_big_pure_go,mips64 !math_big_pure_go,mips64le
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
JMP ·mulWW_g(SB)
|
||||
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
JMP ·divWW_g(SB)
|
||||
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
JMP ·addVV_g(SB)
|
||||
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
JMP ·subVV_g(SB)
|
||||
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
JMP ·addVW_g(SB)
|
||||
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
JMP ·subVW_g(SB)
|
||||
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
JMP ·shlVU_g(SB)
|
||||
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
JMP ·shrVU_g(SB)
|
||||
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
JMP ·mulAddVWW_g(SB)
|
||||
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
JMP ·addMulVVW_g(SB)
|
||||
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
JMP ·divWVW_g(SB)
|
|
@ -1,43 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !math_big_pure_go,mips !math_big_pure_go,mipsle
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
JMP ·mulWW_g(SB)
|
||||
|
||||
TEXT ·divWW(SB),NOSPLIT,$0
|
||||
JMP ·divWW_g(SB)
|
||||
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
JMP ·addVV_g(SB)
|
||||
|
||||
TEXT ·subVV(SB),NOSPLIT,$0
|
||||
JMP ·subVV_g(SB)
|
||||
|
||||
TEXT ·addVW(SB),NOSPLIT,$0
|
||||
JMP ·addVW_g(SB)
|
||||
|
||||
TEXT ·subVW(SB),NOSPLIT,$0
|
||||
JMP ·subVW_g(SB)
|
||||
|
||||
TEXT ·shlVU(SB),NOSPLIT,$0
|
||||
JMP ·shlVU_g(SB)
|
||||
|
||||
TEXT ·shrVU(SB),NOSPLIT,$0
|
||||
JMP ·shrVU_g(SB)
|
||||
|
||||
TEXT ·mulAddVWW(SB),NOSPLIT,$0
|
||||
JMP ·mulAddVWW_g(SB)
|
||||
|
||||
TEXT ·addMulVVW(SB),NOSPLIT,$0
|
||||
JMP ·addMulVVW_g(SB)
|
||||
|
||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||
JMP ·divWVW_g(SB)
|
|
@ -1,197 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// +build !math_big_pure_go,ppc64 !math_big_pure_go,ppc64le
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB), NOSPLIT, $0
|
||||
MOVD x+0(FP), R4
|
||||
MOVD y+8(FP), R5
|
||||
MULHDU R4, R5, R6
|
||||
MULLD R4, R5, R7
|
||||
MOVD R6, z1+16(FP)
|
||||
MOVD R7, z0+24(FP)
|
||||
RET
|
||||
|
||||
// func addVV(z, y, y []Word) (c Word)
|
||||
// z[i] = x[i] + y[i] for all i, carrying
|
||||
TEXT ·addVV(SB), NOSPLIT, $0
|
||||
MOVD z_len+8(FP), R7
|
||||
MOVD x+24(FP), R8
|
||||
MOVD y+48(FP), R9
|
||||
MOVD z+0(FP), R10
|
||||
|
||||
MOVD R0, R4
|
||||
MOVD R0, R6 // R6 will be the address index
|
||||
ADDC R4, R4 // clear CA
|
||||
MOVD R7, CTR
|
||||
|
||||
CMP R0, R7
|
||||
BEQ done
|
||||
|
||||
loop:
|
||||
MOVD (R8)(R6), R11 // x[i]
|
||||
MOVD (R9)(R6), R12 // y[i]
|
||||
ADDE R12, R11, R15 // x[i] + y[i] + CA
|
||||
MOVD R15, (R10)(R6) // z[i]
|
||||
|
||||
ADD $8, R6
|
||||
BC 16, 0, loop // bdnz
|
||||
|
||||
done:
|
||||
ADDZE R4
|
||||
MOVD R4, c+72(FP)
|
||||
RET
|
||||
|
||||
// func subVV(z, x, y []Word) (c Word)
|
||||
// z[i] = x[i] - y[i] for all i, carrying
|
||||
TEXT ·subVV(SB), NOSPLIT, $0
|
||||
MOVD z_len+8(FP), R7
|
||||
MOVD x+24(FP), R8
|
||||
MOVD y+48(FP), R9
|
||||
MOVD z+0(FP), R10
|
||||
|
||||
MOVD R0, R4 // c = 0
|
||||
MOVD R0, R6
|
||||
SUBC R0, R0 // clear CA
|
||||
MOVD R7, CTR
|
||||
|
||||
CMP R0, R7
|
||||
BEQ sublend
|
||||
|
||||
// amd64 saves and restores CF, but I believe they only have to do that because all of
|
||||
// their math operations clobber it - we should just be able to recover it at the end.
|
||||
subloop:
|
||||
MOVD (R8)(R6), R11 // x[i]
|
||||
MOVD (R9)(R6), R12 // y[i]
|
||||
|
||||
SUBE R12, R11, R15
|
||||
MOVD R15, (R10)(R6)
|
||||
|
||||
ADD $8, R6
|
||||
BC 16, 0, subloop // bdnz
|
||||
|
||||
sublend:
|
||||
|
||||
ADDZE R4
|
||||
XOR $1, R4
|
||||
MOVD R4, c+72(FP)
|
||||
RET
|
||||
|
||||
TEXT ·addVW(SB), NOSPLIT, $0
|
||||
BR ·addVW_g(SB)
|
||||
|
||||
TEXT ·subVW(SB), NOSPLIT, $0
|
||||
BR ·subVW_g(SB)
|
||||
|
||||
TEXT ·shlVU(SB), NOSPLIT, $0
|
||||
BR ·shlVU_g(SB)
|
||||
|
||||
TEXT ·shrVU(SB), NOSPLIT, $0
|
||||
BR ·shrVU_g(SB)
|
||||
|
||||
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||
TEXT ·mulAddVWW(SB), NOSPLIT, $0
|
||||
MOVD z+0(FP), R10 // R10 = z[]
|
||||
MOVD x+24(FP), R8 // R8 = x[]
|
||||
MOVD y+48(FP), R9 // R9 = y
|
||||
MOVD r+56(FP), R4 // R4 = r = c
|
||||
MOVD z_len+8(FP), R11 // R11 = z_len
|
||||
|
||||
MOVD R0, R3 // R3 will be the index register
|
||||
CMP R0, R11
|
||||
MOVD R11, CTR // Initialize loop counter
|
||||
BEQ done
|
||||
|
||||
loop:
|
||||
MOVD (R8)(R3), R20 // x[i]
|
||||
MULLD R9, R20, R6 // R6 = z0 = Low-order(x[i]*y)
|
||||
MULHDU R9, R20, R7 // R7 = z1 = High-order(x[i]*y)
|
||||
ADDC R4, R6 // Compute sum for z1 and z0
|
||||
ADDZE R7
|
||||
MOVD R6, (R10)(R3) // z[i]
|
||||
MOVD R7, R4 // c
|
||||
ADD $8, R3
|
||||
BC 16, 0, loop // bdnz
|
||||
|
||||
done:
|
||||
MOVD R4, c+64(FP)
|
||||
RET
|
||||
|
||||
// func addMulVVW(z, x []Word, y Word) (c Word)
|
||||
TEXT ·addMulVVW(SB), NOSPLIT, $0
|
||||
MOVD z+0(FP), R10 // R10 = z[]
|
||||
MOVD x+24(FP), R8 // R8 = x[]
|
||||
MOVD y+48(FP), R9 // R9 = y
|
||||
MOVD z_len+8(FP), R22 // R22 = z_len
|
||||
|
||||
MOVD R0, R3 // R3 will be the index register
|
||||
CMP R0, R22
|
||||
MOVD R0, R4 // R4 = c = 0
|
||||
MOVD R22, CTR // Initialize loop counter
|
||||
BEQ done
|
||||
|
||||
loop:
|
||||
MOVD (R8)(R3), R20 // Load x[i]
|
||||
MOVD (R10)(R3), R21 // Load z[i]
|
||||
MULLD R9, R20, R6 // R6 = Low-order(x[i]*y)
|
||||
MULHDU R9, R20, R7 // R7 = High-order(x[i]*y)
|
||||
ADDC R21, R6 // R6 = z0
|
||||
ADDZE R7 // R7 = z1
|
||||
ADDC R4, R6 // R6 = z0 + c + 0
|
||||
ADDZE R7, R4 // c += z1
|
||||
MOVD R6, (R10)(R3) // Store z[i]
|
||||
ADD $8, R3
|
||||
BC 16, 0, loop // bdnz
|
||||
|
||||
done:
|
||||
MOVD R4, c+56(FP)
|
||||
RET
|
||||
|
||||
// func divWW(x1, x0, y Word) (q, r Word)
|
||||
TEXT ·divWW(SB), NOSPLIT, $0
|
||||
MOVD x1+0(FP), R4
|
||||
MOVD x0+8(FP), R5
|
||||
MOVD y+16(FP), R6
|
||||
|
||||
CMPU R4, R6
|
||||
BGE divbigger
|
||||
|
||||
// from the programmer's note in ch. 3 of the ISA manual, p.74
|
||||
DIVDEU R6, R4, R3
|
||||
DIVDU R6, R5, R7
|
||||
MULLD R6, R3, R8
|
||||
MULLD R6, R7, R20
|
||||
SUB R20, R5, R10
|
||||
ADD R7, R3, R3
|
||||
SUB R8, R10, R4
|
||||
CMPU R4, R10
|
||||
BLT adjust
|
||||
CMPU R4, R6
|
||||
BLT end
|
||||
|
||||
adjust:
|
||||
MOVD $1, R21
|
||||
ADD R21, R3, R3
|
||||
SUB R6, R4, R4
|
||||
|
||||
end:
|
||||
MOVD R3, q+24(FP)
|
||||
MOVD R4, r+32(FP)
|
||||
|
||||
RET
|
||||
|
||||
divbigger:
|
||||
MOVD $-1, R7
|
||||
MOVD R7, q+24(FP)
|
||||
MOVD R7, r+32(FP)
|
||||
RET
|
||||
|
||||
TEXT ·divWVW(SB), NOSPLIT, $0
|
||||
BR ·divWVW_g(SB)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,267 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements multi-precision decimal numbers.
|
||||
// The implementation is for float to decimal conversion only;
|
||||
// not general purpose use.
|
||||
// The only operations are precise conversion from binary to
|
||||
// decimal and rounding.
|
||||
//
|
||||
// The key observation and some code (shr) is borrowed from
|
||||
// strconv/decimal.go: conversion of binary fractional values can be done
|
||||
// precisely in multi-precision decimal because 2 divides 10 (required for
|
||||
// >> of mantissa); but conversion of decimal floating-point values cannot
|
||||
// be done precisely in binary representation.
|
||||
//
|
||||
// In contrast to strconv/decimal.go, only right shift is implemented in
|
||||
// decimal format - left shift can be done precisely in binary format.
|
||||
|
||||
package big
|
||||
|
||||
// A decimal represents an unsigned floating-point number in decimal representation.
|
||||
// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.1 <= d.mant < 1,
|
||||
// with the most-significant mantissa digit at index 0. For the zero decimal, the
|
||||
// mantissa length and exponent are 0.
|
||||
// The zero value for decimal represents a ready-to-use 0.0.
|
||||
type decimal struct {
|
||||
mant []byte // mantissa ASCII digits, big-endian
|
||||
exp int // exponent
|
||||
}
|
||||
|
||||
// at returns the i'th mantissa digit, starting with the most significant digit at 0.
|
||||
func (d *decimal) at(i int) byte {
|
||||
if 0 <= i && i < len(d.mant) {
|
||||
return d.mant[i]
|
||||
}
|
||||
return '0'
|
||||
}
|
||||
|
||||
// Maximum shift amount that can be done in one pass without overflow.
|
||||
// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
|
||||
const maxShift = _W - 4
|
||||
|
||||
// TODO(gri) Since we know the desired decimal precision when converting
|
||||
// a floating-point number, we may be able to limit the number of decimal
|
||||
// digits that need to be computed by init by providing an additional
|
||||
// precision argument and keeping track of when a number was truncated early
|
||||
// (equivalent of "sticky bit" in binary rounding).
|
||||
|
||||
// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
|
||||
// to avoid "infinitely" long running conversions (until we run out of space).
|
||||
|
||||
// Init initializes x to the decimal representation of m << shift (for
|
||||
// shift >= 0), or m >> -shift (for shift < 0).
|
||||
func (x *decimal) init(m nat, shift int) {
|
||||
// special case 0
|
||||
if len(m) == 0 {
|
||||
x.mant = x.mant[:0]
|
||||
x.exp = 0
|
||||
return
|
||||
}
|
||||
|
||||
// Optimization: If we need to shift right, first remove any trailing
|
||||
// zero bits from m to reduce shift amount that needs to be done in
|
||||
// decimal format (since that is likely slower).
|
||||
if shift < 0 {
|
||||
ntz := m.trailingZeroBits()
|
||||
s := uint(-shift)
|
||||
if s >= ntz {
|
||||
s = ntz // shift at most ntz bits
|
||||
}
|
||||
m = nat(nil).shr(m, s)
|
||||
shift += int(s)
|
||||
}
|
||||
|
||||
// Do any shift left in binary representation.
|
||||
if shift > 0 {
|
||||
m = nat(nil).shl(m, uint(shift))
|
||||
shift = 0
|
||||
}
|
||||
|
||||
// Convert mantissa into decimal representation.
|
||||
s := m.utoa(10)
|
||||
n := len(s)
|
||||
x.exp = n
|
||||
// Trim trailing zeros; instead the exponent is tracking
|
||||
// the decimal point independent of the number of digits.
|
||||
for n > 0 && s[n-1] == '0' {
|
||||
n--
|
||||
}
|
||||
x.mant = append(x.mant[:0], s[:n]...)
|
||||
|
||||
// Do any (remaining) shift right in decimal representation.
|
||||
if shift < 0 {
|
||||
for shift < -maxShift {
|
||||
shr(x, maxShift)
|
||||
shift += maxShift
|
||||
}
|
||||
shr(x, uint(-shift))
|
||||
}
|
||||
}
|
||||
|
||||
// shr implements x >> s, for s <= maxShift.
|
||||
func shr(x *decimal, s uint) {
|
||||
// Division by 1<<s using shift-and-subtract algorithm.
|
||||
|
||||
// pick up enough leading digits to cover first shift
|
||||
r := 0 // read index
|
||||
var n Word
|
||||
for n>>s == 0 && r < len(x.mant) {
|
||||
ch := Word(x.mant[r])
|
||||
r++
|
||||
n = n*10 + ch - '0'
|
||||
}
|
||||
if n == 0 {
|
||||
// x == 0; shouldn't get here, but handle anyway
|
||||
x.mant = x.mant[:0]
|
||||
return
|
||||
}
|
||||
for n>>s == 0 {
|
||||
r++
|
||||
n *= 10
|
||||
}
|
||||
x.exp += 1 - r
|
||||
|
||||
// read a digit, write a digit
|
||||
w := 0 // write index
|
||||
mask := Word(1)<<s - 1
|
||||
for r < len(x.mant) {
|
||||
ch := Word(x.mant[r])
|
||||
r++
|
||||
d := n >> s
|
||||
n &= mask // n -= d << s
|
||||
x.mant[w] = byte(d + '0')
|
||||
w++
|
||||
n = n*10 + ch - '0'
|
||||
}
|
||||
|
||||
// write extra digits that still fit
|
||||
for n > 0 && w < len(x.mant) {
|
||||
d := n >> s
|
||||
n &= mask
|
||||
x.mant[w] = byte(d + '0')
|
||||
w++
|
||||
n = n * 10
|
||||
}
|
||||
x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
|
||||
|
||||
// append additional digits that didn't fit
|
||||
for n > 0 {
|
||||
d := n >> s
|
||||
n &= mask
|
||||
x.mant = append(x.mant, byte(d+'0'))
|
||||
n = n * 10
|
||||
}
|
||||
|
||||
trim(x)
|
||||
}
|
||||
|
||||
func (x *decimal) String() string {
|
||||
if len(x.mant) == 0 {
|
||||
return "0"
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
switch {
|
||||
case x.exp <= 0:
|
||||
// 0.00ddd
|
||||
buf = append(buf, "0."...)
|
||||
buf = appendZeros(buf, -x.exp)
|
||||
buf = append(buf, x.mant...)
|
||||
|
||||
case /* 0 < */ x.exp < len(x.mant):
|
||||
// dd.ddd
|
||||
buf = append(buf, x.mant[:x.exp]...)
|
||||
buf = append(buf, '.')
|
||||
buf = append(buf, x.mant[x.exp:]...)
|
||||
|
||||
default: // len(x.mant) <= x.exp
|
||||
// ddd00
|
||||
buf = append(buf, x.mant...)
|
||||
buf = appendZeros(buf, x.exp-len(x.mant))
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// appendZeros appends n 0 digits to buf and returns buf.
|
||||
func appendZeros(buf []byte, n int) []byte {
|
||||
for ; n > 0; n-- {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// shouldRoundUp reports if x should be rounded up
|
||||
// if shortened to n digits. n must be a valid index
|
||||
// for x.mant.
|
||||
func shouldRoundUp(x *decimal, n int) bool {
|
||||
if x.mant[n] == '5' && n+1 == len(x.mant) {
|
||||
// exactly halfway - round to even
|
||||
return n > 0 && (x.mant[n-1]-'0')&1 != 0
|
||||
}
|
||||
// not halfway - digit tells all (x.mant has no trailing zeros)
|
||||
return x.mant[n] >= '5'
|
||||
}
|
||||
|
||||
// round sets x to (at most) n mantissa digits by rounding it
|
||||
// to the nearest even value with n (or fever) mantissa digits.
|
||||
// If n < 0, x remains unchanged.
|
||||
func (x *decimal) round(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
|
||||
if shouldRoundUp(x, n) {
|
||||
x.roundUp(n)
|
||||
} else {
|
||||
x.roundDown(n)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *decimal) roundUp(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
// 0 <= n < len(x.mant)
|
||||
|
||||
// find first digit < '9'
|
||||
for n > 0 && x.mant[n-1] >= '9' {
|
||||
n--
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
// all digits are '9's => round up to '1' and update exponent
|
||||
x.mant[0] = '1' // ok since len(x.mant) > n
|
||||
x.mant = x.mant[:1]
|
||||
x.exp++
|
||||
return
|
||||
}
|
||||
|
||||
// n > 0 && x.mant[n-1] < '9'
|
||||
x.mant[n-1]++
|
||||
x.mant = x.mant[:n]
|
||||
// x already trimmed
|
||||
}
|
||||
|
||||
func (x *decimal) roundDown(n int) {
|
||||
if n < 0 || n >= len(x.mant) {
|
||||
return // nothing to do
|
||||
}
|
||||
x.mant = x.mant[:n]
|
||||
trim(x)
|
||||
}
|
||||
|
||||
// trim cuts off any trailing zeros from x's mantissa;
|
||||
// they are meaningless for the value of x.
|
||||
func trim(x *decimal) {
|
||||
i := len(x.mant)
|
||||
for i > 0 && x.mant[i-1] == '0' {
|
||||
i--
|
||||
}
|
||||
x.mant = x.mant[:i]
|
||||
if i == 0 {
|
||||
x.exp = 0
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
// 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.
|
||||
|
||||
/*
|
||||
Package big implements arbitrary-precision arithmetic (big numbers).
|
||||
The following numeric types are supported:
|
||||
|
||||
Int signed integers
|
||||
Rat rational numbers
|
||||
Float floating-point numbers
|
||||
|
||||
The zero value for an Int, Rat, or Float correspond to 0. Thus, new
|
||||
values can be declared in the usual ways and denote 0 without further
|
||||
initialization:
|
||||
|
||||
var x Int // &x is an *Int of value 0
|
||||
var r = &Rat{} // r is a *Rat of value 0
|
||||
y := new(Float) // y is a *Float of value 0
|
||||
|
||||
Alternatively, new values can be allocated and initialized with factory
|
||||
functions of the form:
|
||||
|
||||
func NewT(v V) *T
|
||||
|
||||
For instance, NewInt(x) returns an *Int set to the value of the int64
|
||||
argument x, NewRat(a, b) returns a *Rat set to the fraction a/b where
|
||||
a and b are int64 values, and NewFloat(f) returns a *Float initialized
|
||||
to the float64 argument f. More flexibility is provided with explicit
|
||||
setters, for instance:
|
||||
|
||||
var z1 Int
|
||||
z1.SetUint64(123) // z1 := 123
|
||||
z2 := new(Rat).SetFloat64(1.25) // z2 := 5/4
|
||||
z3 := new(Float).SetInt(z1) // z3 := 123.0
|
||||
|
||||
Setters, numeric operations and predicates are represented as methods of
|
||||
the form:
|
||||
|
||||
func (z *T) SetV(v V) *T // z = v
|
||||
func (z *T) Unary(x *T) *T // z = unary x
|
||||
func (z *T) Binary(x, y *T) *T // z = x binary y
|
||||
func (x *T) Pred() P // p = pred(x)
|
||||
|
||||
with T one of Int, Rat, or Float. For unary and binary operations, the
|
||||
result is the receiver (usually named z in that case; see below); if it
|
||||
is one of the operands x or y it may be safely overwritten (and its memory
|
||||
reused).
|
||||
|
||||
Arithmetic expressions are typically written as a sequence of individual
|
||||
method calls, with each call corresponding to an operation. The receiver
|
||||
denotes the result and the method arguments are the operation's operands.
|
||||
For instance, given three *Int values a, b and c, the invocation
|
||||
|
||||
c.Add(a, b)
|
||||
|
||||
computes the sum a + b and stores the result in c, overwriting whatever
|
||||
value was held in c before. Unless specified otherwise, operations permit
|
||||
aliasing of parameters, so it is perfectly ok to write
|
||||
|
||||
sum.Add(sum, x)
|
||||
|
||||
to accumulate values x in a sum.
|
||||
|
||||
(By always passing in a result value via the receiver, memory use can be
|
||||
much better controlled. Instead of having to allocate new memory for each
|
||||
result, an operation can reuse the space allocated for the result value,
|
||||
and overwrite that value with the new result in the process.)
|
||||
|
||||
Notational convention: Incoming method parameters (including the receiver)
|
||||
are named consistently in the API to clarify their use. Incoming operands
|
||||
are usually named x, y, a, b, and so on, but never z. A parameter specifying
|
||||
the result is named z (typically the receiver).
|
||||
|
||||
For instance, the arguments for (*Int).Add are named x and y, and because
|
||||
the receiver specifies the result destination, it is called z:
|
||||
|
||||
func (z *Int) Add(x, y *Int) *Int
|
||||
|
||||
Methods of this form typically return the incoming receiver as well, to
|
||||
enable simple call chaining.
|
||||
|
||||
Methods which don't require a result value to be passed in (for instance,
|
||||
Int.Sign), simply return the result. In this case, the receiver is typically
|
||||
the first operand, named x:
|
||||
|
||||
func (x *Int) Sign() int
|
||||
|
||||
Various methods support conversions between strings and corresponding
|
||||
numeric values, and vice versa: *Int, *Rat, and *Float values implement
|
||||
the Stringer interface for a (default) string representation of the value,
|
||||
but also provide SetString methods to initialize a value from a string in
|
||||
a variety of supported formats (see the respective SetString documentation).
|
||||
|
||||
Finally, *Int, *Rat, and *Float satisfy the fmt package's Scanner interface
|
||||
for scanning and (except for *Rat) the Formatter interface for formatted
|
||||
printing.
|
||||
*/
|
||||
package big
|
File diff suppressed because it is too large
Load Diff
|
@ -1,293 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements string-to-Float conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var floatZero Float
|
||||
|
||||
// SetString sets z to the value of s and returns z and a boolean indicating
|
||||
// success. s must be a floating-point number of the same format as accepted
|
||||
// by Parse, with base argument 0. The entire string (not just a prefix) must
|
||||
// be valid for success. If the operation failed, the value of z is undefined
|
||||
// but the returned value is nil.
|
||||
func (z *Float) SetString(s string) (*Float, bool) {
|
||||
if f, _, err := z.Parse(s, 0); err == nil {
|
||||
return f, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// scan is like Parse but reads the longest possible prefix representing a valid
|
||||
// floating point number from an io.ByteScanner rather than a string. It serves
|
||||
// as the implementation of Parse. It does not recognize ±Inf and does not expect
|
||||
// EOF at the end.
|
||||
func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
|
||||
prec := z.prec
|
||||
if prec == 0 {
|
||||
prec = 64
|
||||
}
|
||||
|
||||
// A reasonable value in case of an error.
|
||||
z.form = zero
|
||||
|
||||
// sign
|
||||
z.neg, err = scanSign(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// mantissa
|
||||
var fcount int // fractional digit count; valid if <= 0
|
||||
z.mant, b, fcount, err = z.mant.scan(r, base, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// exponent
|
||||
var exp int64
|
||||
var ebase int
|
||||
exp, ebase, err = scanExponent(r, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// special-case 0
|
||||
if len(z.mant) == 0 {
|
||||
z.prec = prec
|
||||
z.acc = Exact
|
||||
z.form = zero
|
||||
f = z
|
||||
return
|
||||
}
|
||||
// len(z.mant) > 0
|
||||
|
||||
// The mantissa may have a decimal point (fcount <= 0) and there
|
||||
// may be a nonzero exponent exp. The decimal point amounts to a
|
||||
// division by b**(-fcount). An exponent means multiplication by
|
||||
// ebase**exp. Finally, mantissa normalization (shift left) requires
|
||||
// a correcting multiplication by 2**(-shiftcount). Multiplications
|
||||
// are commutative, so we can apply them in any order as long as there
|
||||
// is no loss of precision. We only have powers of 2 and 10, and
|
||||
// we split powers of 10 into the product of the same powers of
|
||||
// 2 and 5. This reduces the size of the multiplication factor
|
||||
// needed for base-10 exponents.
|
||||
|
||||
// normalize mantissa and determine initial exponent contributions
|
||||
exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
|
||||
exp5 := int64(0)
|
||||
|
||||
// determine binary or decimal exponent contribution of decimal point
|
||||
if fcount < 0 {
|
||||
// The mantissa has a "decimal" point ddd.dddd; and
|
||||
// -fcount is the number of digits to the right of '.'.
|
||||
// Adjust relevant exponent accordingly.
|
||||
d := int64(fcount)
|
||||
switch b {
|
||||
case 10:
|
||||
exp5 = d
|
||||
fallthrough // 10**e == 5**e * 2**e
|
||||
case 2:
|
||||
exp2 += d
|
||||
case 16:
|
||||
exp2 += d * 4 // hexadecimal digits are 4 bits each
|
||||
default:
|
||||
panic("unexpected mantissa base")
|
||||
}
|
||||
// fcount consumed - not needed anymore
|
||||
}
|
||||
|
||||
// take actual exponent into account
|
||||
switch ebase {
|
||||
case 10:
|
||||
exp5 += exp
|
||||
fallthrough
|
||||
case 2:
|
||||
exp2 += exp
|
||||
default:
|
||||
panic("unexpected exponent base")
|
||||
}
|
||||
// exp consumed - not needed anymore
|
||||
|
||||
// apply 2**exp2
|
||||
if MinExp <= exp2 && exp2 <= MaxExp {
|
||||
z.prec = prec
|
||||
z.form = finite
|
||||
z.exp = int32(exp2)
|
||||
f = z
|
||||
} else {
|
||||
err = fmt.Errorf("exponent overflow")
|
||||
return
|
||||
}
|
||||
|
||||
if exp5 == 0 {
|
||||
// no decimal exponent contribution
|
||||
z.round(0)
|
||||
return
|
||||
}
|
||||
// exp5 != 0
|
||||
|
||||
// apply 5**exp5
|
||||
p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
|
||||
if exp5 < 0 {
|
||||
z.Quo(z, p.pow5(uint64(-exp5)))
|
||||
} else {
|
||||
z.Mul(z, p.pow5(uint64(exp5)))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// These powers of 5 fit into a uint64.
|
||||
//
|
||||
// for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
|
||||
// fmt.Println(q)
|
||||
// }
|
||||
//
|
||||
var pow5tab = [...]uint64{
|
||||
1,
|
||||
5,
|
||||
25,
|
||||
125,
|
||||
625,
|
||||
3125,
|
||||
15625,
|
||||
78125,
|
||||
390625,
|
||||
1953125,
|
||||
9765625,
|
||||
48828125,
|
||||
244140625,
|
||||
1220703125,
|
||||
6103515625,
|
||||
30517578125,
|
||||
152587890625,
|
||||
762939453125,
|
||||
3814697265625,
|
||||
19073486328125,
|
||||
95367431640625,
|
||||
476837158203125,
|
||||
2384185791015625,
|
||||
11920928955078125,
|
||||
59604644775390625,
|
||||
298023223876953125,
|
||||
1490116119384765625,
|
||||
7450580596923828125,
|
||||
}
|
||||
|
||||
// pow5 sets z to 5**n and returns z.
|
||||
// n must not be negative.
|
||||
func (z *Float) pow5(n uint64) *Float {
|
||||
const m = uint64(len(pow5tab) - 1)
|
||||
if n <= m {
|
||||
return z.SetUint64(pow5tab[n])
|
||||
}
|
||||
// n > m
|
||||
|
||||
z.SetUint64(pow5tab[m])
|
||||
n -= m
|
||||
|
||||
// use more bits for f than for z
|
||||
// TODO(gri) what is the right number?
|
||||
f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
|
||||
|
||||
for n > 0 {
|
||||
if n&1 != 0 {
|
||||
z.Mul(z, f)
|
||||
}
|
||||
f.Mul(f, f)
|
||||
n >>= 1
|
||||
}
|
||||
|
||||
return z
|
||||
}
|
||||
|
||||
// Parse parses s which must contain a text representation of a floating-
|
||||
// point number with a mantissa in the given conversion base (the exponent
|
||||
// is always a decimal number), or a string representing an infinite value.
|
||||
//
|
||||
// It sets z to the (possibly rounded) value of the corresponding floating-
|
||||
// point value, and returns z, the actual base b, and an error err, if any.
|
||||
// The entire string (not just a prefix) must be consumed for success.
|
||||
// If z's precision is 0, it is changed to 64 before rounding takes effect.
|
||||
// The number must be of the form:
|
||||
//
|
||||
// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
|
||||
// sign = "+" | "-" .
|
||||
// prefix = "0" ( "x" | "X" | "b" | "B" ) .
|
||||
// mantissa = digits | digits "." [ digits ] | "." digits .
|
||||
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
|
||||
// infinity = [ sign ] ( "inf" | "Inf" ) .
|
||||
//
|
||||
// The base argument must be 0, 2, 10, or 16. Providing an invalid base
|
||||
// argument will lead to a run-time panic.
|
||||
//
|
||||
// For base 0, the number prefix determines the actual base: A prefix of
|
||||
// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
|
||||
// base 2; otherwise, the actual base is 10 and no prefix is accepted.
|
||||
// The octal prefix "0" is not supported (a leading "0" is simply
|
||||
// considered a "0").
|
||||
//
|
||||
// A "p" exponent indicates a binary (rather then decimal) exponent;
|
||||
// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
|
||||
// maximum float64 value. For hexadecimal mantissae, the exponent must
|
||||
// be binary, if present (an "e" or "E" exponent indicator cannot be
|
||||
// distinguished from a mantissa digit).
|
||||
//
|
||||
// The returned *Float f is nil and the value of z is valid but not
|
||||
// defined if an error is reported.
|
||||
//
|
||||
func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
|
||||
// scan doesn't handle ±Inf
|
||||
if len(s) == 3 && (s == "Inf" || s == "inf") {
|
||||
f = z.SetInf(false)
|
||||
return
|
||||
}
|
||||
if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") {
|
||||
f = z.SetInf(s[0] == '-')
|
||||
return
|
||||
}
|
||||
|
||||
r := strings.NewReader(s)
|
||||
if f, b, err = z.scan(r, base); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// entire string must have been consumed
|
||||
if ch, err2 := r.ReadByte(); err2 == nil {
|
||||
err = fmt.Errorf("expected end of string, found %q", ch)
|
||||
} else if err2 != io.EOF {
|
||||
err = err2
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ParseFloat is like f.Parse(s, base) with f set to the given precision
|
||||
// and rounding mode.
|
||||
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
|
||||
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
|
||||
}
|
||||
|
||||
var _ fmt.Scanner = &floatZero // *Float must implement fmt.Scanner
|
||||
|
||||
// Scan is a support routine for fmt.Scanner; it sets z to the value of
|
||||
// the scanned number. It accepts formats whose verbs are supported by
|
||||
// fmt.Scan for floating point values, which are:
|
||||
// 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
|
||||
// Scan doesn't handle ±Inf.
|
||||
func (z *Float) Scan(s fmt.ScanState, ch rune) error {
|
||||
s.SkipSpace()
|
||||
_, _, err := z.scan(byteReader{s}, 0)
|
||||
return err
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements encoding/decoding of Floats.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const floatGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
// The Float value and all its attributes (precision,
|
||||
// rounding mode, accuracy) are marshaled.
|
||||
func (x *Float) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// determine max. space (bytes) required for encoding
|
||||
sz := 1 + 1 + 4 // version + mode|acc|form|neg (3+2+2+1bit) + prec
|
||||
n := 0 // number of mantissa words
|
||||
if x.form == finite {
|
||||
// add space for mantissa and exponent
|
||||
n = int((x.prec + (_W - 1)) / _W) // required mantissa length in words for given precision
|
||||
// actual mantissa slice could be shorter (trailing 0's) or longer (unused bits):
|
||||
// - if shorter, only encode the words present
|
||||
// - if longer, cut off unused words when encoding in bytes
|
||||
// (in practice, this should never happen since rounding
|
||||
// takes care of it, but be safe and do it always)
|
||||
if len(x.mant) < n {
|
||||
n = len(x.mant)
|
||||
}
|
||||
// len(x.mant) >= n
|
||||
sz += 4 + n*_S // exp + mant
|
||||
}
|
||||
buf := make([]byte, sz)
|
||||
|
||||
buf[0] = floatGobVersion
|
||||
b := byte(x.mode&7)<<5 | byte((x.acc+1)&3)<<3 | byte(x.form&3)<<1
|
||||
if x.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[1] = b
|
||||
binary.BigEndian.PutUint32(buf[2:], x.prec)
|
||||
|
||||
if x.form == finite {
|
||||
binary.BigEndian.PutUint32(buf[6:], uint32(x.exp))
|
||||
x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
// The result is rounded per the precision and rounding mode of
|
||||
// z unless z's precision is 0, in which case z is set exactly
|
||||
// to the decoded value.
|
||||
func (z *Float) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Float{}
|
||||
return nil
|
||||
}
|
||||
|
||||
if buf[0] != floatGobVersion {
|
||||
return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0])
|
||||
}
|
||||
|
||||
oldPrec := z.prec
|
||||
oldMode := z.mode
|
||||
|
||||
b := buf[1]
|
||||
z.mode = RoundingMode((b >> 5) & 7)
|
||||
z.acc = Accuracy((b>>3)&3) - 1
|
||||
z.form = form((b >> 1) & 3)
|
||||
z.neg = b&1 != 0
|
||||
z.prec = binary.BigEndian.Uint32(buf[2:])
|
||||
|
||||
if z.form == finite {
|
||||
z.exp = int32(binary.BigEndian.Uint32(buf[6:]))
|
||||
z.mant = z.mant.setBytes(buf[10:])
|
||||
}
|
||||
|
||||
if oldPrec != 0 {
|
||||
z.mode = oldMode
|
||||
z.SetPrec(uint(oldPrec))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// Only the Float value is marshaled (in full precision), other
|
||||
// attributes such as precision or accuracy are ignored.
|
||||
func (x *Float) MarshalText() (text []byte, err error) {
|
||||
if x == nil {
|
||||
return []byte("<nil>"), nil
|
||||
}
|
||||
var buf []byte
|
||||
return x.Append(buf, 'g', -1), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The result is rounded per the precision and rounding mode of z.
|
||||
// If z's precision is 0, it is changed to 64 before rounding takes
|
||||
// effect.
|
||||
func (z *Float) UnmarshalText(text []byte) error {
|
||||
// TODO(gri): get rid of the []byte/string conversion
|
||||
_, _, err := z.Parse(string(text), 0)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -1,461 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements Float-to-string conversion functions.
|
||||
// It is closely following the corresponding implementation
|
||||
// in strconv/ftoa.go, but modified and simplified for Float.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Text converts the floating-point number x to a string according
|
||||
// to the given format and precision prec. The format is one of:
|
||||
//
|
||||
// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
|
||||
// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
|
||||
// 'f' -ddddd.dddd, no exponent
|
||||
// 'g' like 'e' for large exponents, like 'f' otherwise
|
||||
// 'G' like 'E' for large exponents, like 'f' otherwise
|
||||
// 'b' -ddddddp±dd, binary exponent
|
||||
// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa
|
||||
//
|
||||
// For the binary exponent formats, the mantissa is printed in normalized form:
|
||||
//
|
||||
// 'b' decimal integer mantissa using x.Prec() bits, or -0
|
||||
// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
|
||||
//
|
||||
// If format is a different character, Text returns a "%" followed by the
|
||||
// unrecognized format character.
|
||||
//
|
||||
// The precision prec controls the number of digits (excluding the exponent)
|
||||
// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
|
||||
// it is the number of digits after the decimal point. For 'g' and 'G' it is
|
||||
// the total number of digits. A negative precision selects the smallest
|
||||
// number of decimal digits necessary to identify the value x uniquely using
|
||||
// x.Prec() mantissa bits.
|
||||
// The prec value is ignored for the 'b' or 'p' format.
|
||||
func (x *Float) Text(format byte, prec int) string {
|
||||
cap := 10 // TODO(gri) determine a good/better value here
|
||||
if prec > 0 {
|
||||
cap += prec
|
||||
}
|
||||
return string(x.Append(make([]byte, 0, cap), format, prec))
|
||||
}
|
||||
|
||||
// String formats x like x.Text('g', 10).
|
||||
// (String must be called explicitly, Float.Format does not support %s verb.)
|
||||
func (x *Float) String() string {
|
||||
return x.Text('g', 10)
|
||||
}
|
||||
|
||||
// Append appends to buf the string form of the floating-point number x,
|
||||
// as generated by x.Text, and returns the extended buffer.
|
||||
func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
|
||||
// sign
|
||||
if x.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
|
||||
// Inf
|
||||
if x.form == inf {
|
||||
if !x.neg {
|
||||
buf = append(buf, '+')
|
||||
}
|
||||
return append(buf, "Inf"...)
|
||||
}
|
||||
|
||||
// pick off easy formats
|
||||
switch fmt {
|
||||
case 'b':
|
||||
return x.fmtB(buf)
|
||||
case 'p':
|
||||
return x.fmtP(buf)
|
||||
}
|
||||
|
||||
// Algorithm:
|
||||
// 1) convert Float to multiprecision decimal
|
||||
// 2) round to desired precision
|
||||
// 3) read digits out and format
|
||||
|
||||
// 1) convert Float to multiprecision decimal
|
||||
var d decimal // == 0.0
|
||||
if x.form == finite {
|
||||
// x != 0
|
||||
d.init(x.mant, int(x.exp)-x.mant.bitLen())
|
||||
}
|
||||
|
||||
// 2) round to desired precision
|
||||
shortest := false
|
||||
if prec < 0 {
|
||||
shortest = true
|
||||
roundShortest(&d, x)
|
||||
// Precision for shortest representation mode.
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
prec = len(d.mant) - 1
|
||||
case 'f':
|
||||
prec = max(len(d.mant)-d.exp, 0)
|
||||
case 'g', 'G':
|
||||
prec = len(d.mant)
|
||||
}
|
||||
} else {
|
||||
// round appropriately
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
// one digit before and number of digits after decimal point
|
||||
d.round(1 + prec)
|
||||
case 'f':
|
||||
// number of digits before and after decimal point
|
||||
d.round(d.exp + prec)
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1
|
||||
}
|
||||
d.round(prec)
|
||||
}
|
||||
}
|
||||
|
||||
// 3) read digits out and format
|
||||
switch fmt {
|
||||
case 'e', 'E':
|
||||
return fmtE(buf, fmt, prec, d)
|
||||
case 'f':
|
||||
return fmtF(buf, prec, d)
|
||||
case 'g', 'G':
|
||||
// trim trailing fractional zeros in %e format
|
||||
eprec := prec
|
||||
if eprec > len(d.mant) && len(d.mant) >= d.exp {
|
||||
eprec = len(d.mant)
|
||||
}
|
||||
// %e is used if the exponent from the conversion
|
||||
// is less than -4 or greater than or equal to the precision.
|
||||
// If precision was the shortest possible, use eprec = 6 for
|
||||
// this decision.
|
||||
if shortest {
|
||||
eprec = 6
|
||||
}
|
||||
exp := d.exp - 1
|
||||
if exp < -4 || exp >= eprec {
|
||||
if prec > len(d.mant) {
|
||||
prec = len(d.mant)
|
||||
}
|
||||
return fmtE(buf, fmt+'e'-'g', prec-1, d)
|
||||
}
|
||||
if prec > d.exp {
|
||||
prec = len(d.mant)
|
||||
}
|
||||
return fmtF(buf, max(prec-d.exp, 0), d)
|
||||
}
|
||||
|
||||
// unknown format
|
||||
if x.neg {
|
||||
buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
|
||||
}
|
||||
return append(buf, '%', fmt)
|
||||
}
|
||||
|
||||
func roundShortest(d *decimal, x *Float) {
|
||||
// if the mantissa is zero, the number is zero - stop now
|
||||
if len(d.mant) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
|
||||
// (possibly exclusive) round to x for the given precision of x.
|
||||
// Compute the lower and upper bound in decimal form and find the
|
||||
// shortest decimal number d such that lower <= d <= upper.
|
||||
|
||||
// TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
|
||||
// See if we can use it (in adjusted form) here as well.
|
||||
|
||||
// 1) Compute normalized mantissa mant and exponent exp for x such
|
||||
// that the lsb of mant corresponds to 1/2 ulp for the precision of
|
||||
// x (i.e., for mant we want x.prec + 1 bits).
|
||||
mant := nat(nil).set(x.mant)
|
||||
exp := int(x.exp) - mant.bitLen()
|
||||
s := mant.bitLen() - int(x.prec+1)
|
||||
switch {
|
||||
case s < 0:
|
||||
mant = mant.shl(mant, uint(-s))
|
||||
case s > 0:
|
||||
mant = mant.shr(mant, uint(+s))
|
||||
}
|
||||
exp += s
|
||||
// x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
|
||||
|
||||
// 2) Compute lower bound by subtracting 1/2 ulp.
|
||||
var lower decimal
|
||||
var tmp nat
|
||||
lower.init(tmp.sub(mant, natOne), exp)
|
||||
|
||||
// 3) Compute upper bound by adding 1/2 ulp.
|
||||
var upper decimal
|
||||
upper.init(tmp.add(mant, natOne), exp)
|
||||
|
||||
// The upper and lower bounds are possible outputs only if
|
||||
// the original mantissa is even, so that ToNearestEven rounding
|
||||
// would round to the original mantissa and not the neighbors.
|
||||
inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
|
||||
|
||||
// Now we can figure out the minimum number of digits required.
|
||||
// Walk along until d has distinguished itself from upper and lower.
|
||||
for i, m := range d.mant {
|
||||
l := lower.at(i)
|
||||
u := upper.at(i)
|
||||
|
||||
// Okay to round down (truncate) if lower has a different digit
|
||||
// or if lower is inclusive and is exactly the result of rounding
|
||||
// down (i.e., and we have reached the final digit of lower).
|
||||
okdown := l != m || inclusive && i+1 == len(lower.mant)
|
||||
|
||||
// Okay to round up if upper has a different digit and either upper
|
||||
// is inclusive or upper is bigger than the result of rounding up.
|
||||
okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
|
||||
|
||||
// If it's okay to do either, then round to the nearest one.
|
||||
// If it's okay to do only one, do it.
|
||||
switch {
|
||||
case okdown && okup:
|
||||
d.round(i + 1)
|
||||
return
|
||||
case okdown:
|
||||
d.roundDown(i + 1)
|
||||
return
|
||||
case okup:
|
||||
d.roundUp(i + 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// %e: d.ddddde±dd
|
||||
func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
|
||||
// first digit
|
||||
ch := byte('0')
|
||||
if len(d.mant) > 0 {
|
||||
ch = d.mant[0]
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
|
||||
// .moredigits
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
i := 1
|
||||
m := min(len(d.mant), prec+1)
|
||||
if i < m {
|
||||
buf = append(buf, d.mant[i:m]...)
|
||||
i = m
|
||||
}
|
||||
for ; i <= prec; i++ {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
}
|
||||
|
||||
// e±
|
||||
buf = append(buf, fmt)
|
||||
var exp int64
|
||||
if len(d.mant) > 0 {
|
||||
exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
|
||||
}
|
||||
if exp < 0 {
|
||||
ch = '-'
|
||||
exp = -exp
|
||||
} else {
|
||||
ch = '+'
|
||||
}
|
||||
buf = append(buf, ch)
|
||||
|
||||
// dd...d
|
||||
if exp < 10 {
|
||||
buf = append(buf, '0') // at least 2 exponent digits
|
||||
}
|
||||
return strconv.AppendInt(buf, exp, 10)
|
||||
}
|
||||
|
||||
// %f: ddddddd.ddddd
|
||||
func fmtF(buf []byte, prec int, d decimal) []byte {
|
||||
// integer, padded with zeros as needed
|
||||
if d.exp > 0 {
|
||||
m := min(len(d.mant), d.exp)
|
||||
buf = append(buf, d.mant[:m]...)
|
||||
for ; m < d.exp; m++ {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
} else {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
|
||||
// fraction
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
for i := 0; i < prec; i++ {
|
||||
buf = append(buf, d.at(d.exp+i))
|
||||
}
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// fmtB appends the string of x in the format mantissa "p" exponent
|
||||
// with a decimal mantissa and a binary exponent, or 0" if x is zero,
|
||||
// and returns the extended buffer.
|
||||
// The mantissa is normalized such that is uses x.Prec() bits in binary
|
||||
// representation.
|
||||
// The sign of x is ignored, and x must not be an Inf.
|
||||
func (x *Float) fmtB(buf []byte) []byte {
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// adjust mantissa to use exactly x.prec bits
|
||||
m := x.mant
|
||||
switch w := uint32(len(x.mant)) * _W; {
|
||||
case w < x.prec:
|
||||
m = nat(nil).shl(m, uint(x.prec-w))
|
||||
case w > x.prec:
|
||||
m = nat(nil).shr(m, uint(w-x.prec))
|
||||
}
|
||||
|
||||
buf = append(buf, m.utoa(10)...)
|
||||
buf = append(buf, 'p')
|
||||
e := int64(x.exp) - int64(x.prec)
|
||||
if e >= 0 {
|
||||
buf = append(buf, '+')
|
||||
}
|
||||
return strconv.AppendInt(buf, e, 10)
|
||||
}
|
||||
|
||||
// fmtP appends the string of x in the format "0x." mantissa "p" exponent
|
||||
// with a hexadecimal mantissa and a binary exponent, or "0" if x is zero,
|
||||
// and returns the extended buffer.
|
||||
// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
|
||||
// The sign of x is ignored, and x must not be an Inf.
|
||||
func (x *Float) fmtP(buf []byte) []byte {
|
||||
if x.form == zero {
|
||||
return append(buf, '0')
|
||||
}
|
||||
|
||||
if debugFloat && x.form != finite {
|
||||
panic("non-finite float")
|
||||
}
|
||||
// x != 0
|
||||
|
||||
// remove trailing 0 words early
|
||||
// (no need to convert to hex 0's and trim later)
|
||||
m := x.mant
|
||||
i := 0
|
||||
for i < len(m) && m[i] == 0 {
|
||||
i++
|
||||
}
|
||||
m = m[i:]
|
||||
|
||||
buf = append(buf, "0x."...)
|
||||
buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
|
||||
buf = append(buf, 'p')
|
||||
if x.exp >= 0 {
|
||||
buf = append(buf, '+')
|
||||
}
|
||||
return strconv.AppendInt(buf, int64(x.exp), 10)
|
||||
}
|
||||
|
||||
func min(x, y int) int {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
|
||||
|
||||
// Format implements fmt.Formatter. It accepts all the regular
|
||||
// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
|
||||
// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
|
||||
// interpretation of 'p'. The 'v' format is handled like 'g'.
|
||||
// Format also supports specification of the minimum precision
|
||||
// in digits, the output field width, as well as the format flags
|
||||
// '+' and ' ' for sign control, '0' for space or zero padding,
|
||||
// and '-' for left or right justification. See the fmt package
|
||||
// for details.
|
||||
func (x *Float) Format(s fmt.State, format rune) {
|
||||
prec, hasPrec := s.Precision()
|
||||
if !hasPrec {
|
||||
prec = 6 // default precision for 'e', 'f'
|
||||
}
|
||||
|
||||
switch format {
|
||||
case 'e', 'E', 'f', 'b', 'p':
|
||||
// nothing to do
|
||||
case 'F':
|
||||
// (*Float).Text doesn't support 'F'; handle like 'f'
|
||||
format = 'f'
|
||||
case 'v':
|
||||
// handle like 'g'
|
||||
format = 'g'
|
||||
fallthrough
|
||||
case 'g', 'G':
|
||||
if !hasPrec {
|
||||
prec = -1 // default precision for 'g', 'G'
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
|
||||
return
|
||||
}
|
||||
var buf []byte
|
||||
buf = x.Append(buf, byte(format), prec)
|
||||
if len(buf) == 0 {
|
||||
buf = []byte("?") // should never happen, but don't crash
|
||||
}
|
||||
// len(buf) > 0
|
||||
|
||||
var sign string
|
||||
switch {
|
||||
case buf[0] == '-':
|
||||
sign = "-"
|
||||
buf = buf[1:]
|
||||
case buf[0] == '+':
|
||||
// +Inf
|
||||
sign = "+"
|
||||
if s.Flag(' ') {
|
||||
sign = " "
|
||||
}
|
||||
buf = buf[1:]
|
||||
case s.Flag('+'):
|
||||
sign = "+"
|
||||
case s.Flag(' '):
|
||||
sign = " "
|
||||
}
|
||||
|
||||
var padding int
|
||||
if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
|
||||
padding = width - len(sign) - len(buf)
|
||||
}
|
||||
|
||||
switch {
|
||||
case s.Flag('0') && !x.IsInf():
|
||||
// 0-padding on left
|
||||
writeMultiple(s, sign, 1)
|
||||
writeMultiple(s, "0", padding)
|
||||
s.Write(buf)
|
||||
case s.Flag('-'):
|
||||
// padding on right
|
||||
writeMultiple(s, sign, 1)
|
||||
s.Write(buf)
|
||||
writeMultiple(s, " ", padding)
|
||||
default:
|
||||
// padding on left
|
||||
writeMultiple(s, " ", padding)
|
||||
writeMultiple(s, sign, 1)
|
||||
s.Write(buf)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,247 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements int-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Text returns the string representation of x in the given base.
|
||||
// Base must be between 2 and 62, inclusive. The result uses the
|
||||
// lower-case letters 'a' to 'z' for digit values 10 to 35, and
|
||||
// the upper-case letters 'A' to 'Z' for digit values 36 to 61.
|
||||
// No prefix (such as "0x") is added to the string.
|
||||
func (x *Int) Text(base int) string {
|
||||
if x == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return string(x.abs.itoa(x.neg, base))
|
||||
}
|
||||
|
||||
// Append appends the string representation of x, as generated by
|
||||
// x.Text(base), to buf and returns the extended buffer.
|
||||
func (x *Int) Append(buf []byte, base int) []byte {
|
||||
if x == nil {
|
||||
return append(buf, "<nil>"...)
|
||||
}
|
||||
return append(buf, x.abs.itoa(x.neg, base)...)
|
||||
}
|
||||
|
||||
func (x *Int) String() string {
|
||||
return x.Text(10)
|
||||
}
|
||||
|
||||
// write count copies of text to s
|
||||
func writeMultiple(s fmt.State, text string, count int) {
|
||||
if len(text) > 0 {
|
||||
b := []byte(text)
|
||||
for ; count > 0; count-- {
|
||||
s.Write(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ fmt.Formatter = intOne // *Int must implement fmt.Formatter
|
||||
|
||||
// Format implements fmt.Formatter. It accepts the formats
|
||||
// 'b' (binary), 'o' (octal), 'd' (decimal), 'x' (lowercase
|
||||
// hexadecimal), and 'X' (uppercase hexadecimal).
|
||||
// Also supported are the full suite of package fmt's format
|
||||
// flags for integral types, including '+' and ' ' for sign
|
||||
// control, '#' for leading zero in octal and for hexadecimal,
|
||||
// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
|
||||
// specification of minimum digits precision, output field
|
||||
// width, space or zero padding, and '-' for left or right
|
||||
// justification.
|
||||
//
|
||||
func (x *Int) Format(s fmt.State, ch rune) {
|
||||
// determine base
|
||||
var base int
|
||||
switch ch {
|
||||
case 'b':
|
||||
base = 2
|
||||
case 'o':
|
||||
base = 8
|
||||
case 'd', 's', 'v':
|
||||
base = 10
|
||||
case 'x', 'X':
|
||||
base = 16
|
||||
default:
|
||||
// unknown format
|
||||
fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
|
||||
return
|
||||
}
|
||||
|
||||
if x == nil {
|
||||
fmt.Fprint(s, "<nil>")
|
||||
return
|
||||
}
|
||||
|
||||
// determine sign character
|
||||
sign := ""
|
||||
switch {
|
||||
case x.neg:
|
||||
sign = "-"
|
||||
case s.Flag('+'): // supersedes ' ' when both specified
|
||||
sign = "+"
|
||||
case s.Flag(' '):
|
||||
sign = " "
|
||||
}
|
||||
|
||||
// determine prefix characters for indicating output base
|
||||
prefix := ""
|
||||
if s.Flag('#') {
|
||||
switch ch {
|
||||
case 'o': // octal
|
||||
prefix = "0"
|
||||
case 'x': // hexadecimal
|
||||
prefix = "0x"
|
||||
case 'X':
|
||||
prefix = "0X"
|
||||
}
|
||||
}
|
||||
|
||||
digits := x.abs.utoa(base)
|
||||
if ch == 'X' {
|
||||
// faster than bytes.ToUpper
|
||||
for i, d := range digits {
|
||||
if 'a' <= d && d <= 'z' {
|
||||
digits[i] = 'A' + (d - 'a')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// number of characters for the three classes of number padding
|
||||
var left int // space characters to left of digits for right justification ("%8d")
|
||||
var zeros int // zero characters (actually cs[0]) as left-most digits ("%.8d")
|
||||
var right int // space characters to right of digits for left justification ("%-8d")
|
||||
|
||||
// determine number padding from precision: the least number of digits to output
|
||||
precision, precisionSet := s.Precision()
|
||||
if precisionSet {
|
||||
switch {
|
||||
case len(digits) < precision:
|
||||
zeros = precision - len(digits) // count of zero padding
|
||||
case len(digits) == 1 && digits[0] == '0' && precision == 0:
|
||||
return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
|
||||
}
|
||||
}
|
||||
|
||||
// determine field pad from width: the least number of characters to output
|
||||
length := len(sign) + len(prefix) + zeros + len(digits)
|
||||
if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
|
||||
switch d := width - length; {
|
||||
case s.Flag('-'):
|
||||
// pad on the right with spaces; supersedes '0' when both specified
|
||||
right = d
|
||||
case s.Flag('0') && !precisionSet:
|
||||
// pad with zeros unless precision also specified
|
||||
zeros = d
|
||||
default:
|
||||
// pad on the left with spaces
|
||||
left = d
|
||||
}
|
||||
}
|
||||
|
||||
// print number as [left pad][sign][prefix][zero pad][digits][right pad]
|
||||
writeMultiple(s, " ", left)
|
||||
writeMultiple(s, sign, 1)
|
||||
writeMultiple(s, prefix, 1)
|
||||
writeMultiple(s, "0", zeros)
|
||||
s.Write(digits)
|
||||
writeMultiple(s, " ", right)
|
||||
}
|
||||
|
||||
// scan sets z to the integer value corresponding to the longest possible prefix
|
||||
// read from r representing a signed integer number in a given conversion base.
|
||||
// It returns z, the actual conversion base used, and an error, if any. In the
|
||||
// error case, the value of z is undefined but the returned value is nil. The
|
||||
// syntax follows the syntax of integer literals in Go.
|
||||
//
|
||||
// The base argument must be 0 or a value from 2 through MaxBase. If the base
|
||||
// is 0, the string prefix determines the actual conversion base. A prefix of
|
||||
// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
|
||||
// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
|
||||
//
|
||||
func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
|
||||
// determine sign
|
||||
neg, err := scanSign(r)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// determine mantissa
|
||||
z.abs, base, _, err = z.abs.scan(r, base, false)
|
||||
if err != nil {
|
||||
return nil, base, err
|
||||
}
|
||||
z.neg = len(z.abs) > 0 && neg // 0 has no sign
|
||||
|
||||
return z, base, nil
|
||||
}
|
||||
|
||||
func scanSign(r io.ByteScanner) (neg bool, err error) {
|
||||
var ch byte
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch ch {
|
||||
case '-':
|
||||
neg = true
|
||||
case '+':
|
||||
// nothing to do
|
||||
default:
|
||||
r.UnreadByte()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// byteReader is a local wrapper around fmt.ScanState;
|
||||
// it implements the ByteReader interface.
|
||||
type byteReader struct {
|
||||
fmt.ScanState
|
||||
}
|
||||
|
||||
func (r byteReader) ReadByte() (byte, error) {
|
||||
ch, size, err := r.ReadRune()
|
||||
if size != 1 && err == nil {
|
||||
err = fmt.Errorf("invalid rune %#U", ch)
|
||||
}
|
||||
return byte(ch), err
|
||||
}
|
||||
|
||||
func (r byteReader) UnreadByte() error {
|
||||
return r.UnreadRune()
|
||||
}
|
||||
|
||||
var _ fmt.Scanner = intOne // *Int must implement fmt.Scanner
|
||||
|
||||
// Scan is a support routine for fmt.Scanner; it sets z to the value of
|
||||
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
|
||||
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
|
||||
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
|
||||
s.SkipSpace() // skip leading space characters
|
||||
base := 0
|
||||
switch ch {
|
||||
case 'b':
|
||||
base = 2
|
||||
case 'o':
|
||||
base = 8
|
||||
case 'd':
|
||||
base = 10
|
||||
case 'x', 'X':
|
||||
base = 16
|
||||
case 's', 'v':
|
||||
// let scan determine the base
|
||||
default:
|
||||
return errors.New("Int.Scan: invalid verb")
|
||||
}
|
||||
_, _, err := z.scan(byteReader{s}, base)
|
||||
return err
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements encoding/decoding of Ints.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const intGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (x *Int) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
|
||||
i := x.abs.bytes(buf) - 1 // i >= 0
|
||||
b := intGobVersion << 1 // make space for sign bit
|
||||
if x.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[i] = b
|
||||
return buf[i:], nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Int) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Int{}
|
||||
return nil
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != intGobVersion {
|
||||
return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
|
||||
}
|
||||
z.neg = b&1 != 0
|
||||
z.abs = z.abs.setBytes(buf[1:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (x *Int) MarshalText() (text []byte, err error) {
|
||||
if x == nil {
|
||||
return []byte("<nil>"), nil
|
||||
}
|
||||
return x.abs.itoa(x.neg, 10), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (z *Int) UnmarshalText(text []byte) error {
|
||||
if _, ok := z.setFromScanner(bytes.NewReader(text), 0); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The JSON marshalers are only here for API backward compatibility
|
||||
// (programs that explicitly look for these two methods). JSON works
|
||||
// fine with the TextMarshaler only.
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (x *Int) MarshalJSON() ([]byte, error) {
|
||||
return x.MarshalText()
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (z *Int) UnmarshalJSON(text []byte) error {
|
||||
// Ignore null, like in the main JSON package.
|
||||
if string(text) == "null" {
|
||||
return nil
|
||||
}
|
||||
return z.UnmarshalText(text)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,503 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements nat-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/bits"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// Note: MaxBase = len(digits), but it must remain an untyped rune constant
|
||||
// for API compatibility.
|
||||
|
||||
// MaxBase is the largest number base accepted for string conversions.
|
||||
const MaxBase = 10 + ('z' - 'a' + 1) + ('Z' - 'A' + 1)
|
||||
const maxBaseSmall = 10 + ('z' - 'a' + 1)
|
||||
|
||||
// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
|
||||
// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
|
||||
// In other words, at most n digits in base b fit into a Word.
|
||||
// TODO(gri) replace this with a table, generated at build time.
|
||||
func maxPow(b Word) (p Word, n int) {
|
||||
p, n = b, 1 // assuming b <= _M
|
||||
for max := _M / b; p <= max; {
|
||||
// p == b**n && p <= max
|
||||
p *= b
|
||||
n++
|
||||
}
|
||||
// p == b**n && p <= _M
|
||||
return
|
||||
}
|
||||
|
||||
// pow returns x**n for n > 0, and 1 otherwise.
|
||||
func pow(x Word, n int) (p Word) {
|
||||
// n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
|
||||
// thus x**n == product of x**(2**i) for all i where bi == 1
|
||||
// (Russian Peasant Method for exponentiation)
|
||||
p = 1
|
||||
for n > 0 {
|
||||
if n&1 != 0 {
|
||||
p *= x
|
||||
}
|
||||
x *= x
|
||||
n >>= 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// scan scans the number corresponding to the longest possible prefix
|
||||
// from r representing an unsigned number in a given conversion base.
|
||||
// It returns the corresponding natural number res, the actual base b,
|
||||
// a digit count, and a read or syntax error err, if any.
|
||||
//
|
||||
// number = [ prefix ] mantissa .
|
||||
// prefix = "0" [ "x" | "X" | "b" | "B" ] .
|
||||
// mantissa = digits | digits "." [ digits ] | "." digits .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
|
||||
//
|
||||
// Unless fracOk is set, the base argument must be 0 or a value between
|
||||
// 2 and MaxBase. If fracOk is set, the base argument must be one of
|
||||
// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
|
||||
// time panic.
|
||||
//
|
||||
// For base 0, the number prefix determines the actual base: A prefix of
|
||||
// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
|
||||
// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
|
||||
// the selected base is 10 and no prefix is accepted.
|
||||
//
|
||||
// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
|
||||
// stands for a zero digit), and a period followed by a fractional part
|
||||
// is permitted. The result value is computed as if there were no period
|
||||
// present; and the count value is used to determine the fractional part.
|
||||
//
|
||||
// For bases <= 36, lower and upper case letters are considered the same:
|
||||
// The letters 'a' to 'z' and 'A' to 'Z' represent digit values 10 to 35.
|
||||
// For bases > 36, the upper case letters 'A' to 'Z' represent the digit
|
||||
// values 36 to 61.
|
||||
//
|
||||
// A result digit count > 0 corresponds to the number of (non-prefix) digits
|
||||
// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
|
||||
// is set, only), and -count is the number of fractional digits found.
|
||||
// In this case, the actual value of the scanned number is res * b**count.
|
||||
//
|
||||
func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
|
||||
// reject illegal bases
|
||||
baseOk := base == 0 ||
|
||||
!fracOk && 2 <= base && base <= MaxBase ||
|
||||
fracOk && (base == 2 || base == 10 || base == 16)
|
||||
if !baseOk {
|
||||
panic(fmt.Sprintf("illegal number base %d", base))
|
||||
}
|
||||
|
||||
// one char look-ahead
|
||||
ch, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// determine actual base
|
||||
b = base
|
||||
if base == 0 {
|
||||
// actual base is 10 unless there's a base prefix
|
||||
b = 10
|
||||
if ch == '0' {
|
||||
count = 1
|
||||
switch ch, err = r.ReadByte(); err {
|
||||
case nil:
|
||||
// possibly one of 0x, 0X, 0b, 0B
|
||||
if !fracOk {
|
||||
b = 8
|
||||
}
|
||||
switch ch {
|
||||
case 'x', 'X':
|
||||
b = 16
|
||||
case 'b', 'B':
|
||||
b = 2
|
||||
}
|
||||
switch b {
|
||||
case 16, 2:
|
||||
count = 0 // prefix is not counted
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
// io.EOF is also an error in this case
|
||||
return
|
||||
}
|
||||
case 8:
|
||||
count = 0 // prefix is not counted
|
||||
}
|
||||
case io.EOF:
|
||||
// input is "0"
|
||||
res = z[:0]
|
||||
err = nil
|
||||
return
|
||||
default:
|
||||
// read error
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert string
|
||||
// Algorithm: Collect digits in groups of at most n digits in di
|
||||
// and then use mulAddWW for every such group to add them to the
|
||||
// result.
|
||||
z = z[:0]
|
||||
b1 := Word(b)
|
||||
bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
|
||||
di := Word(0) // 0 <= di < b1**i < bn
|
||||
i := 0 // 0 <= i < n
|
||||
dp := -1 // position of decimal point
|
||||
for {
|
||||
if fracOk && ch == '.' {
|
||||
fracOk = false
|
||||
dp = count
|
||||
// advance
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// convert rune into digit value d1
|
||||
var d1 Word
|
||||
switch {
|
||||
case '0' <= ch && ch <= '9':
|
||||
d1 = Word(ch - '0')
|
||||
case 'a' <= ch && ch <= 'z':
|
||||
d1 = Word(ch - 'a' + 10)
|
||||
case 'A' <= ch && ch <= 'Z':
|
||||
if b <= maxBaseSmall {
|
||||
d1 = Word(ch - 'A' + 10)
|
||||
} else {
|
||||
d1 = Word(ch - 'A' + maxBaseSmall)
|
||||
}
|
||||
default:
|
||||
d1 = MaxBase + 1
|
||||
}
|
||||
if d1 >= b1 {
|
||||
r.UnreadByte() // ch does not belong to number anymore
|
||||
break
|
||||
}
|
||||
count++
|
||||
|
||||
// collect d1 in di
|
||||
di = di*b1 + d1
|
||||
i++
|
||||
|
||||
// if di is "full", add it to the result
|
||||
if i == n {
|
||||
z = z.mulAddWW(z, bn, di)
|
||||
di = 0
|
||||
i = 0
|
||||
}
|
||||
|
||||
// advance
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
// no digits found
|
||||
switch {
|
||||
case base == 0 && b == 8:
|
||||
// there was only the octal prefix 0 (possibly followed by digits > 7);
|
||||
// count as one digit and return base 10, not 8
|
||||
count = 1
|
||||
b = 10
|
||||
case base != 0 || b != 8:
|
||||
// there was neither a mantissa digit nor the octal prefix 0
|
||||
err = errors.New("syntax error scanning number")
|
||||
}
|
||||
return
|
||||
}
|
||||
// count > 0
|
||||
|
||||
// add remaining digits to result
|
||||
if i > 0 {
|
||||
z = z.mulAddWW(z, pow(b1, i), di)
|
||||
}
|
||||
res = z.norm()
|
||||
|
||||
// adjust for fraction, if any
|
||||
if dp >= 0 {
|
||||
// 0 <= dp <= count > 0
|
||||
count = dp - count
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// utoa converts x to an ASCII representation in the given base;
|
||||
// base must be between 2 and MaxBase, inclusive.
|
||||
func (x nat) utoa(base int) []byte {
|
||||
return x.itoa(false, base)
|
||||
}
|
||||
|
||||
// itoa is like utoa but it prepends a '-' if neg && x != 0.
|
||||
func (x nat) itoa(neg bool, base int) []byte {
|
||||
if base < 2 || base > MaxBase {
|
||||
panic("invalid base")
|
||||
}
|
||||
|
||||
// x == 0
|
||||
if len(x) == 0 {
|
||||
return []byte("0")
|
||||
}
|
||||
// len(x) > 0
|
||||
|
||||
// allocate buffer for conversion
|
||||
i := int(float64(x.bitLen())/math.Log2(float64(base))) + 1 // off by 1 at most
|
||||
if neg {
|
||||
i++
|
||||
}
|
||||
s := make([]byte, i)
|
||||
|
||||
// convert power of two and non power of two bases separately
|
||||
if b := Word(base); b == b&-b {
|
||||
// shift is base b digit size in bits
|
||||
shift := uint(bits.TrailingZeros(uint(b))) // shift > 0 because b >= 2
|
||||
mask := Word(1<<shift - 1)
|
||||
w := x[0] // current word
|
||||
nbits := uint(_W) // number of unprocessed bits in w
|
||||
|
||||
// convert less-significant words (include leading zeros)
|
||||
for k := 1; k < len(x); k++ {
|
||||
// convert full digits
|
||||
for nbits >= shift {
|
||||
i--
|
||||
s[i] = digits[w&mask]
|
||||
w >>= shift
|
||||
nbits -= shift
|
||||
}
|
||||
|
||||
// convert any partial leading digit and advance to next word
|
||||
if nbits == 0 {
|
||||
// no partial digit remaining, just advance
|
||||
w = x[k]
|
||||
nbits = _W
|
||||
} else {
|
||||
// partial digit in current word w (== x[k-1]) and next word x[k]
|
||||
w |= x[k] << nbits
|
||||
i--
|
||||
s[i] = digits[w&mask]
|
||||
|
||||
// advance
|
||||
w = x[k] >> (shift - nbits)
|
||||
nbits = _W - (shift - nbits)
|
||||
}
|
||||
}
|
||||
|
||||
// convert digits of most-significant word w (omit leading zeros)
|
||||
for w != 0 {
|
||||
i--
|
||||
s[i] = digits[w&mask]
|
||||
w >>= shift
|
||||
}
|
||||
|
||||
} else {
|
||||
bb, ndigits := maxPow(b)
|
||||
|
||||
// construct table of successive squares of bb*leafSize to use in subdivisions
|
||||
// result (table != nil) <=> (len(x) > leafSize > 0)
|
||||
table := divisors(len(x), b, ndigits, bb)
|
||||
|
||||
// preserve x, create local copy for use by convertWords
|
||||
q := nat(nil).set(x)
|
||||
|
||||
// convert q to string s in base b
|
||||
q.convertWords(s, b, ndigits, bb, table)
|
||||
|
||||
// strip leading zeros
|
||||
// (x != 0; thus s must contain at least one non-zero digit
|
||||
// and the loop will terminate)
|
||||
i = 0
|
||||
for s[i] == '0' {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if neg {
|
||||
i--
|
||||
s[i] = '-'
|
||||
}
|
||||
|
||||
return s[i:]
|
||||
}
|
||||
|
||||
// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
|
||||
// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
|
||||
// repeated nat/Word division.
|
||||
//
|
||||
// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
|
||||
// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
|
||||
// Recursive conversion divides q by its approximate square root, yielding two parts, each half
|
||||
// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
|
||||
// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
|
||||
// is made better by splitting the subblocks recursively. Best is to split blocks until one more
|
||||
// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
|
||||
// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
|
||||
// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
|
||||
// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
|
||||
// specific hardware.
|
||||
//
|
||||
func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []divisor) {
|
||||
// split larger blocks recursively
|
||||
if table != nil {
|
||||
// len(q) > leafSize > 0
|
||||
var r nat
|
||||
index := len(table) - 1
|
||||
for len(q) > leafSize {
|
||||
// find divisor close to sqrt(q) if possible, but in any case < q
|
||||
maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length
|
||||
minLength := maxLength >> 1 // ~= log2 sqrt(q)
|
||||
for index > 0 && table[index-1].nbits > minLength {
|
||||
index-- // desired
|
||||
}
|
||||
if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
|
||||
index--
|
||||
if index < 0 {
|
||||
panic("internal inconsistency")
|
||||
}
|
||||
}
|
||||
|
||||
// split q into the two digit number (q'*bbb + r) to form independent subblocks
|
||||
q, r = q.div(r, q, table[index].bbb)
|
||||
|
||||
// convert subblocks and collect results in s[:h] and s[h:]
|
||||
h := len(s) - table[index].ndigits
|
||||
r.convertWords(s[h:], b, ndigits, bb, table[0:index])
|
||||
s = s[:h] // == q.convertWords(s, b, ndigits, bb, table[0:index+1])
|
||||
}
|
||||
}
|
||||
|
||||
// having split any large blocks now process the remaining (small) block iteratively
|
||||
i := len(s)
|
||||
var r Word
|
||||
if b == 10 {
|
||||
// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
|
||||
for len(q) > 0 {
|
||||
// extract least significant, base bb "digit"
|
||||
q, r = q.divW(q, bb)
|
||||
for j := 0; j < ndigits && i > 0; j++ {
|
||||
i--
|
||||
// avoid % computation since r%10 == r - int(r/10)*10;
|
||||
// this appears to be faster for BenchmarkString10000Base10
|
||||
// and smaller strings (but a bit slower for larger ones)
|
||||
t := r / 10
|
||||
s[i] = '0' + byte(r-t*10)
|
||||
r = t
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for len(q) > 0 {
|
||||
// extract least significant, base bb "digit"
|
||||
q, r = q.divW(q, bb)
|
||||
for j := 0; j < ndigits && i > 0; j++ {
|
||||
i--
|
||||
s[i] = digits[r%b]
|
||||
r /= b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prepend high-order zeros
|
||||
for i > 0 { // while need more leading zeros
|
||||
i--
|
||||
s[i] = '0'
|
||||
}
|
||||
}
|
||||
|
||||
// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
|
||||
// Benchmark and configure leafSize using: go test -bench="Leaf"
|
||||
// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
|
||||
// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
|
||||
var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
|
||||
|
||||
type divisor struct {
|
||||
bbb nat // divisor
|
||||
nbits int // bit length of divisor (discounting leading zeros) ~= log2(bbb)
|
||||
ndigits int // digit length of divisor in terms of output base digits
|
||||
}
|
||||
|
||||
var cacheBase10 struct {
|
||||
sync.Mutex
|
||||
table [64]divisor // cached divisors for base 10
|
||||
}
|
||||
|
||||
// expWW computes x**y
|
||||
func (z nat) expWW(x, y Word) nat {
|
||||
return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
|
||||
}
|
||||
|
||||
// construct table of powers of bb*leafSize to use in subdivisions
|
||||
func divisors(m int, b Word, ndigits int, bb Word) []divisor {
|
||||
// only compute table when recursive conversion is enabled and x is large
|
||||
if leafSize == 0 || m <= leafSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
|
||||
k := 1
|
||||
for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
|
||||
k++
|
||||
}
|
||||
|
||||
// reuse and extend existing table of divisors or create new table as appropriate
|
||||
var table []divisor // for b == 10, table overlaps with cacheBase10.table
|
||||
if b == 10 {
|
||||
cacheBase10.Lock()
|
||||
table = cacheBase10.table[0:k] // reuse old table for this conversion
|
||||
} else {
|
||||
table = make([]divisor, k) // create new table for this conversion
|
||||
}
|
||||
|
||||
// extend table
|
||||
if table[k-1].ndigits == 0 {
|
||||
// add new entries as needed
|
||||
var larger nat
|
||||
for i := 0; i < k; i++ {
|
||||
if table[i].ndigits == 0 {
|
||||
if i == 0 {
|
||||
table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
|
||||
table[0].ndigits = ndigits * leafSize
|
||||
} else {
|
||||
table[i].bbb = nat(nil).sqr(table[i-1].bbb)
|
||||
table[i].ndigits = 2 * table[i-1].ndigits
|
||||
}
|
||||
|
||||
// optimization: exploit aggregated extra bits in macro blocks
|
||||
larger = nat(nil).set(table[i].bbb)
|
||||
for mulAddVWW(larger, larger, b, 0) == 0 {
|
||||
table[i].bbb = table[i].bbb.set(larger)
|
||||
table[i].ndigits++
|
||||
}
|
||||
|
||||
table[i].nbits = table[i].bbb.bitLen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b == 10 {
|
||||
cacheBase10.Unlock()
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
|
@ -1,320 +0,0 @@
|
|||
// 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 big
|
||||
|
||||
import "math/rand"
|
||||
|
||||
// ProbablyPrime reports whether x is probably prime,
|
||||
// applying the Miller-Rabin test with n pseudorandomly chosen bases
|
||||
// as well as a Baillie-PSW test.
|
||||
//
|
||||
// If x is prime, ProbablyPrime returns true.
|
||||
// If x is chosen randomly and not prime, ProbablyPrime probably returns false.
|
||||
// The probability of returning true for a randomly chosen non-prime is at most ¼ⁿ.
|
||||
//
|
||||
// ProbablyPrime is 100% accurate for inputs less than 2⁶⁴.
|
||||
// See Menezes et al., Handbook of Applied Cryptography, 1997, pp. 145-149,
|
||||
// and FIPS 186-4 Appendix F for further discussion of the error probabilities.
|
||||
//
|
||||
// ProbablyPrime is not suitable for judging primes that an adversary may
|
||||
// have crafted to fool the test.
|
||||
//
|
||||
// As of Go 1.8, ProbablyPrime(0) is allowed and applies only a Baillie-PSW test.
|
||||
// Before Go 1.8, ProbablyPrime applied only the Miller-Rabin tests, and ProbablyPrime(0) panicked.
|
||||
func (x *Int) ProbablyPrime(n int) bool {
|
||||
// Note regarding the doc comment above:
|
||||
// It would be more precise to say that the Baillie-PSW test uses the
|
||||
// extra strong Lucas test as its Lucas test, but since no one knows
|
||||
// how to tell any of the Lucas tests apart inside a Baillie-PSW test
|
||||
// (they all work equally well empirically), that detail need not be
|
||||
// documented or implicitly guaranteed.
|
||||
// The comment does avoid saying "the" Baillie-PSW test
|
||||
// because of this general ambiguity.
|
||||
|
||||
if n < 0 {
|
||||
panic("negative n for ProbablyPrime")
|
||||
}
|
||||
if x.neg || len(x.abs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// primeBitMask records the primes < 64.
|
||||
const primeBitMask uint64 = 1<<2 | 1<<3 | 1<<5 | 1<<7 |
|
||||
1<<11 | 1<<13 | 1<<17 | 1<<19 | 1<<23 | 1<<29 | 1<<31 |
|
||||
1<<37 | 1<<41 | 1<<43 | 1<<47 | 1<<53 | 1<<59 | 1<<61
|
||||
|
||||
w := x.abs[0]
|
||||
if len(x.abs) == 1 && w < 64 {
|
||||
return primeBitMask&(1<<w) != 0
|
||||
}
|
||||
|
||||
if w&1 == 0 {
|
||||
return false // n is even
|
||||
}
|
||||
|
||||
const primesA = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37
|
||||
const primesB = 29 * 31 * 41 * 43 * 47 * 53
|
||||
|
||||
var rA, rB uint32
|
||||
switch _W {
|
||||
case 32:
|
||||
rA = uint32(x.abs.modW(primesA))
|
||||
rB = uint32(x.abs.modW(primesB))
|
||||
case 64:
|
||||
r := x.abs.modW((primesA * primesB) & _M)
|
||||
rA = uint32(r % primesA)
|
||||
rB = uint32(r % primesB)
|
||||
default:
|
||||
panic("math/big: invalid word size")
|
||||
}
|
||||
|
||||
if rA%3 == 0 || rA%5 == 0 || rA%7 == 0 || rA%11 == 0 || rA%13 == 0 || rA%17 == 0 || rA%19 == 0 || rA%23 == 0 || rA%37 == 0 ||
|
||||
rB%29 == 0 || rB%31 == 0 || rB%41 == 0 || rB%43 == 0 || rB%47 == 0 || rB%53 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return x.abs.probablyPrimeMillerRabin(n+1, true) && x.abs.probablyPrimeLucas()
|
||||
}
|
||||
|
||||
// probablyPrimeMillerRabin reports whether n passes reps rounds of the
|
||||
// Miller-Rabin primality test, using pseudo-randomly chosen bases.
|
||||
// If force2 is true, one of the rounds is forced to use base 2.
|
||||
// See Handbook of Applied Cryptography, p. 139, Algorithm 4.24.
|
||||
// The number n is known to be non-zero.
|
||||
func (n nat) probablyPrimeMillerRabin(reps int, force2 bool) bool {
|
||||
nm1 := nat(nil).sub(n, natOne)
|
||||
// determine q, k such that nm1 = q << k
|
||||
k := nm1.trailingZeroBits()
|
||||
q := nat(nil).shr(nm1, k)
|
||||
|
||||
nm3 := nat(nil).sub(nm1, natTwo)
|
||||
rand := rand.New(rand.NewSource(int64(n[0])))
|
||||
|
||||
var x, y, quotient nat
|
||||
nm3Len := nm3.bitLen()
|
||||
|
||||
NextRandom:
|
||||
for i := 0; i < reps; i++ {
|
||||
if i == reps-1 && force2 {
|
||||
x = x.set(natTwo)
|
||||
} else {
|
||||
x = x.random(rand, nm3, nm3Len)
|
||||
x = x.add(x, natTwo)
|
||||
}
|
||||
y = y.expNN(x, q, n)
|
||||
if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
|
||||
continue
|
||||
}
|
||||
for j := uint(1); j < k; j++ {
|
||||
y = y.sqr(y)
|
||||
quotient, y = quotient.div(y, y, n)
|
||||
if y.cmp(nm1) == 0 {
|
||||
continue NextRandom
|
||||
}
|
||||
if y.cmp(natOne) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// probablyPrimeLucas reports whether n passes the "almost extra strong" Lucas probable prime test,
|
||||
// using Baillie-OEIS parameter selection. This corresponds to "AESLPSP" on Jacobsen's tables (link below).
|
||||
// The combination of this test and a Miller-Rabin/Fermat test with base 2 gives a Baillie-PSW test.
|
||||
//
|
||||
// References:
|
||||
//
|
||||
// Baillie and Wagstaff, "Lucas Pseudoprimes", Mathematics of Computation 35(152),
|
||||
// October 1980, pp. 1391-1417, especially page 1401.
|
||||
// http://www.ams.org/journals/mcom/1980-35-152/S0025-5718-1980-0583518-6/S0025-5718-1980-0583518-6.pdf
|
||||
//
|
||||
// Grantham, "Frobenius Pseudoprimes", Mathematics of Computation 70(234),
|
||||
// March 2000, pp. 873-891.
|
||||
// http://www.ams.org/journals/mcom/2001-70-234/S0025-5718-00-01197-2/S0025-5718-00-01197-2.pdf
|
||||
//
|
||||
// Baillie, "Extra strong Lucas pseudoprimes", OEIS A217719, https://oeis.org/A217719.
|
||||
//
|
||||
// Jacobsen, "Pseudoprime Statistics, Tables, and Data", http://ntheory.org/pseudoprimes.html.
|
||||
//
|
||||
// Nicely, "The Baillie-PSW Primality Test", http://www.trnicely.net/misc/bpsw.html.
|
||||
// (Note that Nicely's definition of the "extra strong" test gives the wrong Jacobi condition,
|
||||
// as pointed out by Jacobsen.)
|
||||
//
|
||||
// Crandall and Pomerance, Prime Numbers: A Computational Perspective, 2nd ed.
|
||||
// Springer, 2005.
|
||||
func (n nat) probablyPrimeLucas() bool {
|
||||
// Discard 0, 1.
|
||||
if len(n) == 0 || n.cmp(natOne) == 0 {
|
||||
return false
|
||||
}
|
||||
// Two is the only even prime.
|
||||
// Already checked by caller, but here to allow testing in isolation.
|
||||
if n[0]&1 == 0 {
|
||||
return n.cmp(natTwo) == 0
|
||||
}
|
||||
|
||||
// Baillie-OEIS "method C" for choosing D, P, Q,
|
||||
// as in https://oeis.org/A217719/a217719.txt:
|
||||
// try increasing P ≥ 3 such that D = P² - 4 (so Q = 1)
|
||||
// until Jacobi(D, n) = -1.
|
||||
// The search is expected to succeed for non-square n after just a few trials.
|
||||
// After more than expected failures, check whether n is square
|
||||
// (which would cause Jacobi(D, n) = 1 for all D not dividing n).
|
||||
p := Word(3)
|
||||
d := nat{1}
|
||||
t1 := nat(nil) // temp
|
||||
intD := &Int{abs: d}
|
||||
intN := &Int{abs: n}
|
||||
for ; ; p++ {
|
||||
if p > 10000 {
|
||||
// This is widely believed to be impossible.
|
||||
// If we get a report, we'll want the exact number n.
|
||||
panic("math/big: internal error: cannot find (D/n) = -1 for " + intN.String())
|
||||
}
|
||||
d[0] = p*p - 4
|
||||
j := Jacobi(intD, intN)
|
||||
if j == -1 {
|
||||
break
|
||||
}
|
||||
if j == 0 {
|
||||
// d = p²-4 = (p-2)(p+2).
|
||||
// If (d/n) == 0 then d shares a prime factor with n.
|
||||
// Since the loop proceeds in increasing p and starts with p-2==1,
|
||||
// the shared prime factor must be p+2.
|
||||
// If p+2 == n, then n is prime; otherwise p+2 is a proper factor of n.
|
||||
return len(n) == 1 && n[0] == p+2
|
||||
}
|
||||
if p == 40 {
|
||||
// We'll never find (d/n) = -1 if n is a square.
|
||||
// If n is a non-square we expect to find a d in just a few attempts on average.
|
||||
// After 40 attempts, take a moment to check if n is indeed a square.
|
||||
t1 = t1.sqrt(n)
|
||||
t1 = t1.sqr(t1)
|
||||
if t1.cmp(n) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grantham definition of "extra strong Lucas pseudoprime", after Thm 2.3 on p. 876
|
||||
// (D, P, Q above have become Δ, b, 1):
|
||||
//
|
||||
// Let U_n = U_n(b, 1), V_n = V_n(b, 1), and Δ = b²-4.
|
||||
// An extra strong Lucas pseudoprime to base b is a composite n = 2^r s + Jacobi(Δ, n),
|
||||
// where s is odd and gcd(n, 2*Δ) = 1, such that either (i) U_s ≡ 0 mod n and V_s ≡ ±2 mod n,
|
||||
// or (ii) V_{2^t s} ≡ 0 mod n for some 0 ≤ t < r-1.
|
||||
//
|
||||
// We know gcd(n, Δ) = 1 or else we'd have found Jacobi(d, n) == 0 above.
|
||||
// We know gcd(n, 2) = 1 because n is odd.
|
||||
//
|
||||
// Arrange s = (n - Jacobi(Δ, n)) / 2^r = (n+1) / 2^r.
|
||||
s := nat(nil).add(n, natOne)
|
||||
r := int(s.trailingZeroBits())
|
||||
s = s.shr(s, uint(r))
|
||||
nm2 := nat(nil).sub(n, natTwo) // n-2
|
||||
|
||||
// We apply the "almost extra strong" test, which checks the above conditions
|
||||
// except for U_s ≡ 0 mod n, which allows us to avoid computing any U_k values.
|
||||
// Jacobsen points out that maybe we should just do the full extra strong test:
|
||||
// "It is also possible to recover U_n using Crandall and Pomerance equation 3.13:
|
||||
// U_n = D^-1 (2V_{n+1} - PV_n) allowing us to run the full extra-strong test
|
||||
// at the cost of a single modular inversion. This computation is easy and fast in GMP,
|
||||
// so we can get the full extra-strong test at essentially the same performance as the
|
||||
// almost extra strong test."
|
||||
|
||||
// Compute Lucas sequence V_s(b, 1), where:
|
||||
//
|
||||
// V(0) = 2
|
||||
// V(1) = P
|
||||
// V(k) = P V(k-1) - Q V(k-2).
|
||||
//
|
||||
// (Remember that due to method C above, P = b, Q = 1.)
|
||||
//
|
||||
// In general V(k) = α^k + β^k, where α and β are roots of x² - Px + Q.
|
||||
// Crandall and Pomerance (p.147) observe that for 0 ≤ j ≤ k,
|
||||
//
|
||||
// V(j+k) = V(j)V(k) - V(k-j).
|
||||
//
|
||||
// So in particular, to quickly double the subscript:
|
||||
//
|
||||
// V(2k) = V(k)² - 2
|
||||
// V(2k+1) = V(k) V(k+1) - P
|
||||
//
|
||||
// We can therefore start with k=0 and build up to k=s in log₂(s) steps.
|
||||
natP := nat(nil).setWord(p)
|
||||
vk := nat(nil).setWord(2)
|
||||
vk1 := nat(nil).setWord(p)
|
||||
t2 := nat(nil) // temp
|
||||
for i := int(s.bitLen()); i >= 0; i-- {
|
||||
if s.bit(uint(i)) != 0 {
|
||||
// k' = 2k+1
|
||||
// V(k') = V(2k+1) = V(k) V(k+1) - P.
|
||||
t1 = t1.mul(vk, vk1)
|
||||
t1 = t1.add(t1, n)
|
||||
t1 = t1.sub(t1, natP)
|
||||
t2, vk = t2.div(vk, t1, n)
|
||||
// V(k'+1) = V(2k+2) = V(k+1)² - 2.
|
||||
t1 = t1.sqr(vk1)
|
||||
t1 = t1.add(t1, nm2)
|
||||
t2, vk1 = t2.div(vk1, t1, n)
|
||||
} else {
|
||||
// k' = 2k
|
||||
// V(k'+1) = V(2k+1) = V(k) V(k+1) - P.
|
||||
t1 = t1.mul(vk, vk1)
|
||||
t1 = t1.add(t1, n)
|
||||
t1 = t1.sub(t1, natP)
|
||||
t2, vk1 = t2.div(vk1, t1, n)
|
||||
// V(k') = V(2k) = V(k)² - 2
|
||||
t1 = t1.sqr(vk)
|
||||
t1 = t1.add(t1, nm2)
|
||||
t2, vk = t2.div(vk, t1, n)
|
||||
}
|
||||
}
|
||||
|
||||
// Now k=s, so vk = V(s). Check V(s) ≡ ±2 (mod n).
|
||||
if vk.cmp(natTwo) == 0 || vk.cmp(nm2) == 0 {
|
||||
// Check U(s) ≡ 0.
|
||||
// As suggested by Jacobsen, apply Crandall and Pomerance equation 3.13:
|
||||
//
|
||||
// U(k) = D⁻¹ (2 V(k+1) - P V(k))
|
||||
//
|
||||
// Since we are checking for U(k) == 0 it suffices to check 2 V(k+1) == P V(k) mod n,
|
||||
// or P V(k) - 2 V(k+1) == 0 mod n.
|
||||
t1 := t1.mul(vk, natP)
|
||||
t2 := t2.shl(vk1, 1)
|
||||
if t1.cmp(t2) < 0 {
|
||||
t1, t2 = t2, t1
|
||||
}
|
||||
t1 = t1.sub(t1, t2)
|
||||
t3 := vk1 // steal vk1, no longer needed below
|
||||
vk1 = nil
|
||||
_ = vk1
|
||||
t2, t3 = t2.div(t3, t1, n)
|
||||
if len(t3) == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check V(2^t s) ≡ 0 mod n for some 0 ≤ t < r-1.
|
||||
for t := 0; t < r-1; t++ {
|
||||
if len(vk) == 0 { // vk == 0
|
||||
return true
|
||||
}
|
||||
// Optimization: V(k) = 2 is a fixed point for V(k') = V(k)² - 2,
|
||||
// so if V(k) = 2, we can stop: we will never find a future V(k) == 0.
|
||||
if len(vk) == 1 && vk[0] == 2 { // vk == 2
|
||||
return false
|
||||
}
|
||||
// k' = 2k
|
||||
// V(k') = V(2k) = V(k)² - 2
|
||||
t1 = t1.sqr(vk)
|
||||
t1 = t1.sub(t1, natTwo)
|
||||
t2, vk = t2.div(vk, t1, n)
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,517 +0,0 @@
|
|||
// Copyright 2010 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.
|
||||
|
||||
// This file implements multi-precision rational numbers.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// A Rat represents a quotient a/b of arbitrary precision.
|
||||
// The zero value for a Rat represents the value 0.
|
||||
type Rat struct {
|
||||
// To make zero values for Rat work w/o initialization,
|
||||
// a zero value of b (len(b) == 0) acts like b == 1.
|
||||
// a.neg determines the sign of the Rat, b.neg is ignored.
|
||||
a, b Int
|
||||
}
|
||||
|
||||
// NewRat creates a new Rat with numerator a and denominator b.
|
||||
func NewRat(a, b int64) *Rat {
|
||||
return new(Rat).SetFrac64(a, b)
|
||||
}
|
||||
|
||||
// SetFloat64 sets z to exactly f and returns z.
|
||||
// If f is not finite, SetFloat returns nil.
|
||||
func (z *Rat) SetFloat64(f float64) *Rat {
|
||||
const expMask = 1<<11 - 1
|
||||
bits := math.Float64bits(f)
|
||||
mantissa := bits & (1<<52 - 1)
|
||||
exp := int((bits >> 52) & expMask)
|
||||
switch exp {
|
||||
case expMask: // non-finite
|
||||
return nil
|
||||
case 0: // denormal
|
||||
exp -= 1022
|
||||
default: // normal
|
||||
mantissa |= 1 << 52
|
||||
exp -= 1023
|
||||
}
|
||||
|
||||
shift := 52 - exp
|
||||
|
||||
// Optimization (?): partially pre-normalise.
|
||||
for mantissa&1 == 0 && shift > 0 {
|
||||
mantissa >>= 1
|
||||
shift--
|
||||
}
|
||||
|
||||
z.a.SetUint64(mantissa)
|
||||
z.a.neg = f < 0
|
||||
z.b.Set(intOne)
|
||||
if shift > 0 {
|
||||
z.b.Lsh(&z.b, uint(shift))
|
||||
} else {
|
||||
z.a.Lsh(&z.a, uint(-shift))
|
||||
}
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// quotToFloat32 returns the non-negative float32 value
|
||||
// nearest to the quotient a/b, using round-to-even in
|
||||
// halfway cases. It does not mutate its arguments.
|
||||
// Preconditions: b is non-zero; a and b have no common factors.
|
||||
func quotToFloat32(a, b nat) (f float32, exact bool) {
|
||||
const (
|
||||
// float size in bits
|
||||
Fsize = 32
|
||||
|
||||
// mantissa
|
||||
Msize = 23
|
||||
Msize1 = Msize + 1 // incl. implicit 1
|
||||
Msize2 = Msize1 + 1
|
||||
|
||||
// exponent
|
||||
Esize = Fsize - Msize1
|
||||
Ebias = 1<<(Esize-1) - 1
|
||||
Emin = 1 - Ebias
|
||||
Emax = Ebias
|
||||
)
|
||||
|
||||
// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
|
||||
alen := a.bitLen()
|
||||
if alen == 0 {
|
||||
return 0, true
|
||||
}
|
||||
blen := b.bitLen()
|
||||
if blen == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
|
||||
// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
|
||||
// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
|
||||
// This is 2 or 3 more than the float32 mantissa field width of Msize:
|
||||
// - the optional extra bit is shifted away in step 3 below.
|
||||
// - the high-order 1 is omitted in "normal" representation;
|
||||
// - the low-order 1 will be used during rounding then discarded.
|
||||
exp := alen - blen
|
||||
var a2, b2 nat
|
||||
a2 = a2.set(a)
|
||||
b2 = b2.set(b)
|
||||
if shift := Msize2 - exp; shift > 0 {
|
||||
a2 = a2.shl(a2, uint(shift))
|
||||
} else if shift < 0 {
|
||||
b2 = b2.shl(b2, uint(-shift))
|
||||
}
|
||||
|
||||
// 2. Compute quotient and remainder (q, r). NB: due to the
|
||||
// extra shift, the low-order bit of q is logically the
|
||||
// high-order bit of r.
|
||||
var q nat
|
||||
q, r := q.div(a2, a2, b2) // (recycle a2)
|
||||
mantissa := low32(q)
|
||||
haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
|
||||
|
||||
// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
|
||||
// (in effect---we accomplish this incrementally).
|
||||
if mantissa>>Msize2 == 1 {
|
||||
if mantissa&1 == 1 {
|
||||
haveRem = true
|
||||
}
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
if mantissa>>Msize1 != 1 {
|
||||
panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
|
||||
}
|
||||
|
||||
// 4. Rounding.
|
||||
if Emin-Msize <= exp && exp <= Emin {
|
||||
// Denormal case; lose 'shift' bits of precision.
|
||||
shift := uint(Emin - (exp - 1)) // [1..Esize1)
|
||||
lostbits := mantissa & (1<<shift - 1)
|
||||
haveRem = haveRem || lostbits != 0
|
||||
mantissa >>= shift
|
||||
exp = 2 - Ebias // == exp + shift
|
||||
}
|
||||
// Round q using round-half-to-even.
|
||||
exact = !haveRem
|
||||
if mantissa&1 != 0 {
|
||||
exact = false
|
||||
if haveRem || mantissa&2 != 0 {
|
||||
if mantissa++; mantissa >= 1<<Msize2 {
|
||||
// Complete rollover 11...1 => 100...0, so shift is safe
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
|
||||
|
||||
f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
|
||||
if math.IsInf(float64(f), 0) {
|
||||
exact = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// quotToFloat64 returns the non-negative float64 value
|
||||
// nearest to the quotient a/b, using round-to-even in
|
||||
// halfway cases. It does not mutate its arguments.
|
||||
// Preconditions: b is non-zero; a and b have no common factors.
|
||||
func quotToFloat64(a, b nat) (f float64, exact bool) {
|
||||
const (
|
||||
// float size in bits
|
||||
Fsize = 64
|
||||
|
||||
// mantissa
|
||||
Msize = 52
|
||||
Msize1 = Msize + 1 // incl. implicit 1
|
||||
Msize2 = Msize1 + 1
|
||||
|
||||
// exponent
|
||||
Esize = Fsize - Msize1
|
||||
Ebias = 1<<(Esize-1) - 1
|
||||
Emin = 1 - Ebias
|
||||
Emax = Ebias
|
||||
)
|
||||
|
||||
// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
|
||||
alen := a.bitLen()
|
||||
if alen == 0 {
|
||||
return 0, true
|
||||
}
|
||||
blen := b.bitLen()
|
||||
if blen == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
|
||||
// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
|
||||
// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
|
||||
// This is 2 or 3 more than the float64 mantissa field width of Msize:
|
||||
// - the optional extra bit is shifted away in step 3 below.
|
||||
// - the high-order 1 is omitted in "normal" representation;
|
||||
// - the low-order 1 will be used during rounding then discarded.
|
||||
exp := alen - blen
|
||||
var a2, b2 nat
|
||||
a2 = a2.set(a)
|
||||
b2 = b2.set(b)
|
||||
if shift := Msize2 - exp; shift > 0 {
|
||||
a2 = a2.shl(a2, uint(shift))
|
||||
} else if shift < 0 {
|
||||
b2 = b2.shl(b2, uint(-shift))
|
||||
}
|
||||
|
||||
// 2. Compute quotient and remainder (q, r). NB: due to the
|
||||
// extra shift, the low-order bit of q is logically the
|
||||
// high-order bit of r.
|
||||
var q nat
|
||||
q, r := q.div(a2, a2, b2) // (recycle a2)
|
||||
mantissa := low64(q)
|
||||
haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
|
||||
|
||||
// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
|
||||
// (in effect---we accomplish this incrementally).
|
||||
if mantissa>>Msize2 == 1 {
|
||||
if mantissa&1 == 1 {
|
||||
haveRem = true
|
||||
}
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
if mantissa>>Msize1 != 1 {
|
||||
panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
|
||||
}
|
||||
|
||||
// 4. Rounding.
|
||||
if Emin-Msize <= exp && exp <= Emin {
|
||||
// Denormal case; lose 'shift' bits of precision.
|
||||
shift := uint(Emin - (exp - 1)) // [1..Esize1)
|
||||
lostbits := mantissa & (1<<shift - 1)
|
||||
haveRem = haveRem || lostbits != 0
|
||||
mantissa >>= shift
|
||||
exp = 2 - Ebias // == exp + shift
|
||||
}
|
||||
// Round q using round-half-to-even.
|
||||
exact = !haveRem
|
||||
if mantissa&1 != 0 {
|
||||
exact = false
|
||||
if haveRem || mantissa&2 != 0 {
|
||||
if mantissa++; mantissa >= 1<<Msize2 {
|
||||
// Complete rollover 11...1 => 100...0, so shift is safe
|
||||
mantissa >>= 1
|
||||
exp++
|
||||
}
|
||||
}
|
||||
}
|
||||
mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
|
||||
|
||||
f = math.Ldexp(float64(mantissa), exp-Msize1)
|
||||
if math.IsInf(f, 0) {
|
||||
exact = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float32 returns the nearest float32 value for x and a bool indicating
|
||||
// whether f represents x exactly. If the magnitude of x is too large to
|
||||
// be represented by a float32, f is an infinity and exact is false.
|
||||
// The sign of f always matches the sign of x, even if f == 0.
|
||||
func (x *Rat) Float32() (f float32, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
}
|
||||
f, exact = quotToFloat32(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
f = -f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Float64 returns the nearest float64 value for x and a bool indicating
|
||||
// whether f represents x exactly. If the magnitude of x is too large to
|
||||
// be represented by a float64, f is an infinity and exact is false.
|
||||
// The sign of f always matches the sign of x, even if f == 0.
|
||||
func (x *Rat) Float64() (f float64, exact bool) {
|
||||
b := x.b.abs
|
||||
if len(b) == 0 {
|
||||
b = b.set(natOne) // materialize denominator
|
||||
}
|
||||
f, exact = quotToFloat64(x.a.abs, b)
|
||||
if x.a.neg {
|
||||
f = -f
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetFrac sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac(a, b *Int) *Rat {
|
||||
z.a.neg = a.neg != b.neg
|
||||
babs := b.abs
|
||||
if len(babs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
if &z.a == b || alias(z.a.abs, babs) {
|
||||
babs = nat(nil).set(babs) // make a copy
|
||||
}
|
||||
z.a.abs = z.a.abs.set(a.abs)
|
||||
z.b.abs = z.b.abs.set(babs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// SetFrac64 sets z to a/b and returns z.
|
||||
func (z *Rat) SetFrac64(a, b int64) *Rat {
|
||||
z.a.SetInt64(a)
|
||||
if b == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
if b < 0 {
|
||||
b = -b
|
||||
z.a.neg = !z.a.neg
|
||||
}
|
||||
z.b.abs = z.b.abs.setUint64(uint64(b))
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// SetInt sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) SetInt(x *Int) *Rat {
|
||||
z.a.Set(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
return z
|
||||
}
|
||||
|
||||
// SetInt64 sets z to x and returns z.
|
||||
func (z *Rat) SetInt64(x int64) *Rat {
|
||||
z.a.SetInt64(x)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
return z
|
||||
}
|
||||
|
||||
// Set sets z to x (by making a copy of x) and returns z.
|
||||
func (z *Rat) Set(x *Rat) *Rat {
|
||||
if z != x {
|
||||
z.a.Set(&x.a)
|
||||
z.b.Set(&x.b)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Abs sets z to |x| (the absolute value of x) and returns z.
|
||||
func (z *Rat) Abs(x *Rat) *Rat {
|
||||
z.Set(x)
|
||||
z.a.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
// Neg sets z to -x and returns z.
|
||||
func (z *Rat) Neg(x *Rat) *Rat {
|
||||
z.Set(x)
|
||||
z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
|
||||
return z
|
||||
}
|
||||
|
||||
// Inv sets z to 1/x and returns z.
|
||||
func (z *Rat) Inv(x *Rat) *Rat {
|
||||
if len(x.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
z.Set(x)
|
||||
a := z.b.abs
|
||||
if len(a) == 0 {
|
||||
a = a.set(natOne) // materialize numerator
|
||||
}
|
||||
b := z.a.abs
|
||||
if b.cmp(natOne) == 0 {
|
||||
b = b[:0] // normalize denominator
|
||||
}
|
||||
z.a.abs, z.b.abs = a, b // sign doesn't change
|
||||
return z
|
||||
}
|
||||
|
||||
// Sign returns:
|
||||
//
|
||||
// -1 if x < 0
|
||||
// 0 if x == 0
|
||||
// +1 if x > 0
|
||||
//
|
||||
func (x *Rat) Sign() int {
|
||||
return x.a.Sign()
|
||||
}
|
||||
|
||||
// IsInt reports whether the denominator of x is 1.
|
||||
func (x *Rat) IsInt() bool {
|
||||
return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
|
||||
}
|
||||
|
||||
// Num returns the numerator of x; it may be <= 0.
|
||||
// The result is a reference to x's numerator; it
|
||||
// may change if a new value is assigned to x, and vice versa.
|
||||
// The sign of the numerator corresponds to the sign of x.
|
||||
func (x *Rat) Num() *Int {
|
||||
return &x.a
|
||||
}
|
||||
|
||||
// Denom returns the denominator of x; it is always > 0.
|
||||
// The result is a reference to x's denominator; it
|
||||
// may change if a new value is assigned to x, and vice versa.
|
||||
func (x *Rat) Denom() *Int {
|
||||
x.b.neg = false // the result is always >= 0
|
||||
if len(x.b.abs) == 0 {
|
||||
x.b.abs = x.b.abs.set(natOne) // materialize denominator
|
||||
}
|
||||
return &x.b
|
||||
}
|
||||
|
||||
func (z *Rat) norm() *Rat {
|
||||
switch {
|
||||
case len(z.a.abs) == 0:
|
||||
// z == 0 - normalize sign and denominator
|
||||
z.a.neg = false
|
||||
z.b.abs = z.b.abs[:0]
|
||||
case len(z.b.abs) == 0:
|
||||
// z is normalized int - nothing to do
|
||||
case z.b.abs.cmp(natOne) == 0:
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
default:
|
||||
neg := z.a.neg
|
||||
z.a.neg = false
|
||||
z.b.neg = false
|
||||
if f := NewInt(0).lehmerGCD(&z.a, &z.b); f.Cmp(intOne) != 0 {
|
||||
z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
|
||||
z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
|
||||
if z.b.abs.cmp(natOne) == 0 {
|
||||
// z is int - normalize denominator
|
||||
z.b.abs = z.b.abs[:0]
|
||||
}
|
||||
}
|
||||
z.a.neg = neg
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// mulDenom sets z to the denominator product x*y (by taking into
|
||||
// account that 0 values for x or y must be interpreted as 1) and
|
||||
// returns z.
|
||||
func mulDenom(z, x, y nat) nat {
|
||||
switch {
|
||||
case len(x) == 0:
|
||||
return z.set(y)
|
||||
case len(y) == 0:
|
||||
return z.set(x)
|
||||
}
|
||||
return z.mul(x, y)
|
||||
}
|
||||
|
||||
// scaleDenom computes x*f.
|
||||
// If f == 0 (zero value of denominator), the result is (a copy of) x.
|
||||
func scaleDenom(x *Int, f nat) *Int {
|
||||
var z Int
|
||||
if len(f) == 0 {
|
||||
return z.Set(x)
|
||||
}
|
||||
z.abs = z.abs.mul(x.abs, f)
|
||||
z.neg = x.neg
|
||||
return &z
|
||||
}
|
||||
|
||||
// Cmp compares x and y and returns:
|
||||
//
|
||||
// -1 if x < y
|
||||
// 0 if x == y
|
||||
// +1 if x > y
|
||||
//
|
||||
func (x *Rat) Cmp(y *Rat) int {
|
||||
return scaleDenom(&x.a, y.b.abs).Cmp(scaleDenom(&y.a, x.b.abs))
|
||||
}
|
||||
|
||||
// Add sets z to the sum x+y and returns z.
|
||||
func (z *Rat) Add(x, y *Rat) *Rat {
|
||||
a1 := scaleDenom(&x.a, y.b.abs)
|
||||
a2 := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.Add(a1, a2)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Sub sets z to the difference x-y and returns z.
|
||||
func (z *Rat) Sub(x, y *Rat) *Rat {
|
||||
a1 := scaleDenom(&x.a, y.b.abs)
|
||||
a2 := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.Sub(a1, a2)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Mul sets z to the product x*y and returns z.
|
||||
func (z *Rat) Mul(x, y *Rat) *Rat {
|
||||
if x == y {
|
||||
// a squared Rat is positive and can't be reduced
|
||||
z.a.neg = false
|
||||
z.a.abs = z.a.abs.sqr(x.a.abs)
|
||||
z.b.abs = z.b.abs.sqr(x.b.abs)
|
||||
return z
|
||||
}
|
||||
z.a.Mul(&x.a, &y.a)
|
||||
z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
|
||||
return z.norm()
|
||||
}
|
||||
|
||||
// Quo sets z to the quotient x/y and returns z.
|
||||
// If y == 0, a division-by-zero run-time panic occurs.
|
||||
func (z *Rat) Quo(x, y *Rat) *Rat {
|
||||
if len(y.a.abs) == 0 {
|
||||
panic("division by zero")
|
||||
}
|
||||
a := scaleDenom(&x.a, y.b.abs)
|
||||
b := scaleDenom(&y.a, x.b.abs)
|
||||
z.a.abs = a.abs
|
||||
z.b.abs = b.abs
|
||||
z.a.neg = a.neg != b.neg
|
||||
return z.norm()
|
||||
}
|
|
@ -1,283 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements rat-to-string conversion functions.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ratTok(ch rune) bool {
|
||||
return strings.ContainsRune("+-/0123456789.eE", ch)
|
||||
}
|
||||
|
||||
var ratZero Rat
|
||||
var _ fmt.Scanner = &ratZero // *Rat must implement fmt.Scanner
|
||||
|
||||
// Scan is a support routine for fmt.Scanner. It accepts the formats
|
||||
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
|
||||
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
|
||||
tok, err := s.Token(true, ratTok)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.ContainsRune("efgEFGv", ch) {
|
||||
return errors.New("Rat.Scan: invalid verb")
|
||||
}
|
||||
if _, ok := z.SetString(string(tok)); !ok {
|
||||
return errors.New("Rat.Scan: invalid syntax")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetString sets z to the value of s and returns z and a boolean indicating
|
||||
// success. s can be given as a fraction "a/b" or as a floating-point number
|
||||
// optionally followed by an exponent. The entire string (not just a prefix)
|
||||
// must be valid for success. If the operation failed, the value of z is
|
||||
// undefined but the returned value is nil.
|
||||
func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
if len(s) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
// len(s) > 0
|
||||
|
||||
// parse fraction a/b, if any
|
||||
if sep := strings.Index(s, "/"); sep >= 0 {
|
||||
if _, ok := z.a.SetString(s[:sep], 0); !ok {
|
||||
return nil, false
|
||||
}
|
||||
r := strings.NewReader(s[sep+1:])
|
||||
var err error
|
||||
if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil {
|
||||
return nil, false
|
||||
}
|
||||
// entire string must have been consumed
|
||||
if _, err = r.ReadByte(); err != io.EOF {
|
||||
return nil, false
|
||||
}
|
||||
if len(z.b.abs) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
return z.norm(), true
|
||||
}
|
||||
|
||||
// parse floating-point number
|
||||
r := strings.NewReader(s)
|
||||
|
||||
// sign
|
||||
neg, err := scanSign(r)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// mantissa
|
||||
var ecorr int
|
||||
z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// exponent
|
||||
var exp int64
|
||||
exp, _, err = scanExponent(r, false)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// there should be no unread characters left
|
||||
if _, err = r.ReadByte(); err != io.EOF {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// special-case 0 (see also issue #16176)
|
||||
if len(z.a.abs) == 0 {
|
||||
return z, true
|
||||
}
|
||||
// len(z.a.abs) > 0
|
||||
|
||||
// correct exponent
|
||||
if ecorr < 0 {
|
||||
exp += int64(ecorr)
|
||||
}
|
||||
|
||||
// compute exponent power
|
||||
expabs := exp
|
||||
if expabs < 0 {
|
||||
expabs = -expabs
|
||||
}
|
||||
powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
|
||||
|
||||
// complete fraction
|
||||
if exp < 0 {
|
||||
z.b.abs = powTen
|
||||
z.norm()
|
||||
} else {
|
||||
z.a.abs = z.a.abs.mul(z.a.abs, powTen)
|
||||
z.b.abs = z.b.abs[:0]
|
||||
}
|
||||
|
||||
z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
|
||||
|
||||
return z, true
|
||||
}
|
||||
|
||||
// scanExponent scans the longest possible prefix of r representing a decimal
|
||||
// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
|
||||
// exponent base (10 or 2), or a read or syntax error, if any.
|
||||
//
|
||||
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
|
||||
// sign = "+" | "-" .
|
||||
// digits = digit { digit } .
|
||||
// digit = "0" ... "9" .
|
||||
//
|
||||
// A binary exponent is only permitted if binExpOk is set.
|
||||
func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
|
||||
base = 10
|
||||
|
||||
var ch byte
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil // no exponent; same as e0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch ch {
|
||||
case 'e', 'E':
|
||||
// ok
|
||||
case 'p':
|
||||
if binExpOk {
|
||||
base = 2
|
||||
break // ok
|
||||
}
|
||||
fallthrough // binary exponent not permitted
|
||||
default:
|
||||
r.UnreadByte()
|
||||
return // no exponent; same as e0
|
||||
}
|
||||
|
||||
var neg bool
|
||||
if neg, err = scanSign(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var digits []byte
|
||||
if neg {
|
||||
digits = append(digits, '-')
|
||||
}
|
||||
|
||||
// no need to use nat.scan for exponent digits
|
||||
// since we only care about int64 values - the
|
||||
// from-scratch scan is easy enough and faster
|
||||
for i := 0; ; i++ {
|
||||
if ch, err = r.ReadByte(); err != nil {
|
||||
if err != io.EOF || i == 0 {
|
||||
return
|
||||
}
|
||||
err = nil
|
||||
break // i > 0
|
||||
}
|
||||
if ch < '0' || '9' < ch {
|
||||
if i == 0 {
|
||||
r.UnreadByte()
|
||||
err = fmt.Errorf("invalid exponent (missing digits)")
|
||||
return
|
||||
}
|
||||
break // i > 0
|
||||
}
|
||||
digits = append(digits, ch)
|
||||
}
|
||||
// i > 0 => we have at least one digit
|
||||
|
||||
exp, err = strconv.ParseInt(string(digits), 10, 64)
|
||||
return
|
||||
}
|
||||
|
||||
// String returns a string representation of x in the form "a/b" (even if b == 1).
|
||||
func (x *Rat) String() string {
|
||||
return string(x.marshal())
|
||||
}
|
||||
|
||||
// marshal implements String returning a slice of bytes
|
||||
func (x *Rat) marshal() []byte {
|
||||
var buf []byte
|
||||
buf = x.a.Append(buf, 10)
|
||||
buf = append(buf, '/')
|
||||
if len(x.b.abs) != 0 {
|
||||
buf = x.b.Append(buf, 10)
|
||||
} else {
|
||||
buf = append(buf, '1')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// RatString returns a string representation of x in the form "a/b" if b != 1,
|
||||
// and in the form "a" if b == 1.
|
||||
func (x *Rat) RatString() string {
|
||||
if x.IsInt() {
|
||||
return x.a.String()
|
||||
}
|
||||
return x.String()
|
||||
}
|
||||
|
||||
// FloatString returns a string representation of x in decimal form with prec
|
||||
// digits of precision after the decimal point. The last digit is rounded to
|
||||
// nearest, with halves rounded away from zero.
|
||||
func (x *Rat) FloatString(prec int) string {
|
||||
var buf []byte
|
||||
|
||||
if x.IsInt() {
|
||||
buf = x.a.Append(buf, 10)
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
for i := prec; i > 0; i-- {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
// x.b.abs != 0
|
||||
|
||||
q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
|
||||
|
||||
p := natOne
|
||||
if prec > 0 {
|
||||
p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
|
||||
}
|
||||
|
||||
r = r.mul(r, p)
|
||||
r, r2 := r.div(nat(nil), r, x.b.abs)
|
||||
|
||||
// see if we need to round up
|
||||
r2 = r2.add(r2, r2)
|
||||
if x.b.abs.cmp(r2) <= 0 {
|
||||
r = r.add(r, natOne)
|
||||
if r.cmp(p) >= 0 {
|
||||
q = nat(nil).add(q, natOne)
|
||||
r = nat(nil).sub(r, p)
|
||||
}
|
||||
}
|
||||
|
||||
if x.a.neg {
|
||||
buf = append(buf, '-')
|
||||
}
|
||||
buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
|
||||
|
||||
if prec > 0 {
|
||||
buf = append(buf, '.')
|
||||
rs := r.utoa(10)
|
||||
for i := prec - len(rs); i > 0; i-- {
|
||||
buf = append(buf, '0')
|
||||
}
|
||||
buf = append(buf, rs...)
|
||||
}
|
||||
|
||||
return string(buf)
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// This file implements encoding/decoding of Rats.
|
||||
|
||||
package big
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Gob codec version. Permits backward-compatible changes to the encoding.
|
||||
const ratGobVersion byte = 1
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (x *Rat) GobEncode() ([]byte, error) {
|
||||
if x == nil {
|
||||
return nil, nil
|
||||
}
|
||||
buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
|
||||
i := x.b.abs.bytes(buf)
|
||||
j := x.a.abs.bytes(buf[:i])
|
||||
n := i - j
|
||||
if int(uint32(n)) != n {
|
||||
// this should never happen
|
||||
return nil, errors.New("Rat.GobEncode: numerator too large")
|
||||
}
|
||||
binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
|
||||
j -= 1 + 4
|
||||
b := ratGobVersion << 1 // make space for sign bit
|
||||
if x.a.neg {
|
||||
b |= 1
|
||||
}
|
||||
buf[j] = b
|
||||
return buf[j:], nil
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (z *Rat) GobDecode(buf []byte) error {
|
||||
if len(buf) == 0 {
|
||||
// Other side sent a nil or default value.
|
||||
*z = Rat{}
|
||||
return nil
|
||||
}
|
||||
b := buf[0]
|
||||
if b>>1 != ratGobVersion {
|
||||
return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
|
||||
}
|
||||
const j = 1 + 4
|
||||
i := j + binary.BigEndian.Uint32(buf[j-4:j])
|
||||
z.a.neg = b&1 != 0
|
||||
z.a.abs = z.a.abs.setBytes(buf[j:i])
|
||||
z.b.abs = z.b.abs.setBytes(buf[i:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (x *Rat) MarshalText() (text []byte, err error) {
|
||||
if x.IsInt() {
|
||||
return x.a.MarshalText()
|
||||
}
|
||||
return x.marshal(), nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (z *Rat) UnmarshalText(text []byte) error {
|
||||
// TODO(gri): get rid of the []byte/string conversion
|
||||
if _, ok := z.SetString(string(text)); !ok {
|
||||
return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// generated by stringer -type=RoundingMode; DO NOT EDIT
|
||||
|
||||
package big
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf"
|
||||
|
||||
var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70}
|
||||
|
||||
func (i RoundingMode) String() string {
|
||||
if i+1 >= RoundingMode(len(_RoundingMode_index)) {
|
||||
return fmt.Sprintf("RoundingMode(%d)", i)
|
||||
}
|
||||
return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// Copyright 2017 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 big
|
||||
|
||||
import "math"
|
||||
|
||||
var (
|
||||
half = NewFloat(0.5)
|
||||
two = NewFloat(2.0)
|
||||
three = NewFloat(3.0)
|
||||
)
|
||||
|
||||
// Sqrt sets z to the rounded square root of x, and returns it.
|
||||
//
|
||||
// If z's precision is 0, it is changed to x's precision before the
|
||||
// operation. Rounding is performed according to z's precision and
|
||||
// rounding mode.
|
||||
//
|
||||
// The function panics if z < 0. The value of z is undefined in that
|
||||
// case.
|
||||
func (z *Float) Sqrt(x *Float) *Float {
|
||||
if debugFloat {
|
||||
x.validate()
|
||||
}
|
||||
|
||||
if z.prec == 0 {
|
||||
z.prec = x.prec
|
||||
}
|
||||
|
||||
if x.Sign() == -1 {
|
||||
// following IEEE754-2008 (section 7.2)
|
||||
panic(ErrNaN{"square root of negative operand"})
|
||||
}
|
||||
|
||||
// handle ±0 and +∞
|
||||
if x.form != finite {
|
||||
z.acc = Exact
|
||||
z.form = x.form
|
||||
z.neg = x.neg // IEEE754-2008 requires √±0 = ±0
|
||||
return z
|
||||
}
|
||||
|
||||
// MantExp sets the argument's precision to the receiver's, and
|
||||
// when z.prec > x.prec this will lower z.prec. Restore it after
|
||||
// the MantExp call.
|
||||
prec := z.prec
|
||||
b := x.MantExp(z)
|
||||
z.prec = prec
|
||||
|
||||
// Compute √(z·2**b) as
|
||||
// √( z)·2**(½b) if b is even
|
||||
// √(2z)·2**(⌊½b⌋) if b > 0 is odd
|
||||
// √(½z)·2**(⌈½b⌉) if b < 0 is odd
|
||||
switch b % 2 {
|
||||
case 0:
|
||||
// nothing to do
|
||||
case 1:
|
||||
z.Mul(two, z)
|
||||
case -1:
|
||||
z.Mul(half, z)
|
||||
}
|
||||
// 0.25 <= z < 2.0
|
||||
|
||||
// Solving x² - z = 0 directly requires a Quo call, but it's
|
||||
// faster for small precisions.
|
||||
//
|
||||
// Solving 1/x² - z = 0 avoids the Quo call and is much faster for
|
||||
// high precisions.
|
||||
//
|
||||
// 128bit precision is an empirically chosen threshold.
|
||||
if z.prec <= 128 {
|
||||
z.sqrtDirect(z)
|
||||
} else {
|
||||
z.sqrtInverse(z)
|
||||
}
|
||||
|
||||
// re-attach halved exponent
|
||||
return z.SetMantExp(z, b/2)
|
||||
}
|
||||
|
||||
// Compute √x (up to prec 128) by solving
|
||||
// t² - x = 0
|
||||
// for t, starting with a 53 bits precision guess from math.Sqrt and
|
||||
// then using at most two iterations of Newton's method.
|
||||
func (z *Float) sqrtDirect(x *Float) {
|
||||
// let
|
||||
// f(t) = t² - x
|
||||
// then
|
||||
// g(t) = f(t)/f'(t) = ½(t² - x)/t
|
||||
// and the next guess is given by
|
||||
// t2 = t - g(t) = ½(t² + x)/t
|
||||
u := new(Float)
|
||||
ng := func(t *Float) *Float {
|
||||
u.prec = t.prec
|
||||
u.Mul(t, t) // u = t²
|
||||
u.Add(u, x) // = t² + x
|
||||
u.Mul(half, u) // = ½(t² + x)
|
||||
return t.Quo(u, t) // = ½(t² + x)/t
|
||||
}
|
||||
|
||||
xf, _ := x.Float64()
|
||||
sq := NewFloat(math.Sqrt(xf))
|
||||
|
||||
switch {
|
||||
case z.prec > 128:
|
||||
panic("sqrtDirect: only for z.prec <= 128")
|
||||
case z.prec > 64:
|
||||
sq.prec *= 2
|
||||
sq = ng(sq)
|
||||
fallthrough
|
||||
default:
|
||||
sq.prec *= 2
|
||||
sq = ng(sq)
|
||||
}
|
||||
|
||||
z.Set(sq)
|
||||
}
|
||||
|
||||
// Compute √x (to z.prec precision) by solving
|
||||
// 1/t² - x = 0
|
||||
// for t (using Newton's method), and then inverting.
|
||||
func (z *Float) sqrtInverse(x *Float) {
|
||||
// let
|
||||
// f(t) = 1/t² - x
|
||||
// then
|
||||
// g(t) = f(t)/f'(t) = -½t(1 - xt²)
|
||||
// and the next guess is given by
|
||||
// t2 = t - g(t) = ½t(3 - xt²)
|
||||
u := new(Float)
|
||||
ng := func(t *Float) *Float {
|
||||
u.prec = t.prec
|
||||
u.Mul(t, t) // u = t²
|
||||
u.Mul(x, u) // = xt²
|
||||
u.Sub(three, u) // = 3 - xt²
|
||||
u.Mul(t, u) // = t(3 - xt²)
|
||||
return t.Mul(half, u) // = ½t(3 - xt²)
|
||||
}
|
||||
|
||||
xf, _ := x.Float64()
|
||||
sqi := NewFloat(1 / math.Sqrt(xf))
|
||||
for prec := z.prec + 32; sqi.prec < prec; {
|
||||
sqi.prec *= 2
|
||||
sqi = ng(sqi)
|
||||
}
|
||||
// sqi = 1/√x
|
||||
|
||||
// x/√x = √x
|
||||
z.Mul(x, sqi)
|
||||
}
|
|
@ -1170,12 +1170,6 @@
|
|||
"revision": "0fb14efe8c47ae851c0034ed7a448854d3d34cf3",
|
||||
"revisionTime": "2018-02-01T23:52:37Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "lRuxdDhw4Qt9aKXpHzdRInP+jVg=",
|
||||
"path": "github.com/hashicorp/golang-math-big/big",
|
||||
"revision": "561262b71329a2a771294d66accacab6b598b37b",
|
||||
"revisionTime": "2018-03-16T14:22:57Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "HtpYAWHvd9mq+mHkpo7z8PGzMik=",
|
||||
"path": "github.com/hashicorp/hcl",
|
||||
|
|
Loading…
Reference in New Issue