github.com/tobgu/qframe@v0.4.0/internal/ryu/ryu64.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/bits"
    22  )
    23  
    24  type uint128 struct {
    25  	lo uint64
    26  	hi uint64
    27  }
    28  
    29  // dec64 is a floating decimal type representing m * 10^e.
    30  type dec64 struct {
    31  	m uint64
    32  	e int32
    33  }
    34  
    35  func (d dec64) append(b []byte, neg bool) []byte {
    36  	// Step 5: Print the decimal representation.
    37  	if neg {
    38  		b = append(b, '-')
    39  	}
    40  
    41  	out := d.m
    42  	outLen := decimalLen64(out)
    43  	bufLen := outLen
    44  	if bufLen > 1 {
    45  		bufLen++ // extra space for '.'
    46  	}
    47  
    48  	// Print the decimal digits.
    49  	n := len(b)
    50  	if cap(b)-len(b) >= bufLen {
    51  		// Avoid function call in the common case.
    52  		b = b[:len(b)+bufLen]
    53  	} else {
    54  		b = append(b, make([]byte, bufLen)...)
    55  	}
    56  
    57  	// Avoid expensive 64-bit divisions.
    58  	// We have at most 17 digits, and uint32 can store 9 digits.
    59  	// If the output doesn't fit into a uint32, cut off 8 digits
    60  	// so the rest will fit into a uint32.
    61  	var i int
    62  	if out>>32 > 0 {
    63  		var out32 uint32
    64  		out, out32 = out/1e8, uint32(out%1e8)
    65  		for ; i < 8; i++ {
    66  			b[n+outLen-i] = '0' + byte(out32%10)
    67  			out32 /= 10
    68  		}
    69  	}
    70  	out32 := uint32(out)
    71  	for ; i < outLen-1; i++ {
    72  		b[n+outLen-i] = '0' + byte(out32%10)
    73  		out32 /= 10
    74  	}
    75  	b[n] = '0' + byte(out32%10)
    76  
    77  	// Print the '.' if needed.
    78  	if outLen > 1 {
    79  		b[n+1] = '.'
    80  	}
    81  
    82  	// Print the exponent.
    83  	b = append(b, 'e')
    84  	exp := d.e + int32(outLen) - 1
    85  	if exp < 0 {
    86  		b = append(b, '-')
    87  		exp = -exp
    88  	} else {
    89  		// Unconditionally print a + here to match strconv's formatting.
    90  		b = append(b, '+')
    91  	}
    92  	// Always print at least two digits to match strconv's formatting.
    93  	d2 := exp % 10
    94  	exp /= 10
    95  	d1 := exp % 10
    96  	d0 := exp / 10
    97  	if d0 > 0 {
    98  		b = append(b, '0'+byte(d0))
    99  	}
   100  	b = append(b, '0'+byte(d1), '0'+byte(d2))
   101  
   102  	return b
   103  }
   104  
   105  func sizeSlice(b []byte, bufLen int) []byte {
   106  	if cap(b)-len(b) >= bufLen {
   107  		// Avoid function call in the common case.
   108  		return b[:len(b)+bufLen]
   109  	}
   110  
   111  	return append(b, make([]byte, bufLen)...)
   112  }
   113  
   114  func (d dec64) appendF(b []byte, neg bool) []byte {
   115  	// Step 5: Print the decimal representation.
   116  	if neg {
   117  		b = append(b, '-')
   118  	}
   119  
   120  	out := d.m
   121  	outLen := decimalLen64(out)
   122  
   123  	dE := int(d.e)
   124  	if dE >= 0 {
   125  		// XYZ
   126  		n := len(b)
   127  		b = sizeSlice(b, dE+outLen)
   128  		for i := n; i < dE+n; i++ {
   129  			b[outLen+i] = '0'
   130  		}
   131  
   132  		for i := n + outLen - 1; i >= n; i-- {
   133  			b[i] = '0' + byte(out%10)
   134  			out /= 10
   135  		}
   136  
   137  		return b
   138  	}
   139  
   140  	ePos := -dE
   141  	if ePos >= outLen {
   142  		// 0.XYZ
   143  		b := append(b, "0."...)
   144  		n := len(b)
   145  		b = sizeSlice(b, ePos)
   146  		for i := n + ePos - 1; i >= n; i-- {
   147  			b[i] = '0' + byte(out%10)
   148  			out /= 10
   149  		}
   150  
   151  		return b
   152  	}
   153  
   154  	// Y.XZ
   155  	b = sizeSlice(b, outLen+1) // + "."
   156  	n := len(b)
   157  	i := n - 1
   158  	end := i - outLen
   159  	for ; ePos > 0; i-- {
   160  		b[i] = '0' + byte(out%10)
   161  		out /= 10
   162  		ePos--
   163  	}
   164  
   165  	b[i] = '.'
   166  	i--
   167  
   168  	for ; i >= end; i-- {
   169  		b[i] = '0' + byte(out%10)
   170  		out /= 10
   171  	}
   172  
   173  	return b
   174  }
   175  
   176  func float64ToDecimalExactInt(mant, exp uint64) (d dec64, ok bool) {
   177  	e := exp - bias64
   178  	if e > mantBits64 {
   179  		return d, false
   180  	}
   181  	shift := mantBits64 - e
   182  	mant |= 1 << mantBits64 // implicit 1
   183  	d.m = mant >> shift
   184  	if d.m<<shift != mant {
   185  		return d, false
   186  	}
   187  
   188  	for d.m%10 == 0 {
   189  		d.m /= 10
   190  		d.e++
   191  	}
   192  	return d, true
   193  }
   194  
   195  func float64ToDecimal(mant, exp uint64) dec64 {
   196  	var e2 int32
   197  	var m2 uint64
   198  	if exp == 0 {
   199  		// We subtract 2 so that the bounds computation has
   200  		// 2 additional bits.
   201  		e2 = 1 - bias64 - mantBits64 - 2
   202  		m2 = mant
   203  	} else {
   204  		e2 = int32(exp) - bias64 - mantBits64 - 2
   205  		m2 = uint64(1)<<mantBits64 | mant
   206  	}
   207  	even := m2&1 == 0
   208  	acceptBounds := even
   209  
   210  	// Step 2: Determine the interval of valid decimal representations.
   211  	mv := 4 * m2
   212  	mmShift := boolToUint64(mant != 0 || exp <= 1)
   213  	// We would compute mp and mm like this:
   214  	// mp := 4 * m2 + 2;
   215  	// mm := mv - 1 - mmShift;
   216  
   217  	// Step 3: Convert to a decimal power base uing 128-bit arithmetic.
   218  	var (
   219  		vr, vp, vm        uint64
   220  		e10               int32
   221  		vmIsTrailingZeros bool
   222  		vrIsTrailingZeros bool
   223  	)
   224  	if e2 >= 0 {
   225  		// This expression is slightly faster than max(0, log10Pow2(e2) - 1).
   226  		q := log10Pow2(e2) - boolToUint32(e2 > 3)
   227  		e10 = int32(q)
   228  		k := pow5InvNumBits64 + pow5Bits(int32(q)) - 1
   229  		i := -e2 + int32(q) + k
   230  		mul := pow5InvSplit64[q]
   231  		vr = mulShift64(4*m2, mul, i)
   232  		vp = mulShift64(4*m2+2, mul, i)
   233  		vm = mulShift64(4*m2-1-mmShift, mul, i)
   234  		if q <= 21 {
   235  			// This should use q <= 22, but I think 21 is also safe.
   236  			// Smaller values may still be safe, but it's more
   237  			// difficult to reason about them. Only one of mp, mv,
   238  			// and mm can be a multiple of 5, if any.
   239  			if mv%5 == 0 {
   240  				vrIsTrailingZeros = multipleOfPowerOfFive64(mv, q)
   241  			} else if acceptBounds {
   242  				// Same as min(e2 + (^mm & 1), pow5Factor64(mm)) >= q
   243  				// <=> e2 + (^mm & 1) >= q && pow5Factor64(mm) >= q
   244  				// <=> true && pow5Factor64(mm) >= q, since e2 >= q.
   245  				vmIsTrailingZeros = multipleOfPowerOfFive64(mv-1-mmShift, q)
   246  			} else if multipleOfPowerOfFive64(mv+2, q) {
   247  				vp--
   248  			}
   249  		}
   250  	} else {
   251  		// This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
   252  		q := log10Pow5(-e2) - boolToUint32(-e2 > 1)
   253  		e10 = int32(q) + e2
   254  		i := -e2 - int32(q)
   255  		k := pow5Bits(i) - pow5NumBits64
   256  		j := int32(q) - k
   257  		mul := pow5Split64[i]
   258  		vr = mulShift64(4*m2, mul, j)
   259  		vp = mulShift64(4*m2+2, mul, j)
   260  		vm = mulShift64(4*m2-1-mmShift, mul, j)
   261  		if q <= 1 {
   262  			// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
   263  			// mv = 4 * m2, so it always has at least two trailing 0 bits.
   264  			vrIsTrailingZeros = true
   265  			if acceptBounds {
   266  				// mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1.
   267  				vmIsTrailingZeros = mmShift == 1
   268  			} else {
   269  				// mp = mv + 2, so it always has at least one trailing 0 bit.
   270  				vp--
   271  			}
   272  		} else if q < 63 { // TODO(ulfjack/cespare): Use a tighter bound here.
   273  			// We need to compute min(ntz(mv), pow5Factor64(mv) - e2) >= q - 1
   274  			// <=> ntz(mv) >= q - 1 && pow5Factor64(mv) - e2 >= q - 1
   275  			// <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q)
   276  			// <=> (mv & ((1 << (q - 1)) - 1)) == 0
   277  			// We also need to make sure that the left shift does not overflow.
   278  			vrIsTrailingZeros = multipleOfPowerOfTwo64(mv, q-1)
   279  		}
   280  	}
   281  
   282  	// Step 4: Find the shortest decimal representation
   283  	// in the interval of valid representations.
   284  	var removed int32
   285  	var lastRemovedDigit uint8
   286  	var out uint64
   287  	// On average, we remove ~2 digits.
   288  	if vmIsTrailingZeros || vrIsTrailingZeros {
   289  		// General case, which happens rarely (~0.7%).
   290  		for {
   291  			vpDiv10 := vp / 10
   292  			vmDiv10 := vm / 10
   293  			if vpDiv10 <= vmDiv10 {
   294  				break
   295  			}
   296  			vmMod10 := vm % 10
   297  			vrDiv10 := vr / 10
   298  			vrMod10 := vr % 10
   299  			vmIsTrailingZeros = vmIsTrailingZeros && vmMod10 == 0
   300  			vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0
   301  			lastRemovedDigit = uint8(vrMod10)
   302  			vr = vrDiv10
   303  			vp = vpDiv10
   304  			vm = vmDiv10
   305  			removed++
   306  		}
   307  		if vmIsTrailingZeros {
   308  			for {
   309  				vmDiv10 := vm / 10
   310  				vmMod10 := vm % 10
   311  				if vmMod10 != 0 {
   312  					break
   313  				}
   314  				vpDiv10 := vp / 10
   315  				vrDiv10 := vr / 10
   316  				vrMod10 := vr % 10
   317  				vrIsTrailingZeros = vrIsTrailingZeros && lastRemovedDigit == 0
   318  				lastRemovedDigit = uint8(vrMod10)
   319  				vr = vrDiv10
   320  				vp = vpDiv10
   321  				vm = vmDiv10
   322  				removed++
   323  			}
   324  		}
   325  		if vrIsTrailingZeros && lastRemovedDigit == 5 && vr%2 == 0 {
   326  			// Round even if the exact number is .....50..0.
   327  			lastRemovedDigit = 4
   328  		}
   329  		out = vr
   330  		// We need to take vr + 1 if vr is outside bounds
   331  		// or we need to round up.
   332  		if (vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5 {
   333  			out++
   334  		}
   335  	} else {
   336  		// Specialized for the common case (~99.3%).
   337  		// Percentages below are relative to this.
   338  		roundUp := false
   339  		for vp/100 > vm/100 {
   340  			// Optimization: remove two digits at a time (~86.2%).
   341  			roundUp = vr%100 >= 50
   342  			vr /= 100
   343  			vp /= 100
   344  			vm /= 100
   345  			removed += 2
   346  		}
   347  		// Loop iterations below (approximately), without optimization above:
   348  		// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
   349  		// Loop iterations below (approximately), with optimization above:
   350  		// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
   351  		for vp/10 > vm/10 {
   352  			roundUp = vr%10 >= 5
   353  			vr /= 10
   354  			vp /= 10
   355  			vm /= 10
   356  			removed++
   357  		}
   358  		// We need to take vr + 1 if vr is outside bounds
   359  		// or we need to round up.
   360  		out = vr + boolToUint64(vr == vm || roundUp)
   361  	}
   362  
   363  	return dec64{m: out, e: e10 + removed}
   364  }
   365  
   366  var powersOf10 = [...]uint64{
   367  	1e0,
   368  	1e1,
   369  	1e2,
   370  	1e3,
   371  	1e4,
   372  	1e5,
   373  	1e6,
   374  	1e7,
   375  	1e8,
   376  	1e9,
   377  	1e10,
   378  	1e11,
   379  	1e12,
   380  	1e13,
   381  	1e14,
   382  	1e15,
   383  	1e16,
   384  	1e17,
   385  	// We only need to find the length of at most 17 digit numbers.
   386  }
   387  
   388  func decimalLen64(u uint64) int {
   389  	// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
   390  	log2 := 64 - bits.LeadingZeros64(u) - 1
   391  	t := (log2 + 1) * 1233 >> 12
   392  	return t - boolToInt(u < powersOf10[t]) + 1
   393  }
   394  
   395  func mulShift64(m uint64, mul uint128, shift int32) uint64 {
   396  	hihi, hilo := bits.Mul64(m, mul.hi)
   397  	lohi, _ := bits.Mul64(m, mul.lo)
   398  	sum := uint128{hi: hihi, lo: lohi + hilo}
   399  	if sum.lo < lohi {
   400  		sum.hi++ // overflow
   401  	}
   402  	return shiftRight128(sum, shift-64)
   403  }
   404  
   405  func shiftRight128(v uint128, shift int32) uint64 {
   406  	// The shift value is always modulo 64.
   407  	// In the current implementation of the 64-bit version
   408  	// of Ryu, the shift value is always < 64.
   409  	// (It is in the range [2, 59].)
   410  	// Check this here in case a future change requires larger shift
   411  	// values. In this case this function needs to be adjusted.
   412  	assert(shift < 64, "shift < 64")
   413  	return (v.hi << uint64(64-shift)) | (v.lo >> uint(shift))
   414  }
   415  
   416  func pow5Factor64(v uint64) uint32 {
   417  	for n := uint32(0); ; n++ {
   418  		q, r := v/5, v%5
   419  		if r != 0 {
   420  			return n
   421  		}
   422  		v = q
   423  	}
   424  }
   425  
   426  func multipleOfPowerOfFive64(v uint64, p uint32) bool {
   427  	return pow5Factor64(v) >= p
   428  }
   429  
   430  func multipleOfPowerOfTwo64(v uint64, p uint32) bool {
   431  	return uint32(bits.TrailingZeros64(v)) >= p
   432  }