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 }