| // 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 ( | |
| "errors" | |
| "fmt" | |
| "internal/byteorder" | |
| ) | |
| // Gob codec version. Permits backward-compatible changes to the encoding. | |
| const floatGobVersion byte = 1 | |
| // GobEncode implements the [encoding/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 | |
| byteorder.BEPutUint32(buf[2:], x.prec) | |
| if x.form == finite { | |
| byteorder.BEPutUint32(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 [encoding/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 len(buf) < 6 { | |
| return errors.New("Float.GobDecode: buffer too small") | |
| } | |
| 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 = byteorder.BEUint32(buf[2:]) | |
| if z.form == finite { | |
| if len(buf) < 10 { | |
| return errors.New("Float.GobDecode: buffer too small for finite form float") | |
| } | |
| z.exp = int32(byteorder.BEUint32(buf[6:])) | |
| z.mant = z.mant.setBytes(buf[10:]) | |
| } | |
| if oldPrec != 0 { | |
| z.mode = oldMode | |
| z.SetPrec(uint(oldPrec)) | |
| } | |
| if msg := z.validate0(); msg != "" { | |
| return errors.New("Float.GobDecode: " + msg) | |
| } | |
| return nil | |
| } | |
| // AppendText implements the [encoding.TextAppender] interface. | |
| // Only the [Float] value is marshaled (in full precision), other | |
| // attributes such as precision or accuracy are ignored. | |
| func (x *Float) AppendText(b []byte) ([]byte, error) { | |
| if x == nil { | |
| return append(b, "<nil>"...), nil | |
| } | |
| return x.Append(b, 'g', -1), 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) { | |
| return x.AppendText(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 | |
| } | |