/base/ryu/exp.jl
https://github.com/JuliaLang/julia · Julia · 236 lines · 232 code · 3 blank · 1 comment · 55 complexity · cc8788f48b9f6717da148abefc6f4332 MD5 · raw file
- function writeexp(buf, pos, v::T,
- precision=-1, plus=false, space=false, hash=false,
- expchar=UInt8('e'), decchar=UInt8('.'), trimtrailingzeros=false) where {T <: Base.IEEEFloat}
- @assert 0 < pos <= length(buf)
- startpos = pos
- x = Float64(v)
- pos = append_sign(x, plus, space, buf, pos)
- # special cases
- if x == 0
- buf[pos] = UInt8('0')
- pos += 1
- if precision > 0 && !trimtrailingzeros
- buf[pos] = decchar
- pos += 1
- for _ = 1:precision
- buf[pos] = UInt8('0')
- pos += 1
- end
- elseif hash
- buf[pos] = decchar
- pos += 1
- end
- buf[pos] = expchar
- buf[pos + 1] = UInt8('+')
- buf[pos + 2] = UInt8('0')
- buf[pos + 3] = UInt8('0')
- return pos + 4
- elseif isnan(x)
- buf[pos] = UInt8('N')
- buf[pos + 1] = UInt8('a')
- buf[pos + 2] = UInt8('N')
- return pos + 3
- elseif !isfinite(x)
- buf[pos] = UInt8('I')
- buf[pos + 1] = UInt8('n')
- buf[pos + 2] = UInt8('f')
- return pos + 3
- end
- bits = Core.bitcast(UInt64, x)
- mant = bits & MANTISSA_MASK
- exp = Int((bits >> 52) & EXP_MASK)
- if exp == 0
- e2 = 1 - 1023 - 52
- m2 = mant
- else
- e2 = exp - 1023 - 52
- m2 = (Int64(1) << 52) | mant
- end
- nonzero = false
- precision += 1
- digits = 0
- printedDigits = 0
- availableDigits = 0
- e = 0
- if e2 >= -52
- idx = e2 < 0 ? 0 : indexforexp(e2)
- p10bits = pow10bitsforindex(idx)
- len = lengthforindex(idx)
- i = len - 1
- while i >= 0
- j = p10bits - e2
- #=@inbounds=# mula, mulb, mulc = POW10_SPLIT[POW10_OFFSET[idx + 1] + i + 1]
- digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
- if printedDigits != 0
- if printedDigits + 9 > precision
- availableDigits = 9
- break
- end
- pos = append_nine_digits(digits, buf, pos)
- printedDigits += 9
- elseif digits != 0
- availableDigits = decimallength(digits)
- e = i * 9 + availableDigits - 1
- if availableDigits > precision
- break
- end
- if precision > 1
- pos = append_d_digits(availableDigits, digits, buf, pos, decchar)
- else
- buf[pos] = UInt8('0') + digits
- pos += 1
- if hash
- buf[pos] = decchar
- pos += 1
- end
- end
- printedDigits = availableDigits
- availableDigits = 0
- end
- i -= 1
- end
- end
- if e2 < 0 && availableDigits == 0
- idx = div(-e2, 16)
- i = MIN_BLOCK_2[idx + 1]
- while i < 200
- j = 120 + (-e2 - 16 * idx)
- p = POW10_OFFSET_2[idx + 1] + i - MIN_BLOCK_2[idx + 1]
- if p >= POW10_OFFSET_2[idx + 2]
- digits = 0
- else
- #=@inbounds=# mula, mulb, mulc = POW10_SPLIT_2[p + 1]
- digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
- end
- if printedDigits != 0
- if printedDigits + 9 > precision
- availableDigits = 9
- break
- end
- pos = append_nine_digits(digits, buf, pos)
- printedDigits += 9
- elseif digits != 0
- availableDigits = decimallength(digits)
- e = -(i + 1) * 9 + availableDigits - 1
- if availableDigits > precision
- break
- end
- if precision > 1
- pos = append_d_digits(availableDigits, digits, buf, pos, decchar)
- else
- buf[pos] = UInt8('0') + digits
- pos += 1
- if hash
- buf[pos] = decchar
- pos += 1
- end
- end
- printedDigits = availableDigits
- availableDigits = 0
- end
- i += 1
- end
- end
- maximum = precision - printedDigits
- if availableDigits == 0
- digits = 0
- end
- lastDigit = 0
- if availableDigits > maximum
- for k = 0:(availableDigits - maximum - 1)
- lastDigit = digits % 10
- digits = div(digits, 10)
- end
- end
- roundUp = 0
- if lastDigit != 5
- roundUp = lastDigit > 5
- else
- rexp = precision - e
- requiredTwos = -e2 - rexp
- trailingZeros = requiredTwos <= 0 ||
- (requiredTwos < 60 && pow2(m2, requiredTwos))
- if rexp < 0
- requiredFives = -rexp
- trailingZeros = trailingZeros & pow5(m2, requiredFives)
- end
- roundUp = trailingZeros ? 2 : 1
- end
- if printedDigits != 0
- if digits == 0
- for _ = 1:maximum
- buf[pos] = UInt8('0')
- pos += 1
- end
- else
- pos = append_c_digits(maximum, digits, buf, pos)
- end
- else
- if precision > 1
- pos = append_d_digits(maximum, digits, buf, pos, decchar)
- else
- buf[pos] = UInt8('0') + digits
- pos += 1
- if hash
- buf[pos] = decchar
- pos += 1
- end
- end
- end
- if roundUp != 0
- roundPos = pos
- while true
- roundPos -= 1
- if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-') || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
- buf[roundPos + 1] = UInt8('1')
- e += 1
- break
- end
- c = roundPos > 0 ? buf[roundPos] : 0x00
- if c == decchar
- continue
- elseif c == UInt8('9')
- buf[roundPos] = UInt8('0')
- roundUp = 1
- continue
- else
- if roundUp == 2 && UInt8(c) % 2 == 0
- break
- end
- buf[roundPos] = c + 1
- break
- end
- end
- end
- if trimtrailingzeros
- while buf[pos - 1] == UInt8('0')
- pos -= 1
- end
- if buf[pos - 1] == decchar && !hash
- pos -= 1
- end
- end
- buf[pos] = expchar
- pos += 1
- if e < 0
- buf[pos] = UInt8('-')
- pos += 1
- e = -e
- else
- buf[pos] = UInt8('+')
- pos += 1
- end
- if e >= 100
- c = e % 10
- unsafe_copyto!(buf, pos, DIGIT_TABLE, 2 * div(e, 10) + 1, 2)
- buf[pos + 2] = UInt8('0') + c
- pos += 3
- else
- unsafe_copyto!(buf, pos, DIGIT_TABLE, 2 * e + 1, 2)
- pos += 2
- end
- return pos
- end