Source file src/math/big/floatmarsh.go

     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 := 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.
    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  // 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.
   112  func (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.
   124  func (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  

View as plain text