// MIT License // // Copyright (c) 2017 José Santos // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. package fastprinter import ( "io" "math" ) type floatInfo struct { mantbits uint expbits uint bias int } var ( float64info = floatInfo{52, 11, -1023} floatNaN = []byte("Nan") floatNinf = []byte("-Inf") floatPinf = []byte("+Inf") pool_floatBuffer = newByteSliceBufferPool(800) ) func PrintFloat(w io.Writer, f float64) (int, error) { return PrintFloatPrecision(w, f, -1) } func PrintFloatPrecision(dst io.Writer, val float64, prec int) (int, error) { var bits uint64 var flt *floatInfo bits = math.Float64bits(val) flt = &float64info neg := bits>>(flt.expbits+flt.mantbits) != 0 exp := int(bits>>flt.mantbits) & (1< 2^(exp-mantbits), // or equivalently log2(10)*(dp-nd) > exp-mantbits. // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). minexp := flt.bias + 1 // minimum possible exponent if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { // The number is already shortest. return } // d = mant << (exp - mantbits) // Next highest floating point number is mant+1 << exp-mantbits. // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. upper := new(decimal) upper.Assign(mant*2 + 1) upper.Shift(exp - int(flt.mantbits) - 1) // d = mant << (exp - mantbits) // Next lowest floating point number is mant-1 << exp-mantbits, // unless mant-1 drops the significant bit and exp is not the minimum exp, // in which case the next lowest is mant*2-1 << exp-mantbits-1. // Either way, call it mantlo << explo-mantbits. // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. var mantlo uint64 var explo int if mant > 1< 0 { m := min(d.nd, d.dp) copy(a.bytes[i:], d.d[:m]) i += m for ; m < d.dp; m++ { a.bytes[i] = '0' i++ } } else { a.bytes[i] = '0' i++ } // fraction if prec > 0 { a.bytes[i] = '.' i++ for j := 0; j < prec; j++ { ch := byte('0') if j := d.dp + j; 0 <= j && j < d.nd { ch = d.d[j] } a.bytes[i] = ch i++ } } n, err = dst.Write(a.bytes[0:i]) pool_floatBuffer.Put(a) return } func min(a, b int) int { if a < b { return a } return b } func max(a, b int) int { if a > b { return a } return b }