github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/math/big/floatmarsh.go (about) 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 "encoding/binary" 11 "fmt" 12 ) 13 14 // Gob codec version. Permits backward-compatible changes to the encoding. 15 const floatGobVersion byte = 1 16 17 // GobEncode implements the gob.GobEncoder interface. 18 // The Float value and all its attributes (precision, 19 // rounding mode, accuracy) are marshaled. 20 func (x *Float) GobEncode() ([]byte, error) { 21 if x == nil { 22 return nil, nil 23 } 24 25 // determine max. space (bytes) required for encoding 26 sz := 1 + 1 + 4 // version + mode|acc|form|neg (3+2+2+1bit) + prec 27 n := 0 // number of mantissa words 28 if x.form == finite { 29 // add space for mantissa and exponent 30 n = int((x.prec + (_W - 1)) / _W) // required mantissa length in words for given precision 31 // actual mantissa slice could be shorter (trailing 0's) or longer (unused bits): 32 // - if shorter, only encode the words present 33 // - if longer, cut off unused words when encoding in bytes 34 // (in practice, this should never happen since rounding 35 // takes care of it, but be safe and do it always) 36 if len(x.mant) < n { 37 n = len(x.mant) 38 } 39 // len(x.mant) >= n 40 sz += 4 + n*_S // exp + mant 41 } 42 buf := make([]byte, sz) 43 44 buf[0] = floatGobVersion 45 b := byte(x.mode&7)<<5 | byte((x.acc+1)&3)<<3 | byte(x.form&3)<<1 46 if x.neg { 47 b |= 1 48 } 49 buf[1] = b 50 binary.BigEndian.PutUint32(buf[2:], x.prec) 51 52 if x.form == finite { 53 binary.BigEndian.PutUint32(buf[6:], uint32(x.exp)) 54 x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words 55 } 56 57 return buf, nil 58 } 59 60 // GobDecode implements the gob.GobDecoder interface. 61 // The result is rounded per the precision and rounding mode of 62 // z unless z's precision is 0, in which case z is set exactly 63 // to the decoded value. 64 func (z *Float) GobDecode(buf []byte) error { 65 if len(buf) == 0 { 66 // Other side sent a nil or default value. 67 *z = Float{} 68 return nil 69 } 70 71 if buf[0] != floatGobVersion { 72 return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0]) 73 } 74 75 oldPrec := z.prec 76 oldMode := z.mode 77 78 b := buf[1] 79 z.mode = RoundingMode((b >> 5) & 7) 80 z.acc = Accuracy((b>>3)&3) - 1 81 z.form = form((b >> 1) & 3) 82 z.neg = b&1 != 0 83 z.prec = binary.BigEndian.Uint32(buf[2:]) 84 85 if z.form == finite { 86 z.exp = int32(binary.BigEndian.Uint32(buf[6:])) 87 z.mant = z.mant.setBytes(buf[10:]) 88 } 89 90 if oldPrec != 0 { 91 z.mode = oldMode 92 z.SetPrec(uint(oldPrec)) 93 } 94 95 return nil 96 } 97 98 // MarshalText implements the encoding.TextMarshaler interface. 99 // Only the Float value is marshaled (in full precision), other 100 // attributes such as precision or accuracy are ignored. 101 func (x *Float) MarshalText() (text []byte, err error) { 102 if x == nil { 103 return []byte("<nil>"), nil 104 } 105 var buf []byte 106 return x.Append(buf, 'g', -1), nil 107 } 108 109 // UnmarshalText implements the encoding.TextUnmarshaler interface. 110 // The result is rounded per the precision and rounding mode of z. 111 // If z's precision is 0, it is changed to 64 before rounding takes 112 // effect. 113 func (z *Float) UnmarshalText(text []byte) error { 114 // TODO(gri): get rid of the []byte/string conversion 115 _, _, err := z.Parse(string(text), 0) 116 if err != nil { 117 err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err) 118 } 119 return err 120 }