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
7package big
8
9import (
10	"errors"
11	"fmt"
12	"internal/byteorder"
13)
14
15// Gob codec version. Permits backward-compatible changes to the encoding.
16const 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.
21func (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 := make([]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.
65func (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// MarshalText implements the [encoding.TextMarshaler] interface.
110// Only the [Float] value is marshaled (in full precision), other
111// attributes such as precision or accuracy are ignored.
112func (x *Float) MarshalText() (text []byte, err error) {
113	if x == nil {
114		return []byte("<nil>"), nil
115	}
116	var buf []byte
117	return x.Append(buf, 'g', -1), nil
118}
119
120// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
121// The result is rounded per the precision and rounding mode of z.
122// If z's precision is 0, it is changed to 64 before rounding takes
123// effect.
124func (z *Float) UnmarshalText(text []byte) error {
125	// TODO(gri): get rid of the []byte/string conversion
126	_, _, err := z.Parse(string(text), 0)
127	if err != nil {
128		err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
129	}
130	return err
131}
132