github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/ftoa/internal/fast/diyfp.go (about)

     1  package fast
     2  
     3  import "math"
     4  
     5  const (
     6  	diyFpKSignificandSize        = 64
     7  	kSignificandSize             = 53
     8  	kUint64MSB            uint64 = 1 << 63
     9  
    10  	kSignificandMask = 0x000FFFFFFFFFFFFF
    11  	kHiddenBit       = 0x0010000000000000
    12  	kExponentMask    = 0x7FF0000000000000
    13  
    14  	kPhysicalSignificandSize = 52 // Excludes the hidden bit.
    15  	kExponentBias            = 0x3FF + kPhysicalSignificandSize
    16  	kDenormalExponent        = -kExponentBias + 1
    17  )
    18  
    19  type double float64
    20  
    21  type diyfp struct {
    22  	f uint64
    23  	e int
    24  }
    25  
    26  // f =- o.
    27  // The exponents of both numbers must be the same and the significand of this
    28  // must be bigger than the significand of other.
    29  // The result will not be normalized.
    30  func (f *diyfp) subtract(o diyfp) {
    31  	_DCHECK(f.e == o.e)
    32  	_DCHECK(f.f >= o.f)
    33  	f.f -= o.f
    34  }
    35  
    36  // Returns f - o
    37  // The exponents of both numbers must be the same and this must be bigger
    38  // than other. The result will not be normalized.
    39  func (f diyfp) minus(o diyfp) diyfp {
    40  	res := f
    41  	res.subtract(o)
    42  	return res
    43  }
    44  
    45  // f *= o
    46  func (f *diyfp) mul(o diyfp) {
    47  	// Simply "emulates" a 128 bit multiplication.
    48  	// However: the resulting number only contains 64 bits. The least
    49  	// significant 64 bits are only used for rounding the most significant 64
    50  	// bits.
    51  	const kM32 uint64 = 0xFFFFFFFF
    52  	a := f.f >> 32
    53  	b := f.f & kM32
    54  	c := o.f >> 32
    55  	d := o.f & kM32
    56  	ac := a * c
    57  	bc := b * c
    58  	ad := a * d
    59  	bd := b * d
    60  	tmp := (bd >> 32) + (ad & kM32) + (bc & kM32)
    61  	// By adding 1U << 31 to tmp we round the final result.
    62  	// Halfway cases will be round up.
    63  	tmp += 1 << 31
    64  	result_f := ac + (ad >> 32) + (bc >> 32) + (tmp >> 32)
    65  	f.e += o.e + 64
    66  	f.f = result_f
    67  }
    68  
    69  // Returns f * o
    70  func (f diyfp) times(o diyfp) diyfp {
    71  	res := f
    72  	res.mul(o)
    73  	return res
    74  }
    75  
    76  func (f *diyfp) _normalize() {
    77  	f_, e := f.f, f.e
    78  	// This method is mainly called for normalizing boundaries. In general
    79  	// boundaries need to be shifted by 10 bits. We thus optimize for this case.
    80  	const k10MSBits uint64 = 0x3FF << 54
    81  	for f_&k10MSBits == 0 {
    82  		f_ <<= 10
    83  		e -= 10
    84  	}
    85  	for f_&kUint64MSB == 0 {
    86  		f_ <<= 1
    87  		e--
    88  	}
    89  	f.f, f.e = f_, e
    90  }
    91  
    92  func normalizeDiyfp(f diyfp) diyfp {
    93  	res := f
    94  	res._normalize()
    95  	return res
    96  }
    97  
    98  // f must be strictly greater than 0.
    99  func (d double) toNormalizedDiyfp() diyfp {
   100  	f, e := d.sigExp()
   101  
   102  	// The current float could be a denormal.
   103  	for (f & kHiddenBit) == 0 {
   104  		f <<= 1
   105  		e--
   106  	}
   107  	// Do the final shifts in one go.
   108  	f <<= diyFpKSignificandSize - kSignificandSize
   109  	e -= diyFpKSignificandSize - kSignificandSize
   110  	return diyfp{f, e}
   111  }
   112  
   113  // Returns the two boundaries of this.
   114  // The bigger boundary (m_plus) is normalized. The lower boundary has the same
   115  // exponent as m_plus.
   116  // Precondition: the value encoded by this Double must be greater than 0.
   117  func (d double) normalizedBoundaries() (m_minus, m_plus diyfp) {
   118  	v := d.toDiyFp()
   119  	significand_is_zero := v.f == kHiddenBit
   120  	m_plus = normalizeDiyfp(diyfp{f: (v.f << 1) + 1, e: v.e - 1})
   121  	if significand_is_zero && v.e != kDenormalExponent {
   122  		// The boundary is closer. Think of v = 1000e10 and v- = 9999e9.
   123  		// Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
   124  		// at a distance of 1e8.
   125  		// The only exception is for the smallest normal: the largest denormal is
   126  		// at the same distance as its successor.
   127  		// Note: denormals have the same exponent as the smallest normals.
   128  		m_minus = diyfp{f: (v.f << 2) - 1, e: v.e - 2}
   129  	} else {
   130  		m_minus = diyfp{f: (v.f << 1) - 1, e: v.e - 1}
   131  	}
   132  	m_minus.f <<= m_minus.e - m_plus.e
   133  	m_minus.e = m_plus.e
   134  	return
   135  }
   136  
   137  func (d double) toDiyFp() diyfp {
   138  	f, e := d.sigExp()
   139  	return diyfp{f: f, e: e}
   140  }
   141  
   142  func (d double) sigExp() (significand uint64, exponent int) {
   143  	d64 := math.Float64bits(float64(d))
   144  	significand = d64 & kSignificandMask
   145  	if d64&kExponentMask != 0 { // not denormal
   146  		significand += kHiddenBit
   147  		exponent = int((d64&kExponentMask)>>kPhysicalSignificandSize) - kExponentBias
   148  	} else {
   149  		exponent = kDenormalExponent
   150  	}
   151  	return
   152  }