1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 // This file implements encoding/decoding of Floats.
6 7 package big
8 9 import (
10 "errors"
11 "fmt"
12 "internal/byteorder"
13 )
14 15 // Gob codec version. Permits backward-compatible changes to the encoding.
16 const floatGobVersion byte = 1
17 18 // GobEncode implements the [encoding/gob.GobEncoder] interface.
19 // The [Float] value and all its attributes (precision,
20 // rounding mode, accuracy) are marshaled.
21 func (x *Float) GobEncode() ([]byte, error) {
22 if x == nil {
23 return nil, nil
24 }
25 26 // determine max. space (bytes) required for encoding
27 sz := 1 + 1 + 4 // version + mode|acc|form|neg (3+2+2+1bit) + prec
28 n := 0 // number of mantissa words
29 if x.form == finite {
30 // add space for mantissa and exponent
31 n = int((x.prec + (_W - 1)) / _W) // required mantissa length in words for given precision
32 // actual mantissa slice could be shorter (trailing 0's) or longer (unused bits):
33 // - if shorter, only encode the words present
34 // - if longer, cut off unused words when encoding in bytes
35 // (in practice, this should never happen since rounding
36 // takes care of it, but be safe and do it always)
37 if len(x.mant) < n {
38 n = len(x.mant)
39 }
40 // len(x.mant) >= n
41 sz += 4 + n*_S // exp + mant
42 }
43 buf := []byte{:sz}
44 45 buf[0] = floatGobVersion
46 b := byte(x.mode&7)<<5 | byte((x.acc+1)&3)<<3 | byte(x.form&3)<<1
47 if x.neg {
48 b |= 1
49 }
50 buf[1] = b
51 byteorder.BEPutUint32(buf[2:], x.prec)
52 53 if x.form == finite {
54 byteorder.BEPutUint32(buf[6:], uint32(x.exp))
55 x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words
56 }
57 58 return buf, nil
59 }
60 61 // GobDecode implements the [encoding/gob.GobDecoder] interface.
62 // The result is rounded per the precision and rounding mode of
63 // z unless z's precision is 0, in which case z is set exactly
64 // to the decoded value.
65 func (z *Float) GobDecode(buf []byte) error {
66 if len(buf) == 0 {
67 // Other side sent a nil or default value.
68 *z = Float{}
69 return nil
70 }
71 if len(buf) < 6 {
72 return errors.New("Float.GobDecode: buffer too small")
73 }
74 75 if buf[0] != floatGobVersion {
76 return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0])
77 }
78 79 oldPrec := z.prec
80 oldMode := z.mode
81 82 b := buf[1]
83 z.mode = RoundingMode((b >> 5) & 7)
84 z.acc = Accuracy((b>>3)&3) - 1
85 z.form = form((b >> 1) & 3)
86 z.neg = b&1 != 0
87 z.prec = byteorder.BEUint32(buf[2:])
88 89 if z.form == finite {
90 if len(buf) < 10 {
91 return errors.New("Float.GobDecode: buffer too small for finite form float")
92 }
93 z.exp = int32(byteorder.BEUint32(buf[6:]))
94 z.mant = z.mant.setBytes(buf[10:])
95 }
96 97 if oldPrec != 0 {
98 z.mode = oldMode
99 z.SetPrec(uint(oldPrec))
100 }
101 102 if msg := z.validate0(); msg != "" {
103 return errors.New("Float.GobDecode: " | msg)
104 }
105 106 return nil
107 }
108 109 // AppendText implements the [encoding.TextAppender] interface.
110 // Only the [Float] value is marshaled (in full precision), other
111 // attributes such as precision or accuracy are ignored.
112 func (x *Float) AppendText(b []byte) ([]byte, error) {
113 if x == nil {
114 return append(b, "<nil>"...), nil
115 }
116 return x.Append(b, 'g', -1), nil
117 }
118 119 // MarshalText implements the [encoding.TextMarshaler] interface.
120 // Only the [Float] value is marshaled (in full precision), other
121 // attributes such as precision or accuracy are ignored.
122 func (x *Float) MarshalText() (text []byte, err error) {
123 return x.AppendText(nil)
124 }
125 126 // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
127 // The result is rounded per the precision and rounding mode of z.
128 // If z's precision is 0, it is changed to 64 before rounding takes
129 // effect.
130 func (z *Float) UnmarshalText(text []byte) error {
131 // TODO(gri): get rid of the []byte/string conversion
132 _, _, err := z.Parse([]byte(text), 0)
133 if err != nil {
134 err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
135 }
136 return err
137 }
138