github.com/tobgu/qframe@v0.4.0/internal/ryu/ryu32.go (about) 1 // Copyright 2018 Ulf Adams 2 // Modifications copyright 2019 Caleb Spare 3 // 4 // The contents of this file may be used under the terms of the Apache License, 5 // Version 2.0. 6 // 7 // (See accompanying file LICENSE or copy at 8 // http://www.apache.org/licenses/LICENSE-2.0) 9 // 10 // Unless required by applicable law or agreed to in writing, this software 11 // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 12 // KIND, either express or implied. 13 // 14 // The code in this file is part of a Go translation of the C code written by 15 // Ulf Adams which may be found at https://github.com/ulfjack/ryu. That source 16 // code is licensed under Apache 2.0 and this code is derivative work thereof. 17 18 package ryu 19 20 import ( 21 "math" 22 "math/bits" 23 ) 24 25 // dec32 is a floating decimal type representing m * 10^e. 26 type dec32 struct { 27 m uint32 28 e int32 29 } 30 31 func (d dec32) append(b []byte, neg bool) []byte { 32 // Step 5: Print the decimal representation. 33 if neg { 34 b = append(b, '-') 35 } 36 37 out := d.m 38 outLen := decimalLen32(out) 39 bufLen := outLen 40 if bufLen > 1 { 41 bufLen++ // extra space for '.' 42 } 43 44 // Print the decimal digits. 45 n := len(b) 46 b = append(b, make([]byte, bufLen)...) 47 for i := 0; i < outLen-1; i++ { 48 b[n+outLen-i] = '0' + byte(out%10) 49 out /= 10 50 } 51 b[n] = '0' + byte(out%10) 52 53 // Print the '.' if needed. 54 if outLen > 1 { 55 b[n+1] = '.' 56 } 57 58 // Print the exponent. 59 b = append(b, 'e') 60 exp := d.e + int32(outLen) - 1 61 if exp < 0 { 62 b = append(b, '-') 63 exp = -exp 64 } else { 65 // Unconditionally print a + here to match strconv's formatting. 66 b = append(b, '+') 67 } 68 // Always print two digits to match strconv's formatting. 69 d1 := exp % 10 70 d0 := exp / 10 71 b = append(b, '0'+byte(d0), '0'+byte(d1)) 72 73 return b 74 } 75 76 func float32ToDecimalExactInt(mant, exp uint32) (d dec32, ok bool) { 77 e := exp - bias32 78 if e > mantBits32 { 79 return d, false 80 } 81 shift := mantBits32 - e 82 mant |= 1 << mantBits32 // implicit 1 83 d.m = mant >> shift 84 if d.m<<shift != mant { 85 return d, false 86 } 87 for d.m%10 == 0 { 88 d.m /= 10 89 d.e++ 90 } 91 return d, true 92 } 93 94 func float32ToDecimal(mant, exp uint32) dec32 { 95 var e2 int32 96 var m2 uint32 97 if exp == 0 { 98 // We subtract 2 so that the bounds computation has 99 // 2 additional bits. 100 e2 = 1 - bias32 - mantBits32 - 2 101 m2 = mant 102 } else { 103 e2 = int32(exp) - bias32 - mantBits32 - 2 104 m2 = uint32(1)<<mantBits32 | mant 105 } 106 even := m2&1 == 0 107 acceptBounds := even 108 109 // Step 2: Determine the interval of valid decimal representations. 110 var ( 111 mv = 4 * m2 112 mp = 4*m2 + 2 113 mmShift = boolToUint32(mant != 0 || exp <= 1) 114 mm = 4*m2 - 1 - mmShift 115 ) 116 117 // Step 3: Convert to a decimal power base using 64-bit arithmetic. 118 var ( 119 vr, vp, vm uint32 120 e10 int32 121 vmIsTrailingZeros bool 122 vrIsTrailingZeros bool 123 lastRemovedDigit uint8 124 ) 125 if e2 >= 0 { 126 q := log10Pow2(e2) 127 e10 = int32(q) 128 k := pow5InvNumBits32 + pow5Bits(int32(q)) - 1 129 i := -e2 + int32(q) + k 130 vr = mulPow5InvDivPow2(mv, q, i) 131 vp = mulPow5InvDivPow2(mp, q, i) 132 vm = mulPow5InvDivPow2(mm, q, i) 133 if q != 0 && (vp-1)/10 <= vm/10 { 134 // We need to know one removed digit even if we are not 135 // going to loop below. We could use q = X - 1 above, 136 // except that would require 33 bits for the result, and 137 // we've found that 32-bit arithmetic is faster even on 138 // 64-bit machines. 139 l := pow5InvNumBits32 + pow5Bits(int32(q-1)) - 1 140 lastRemovedDigit = uint8(mulPow5InvDivPow2(mv, q-1, -e2+int32(q-1)+l) % 10) 141 } 142 if q <= 9 { 143 // The largest power of 5 that fits in 24 bits is 5^10, 144 // but q <= 9 seems to be safe as well. Only one of mp, 145 // mv, and mm can be a multiple of 5, if any. 146 if mv%5 == 0 { 147 vrIsTrailingZeros = multipleOfPowerOfFive32(mv, q) 148 } else if acceptBounds { 149 vmIsTrailingZeros = multipleOfPowerOfFive32(mm, q) 150 } else if multipleOfPowerOfFive32(mp, q) { 151 vp-- 152 } 153 } 154 } else { 155 q := log10Pow5(-e2) 156 e10 = int32(q) + e2 157 i := -e2 - int32(q) 158 k := pow5Bits(i) - pow5NumBits32 159 j := int32(q) - k 160 vr = mulPow5DivPow2(mv, uint32(i), j) 161 vp = mulPow5DivPow2(mp, uint32(i), j) 162 vm = mulPow5DivPow2(mm, uint32(i), j) 163 if q != 0 && (vp-1)/10 <= vm/10 { 164 j = int32(q) - 1 - (pow5Bits(i+1) - pow5NumBits32) 165 lastRemovedDigit = uint8(mulPow5DivPow2(mv, uint32(i+1), j) % 10) 166 } 167 if q <= 1 { 168 // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at 169 // least q trailing 0 bits. mv = 4 * m2, so it always 170 // has at least two trailing 0 bits. 171 vrIsTrailingZeros = true 172 if acceptBounds { 173 // mm = mv - 1 - mmShift, so it has 1 trailing 0 bit 174 // iff mmShift == 1. 175 vmIsTrailingZeros = mmShift == 1 176 } else { 177 // mp = mv + 2, so it always has at least one 178 // trailing 0 bit. 179 vp-- 180 } 181 } else if q < 31 { 182 vrIsTrailingZeros = multipleOfPowerOfTwo32(mv, q-1) 183 } 184 } 185 186 // Step 4: Find the shortest decimal representation 187 // in the interval of valid representations. 188 var removed int32 189 var out uint32 190 if vmIsTrailingZeros || vrIsTrailingZeros { 191 // General case, which happens rarely (~4.0%). 192 for vp/10 > vm/10 { 193 vmIsTrailingZeros = vmIsTrailingZeros && vm%10 == 0 194 vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 195 lastRemovedDigit = uint8(vr % 10) 196 vr /= 10 197 vp /= 10 198 vm /= 10 199 removed++ 200 } 201 if vmIsTrailingZeros { 202 for vm%10 == 0 { 203 vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0 204 lastRemovedDigit = uint8(vr % 10) 205 vr /= 10 206 vp /= 10 207 vm /= 10 208 removed++ 209 } 210 } 211 if vrIsTrailingZeros && lastRemovedDigit == 5 && vr%2 == 0 { 212 // Round even if the exact number is .....50..0. 213 lastRemovedDigit = 4 214 } 215 out = vr 216 // We need to take vr + 1 if vr is outside bounds 217 // or we need to round up. 218 if (vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5 { 219 out++ 220 } 221 } else { 222 // Specialized for the common case (~96.0%). Percentages below 223 // are relative to this. Loop iterations below (approximately): 224 // 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01% 225 for vp/10 > vm/10 { 226 lastRemovedDigit = uint8(vr % 10) 227 vr /= 10 228 vp /= 10 229 vm /= 10 230 removed++ 231 } 232 // We need to take vr + 1 if vr is outside bounds 233 // or we need to round up. 234 out = vr + boolToUint32(vr == vm || lastRemovedDigit >= 5) 235 } 236 237 return dec32{m: out, e: e10 + removed} 238 } 239 240 func decimalLen32(u uint32) int { 241 // Function precondition: u is not a 10-digit number. 242 // (9 digits are sufficient for round-tripping.) 243 // This benchmarked faster than the log2 approach used for uint64s. 244 assert(u < 1000000000, "too big") 245 switch { 246 case u >= 100000000: 247 return 9 248 case u >= 10000000: 249 return 8 250 case u >= 1000000: 251 return 7 252 case u >= 100000: 253 return 6 254 case u >= 10000: 255 return 5 256 case u >= 1000: 257 return 4 258 case u >= 100: 259 return 3 260 case u >= 10: 261 return 2 262 default: 263 return 1 264 } 265 } 266 267 func mulShift32(m uint32, mul uint64, shift int32) uint32 { 268 assert(shift > 32, "shift > 32") 269 270 hi, lo := bits.Mul64(uint64(m), mul) 271 shiftedSum := (lo >> uint(shift)) + (hi << uint(64-shift)) 272 assert(shiftedSum <= math.MaxUint32, "shiftedSum <= math.MaxUint32") 273 return uint32(shiftedSum) 274 } 275 276 func mulPow5InvDivPow2(m, q uint32, j int32) uint32 { 277 return mulShift32(m, pow5InvSplit32[q], j) 278 } 279 280 func mulPow5DivPow2(m, i uint32, j int32) uint32 { 281 return mulShift32(m, pow5Split32[i], j) 282 } 283 284 func pow5Factor32(v uint32) uint32 { 285 for n := uint32(0); ; n++ { 286 q, r := v/5, v%5 287 if r != 0 { 288 return n 289 } 290 v = q 291 } 292 } 293 294 // multipleOfPowerOfFive32 reports whether v is divisible by 5^p. 295 func multipleOfPowerOfFive32(v, p uint32) bool { 296 return pow5Factor32(v) >= p 297 } 298 299 // multipleOfPowerOfTwo32 reports whether v is divisible by 2^p. 300 func multipleOfPowerOfTwo32(v, p uint32) bool { 301 return uint32(bits.TrailingZeros32(v)) >= p 302 }