253 lines
8.2 KiB
Julia
253 lines
8.2 KiB
Julia
# This file is a part of Julia, but is derived from
|
|
# https://github.com/google/double-conversion which has the following license
|
|
#
|
|
# Copyright 2006-2014, the V8 project authors. All rights reserved.
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above
|
|
# copyright notice, this list of conditions and the following
|
|
# disclaimer in the documentation and/or other materials provided
|
|
# with the distribution.
|
|
# * Neither the name of Google Inc. nor the names of its
|
|
# contributors may be used to endorse or promote products derived
|
|
# from this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
const kDoubleSignificandSize = 53
|
|
|
|
function filldigits32fixedlength(n1,requested_len,buffer,len)
|
|
for i = (requested_len-1):-1:0
|
|
buffer[len+i] = 0x30 + n1 % 10
|
|
n1 = div(n1,10)
|
|
end
|
|
return len + requested_len
|
|
end
|
|
|
|
function filldigits32(n,buffer,len)
|
|
n_len = 0
|
|
while n != 0
|
|
digit = n % 10
|
|
n = div(n,10)
|
|
buffer[len+n_len] = 0x30 + digit
|
|
n_len += 1
|
|
end
|
|
i,j = len, len + n_len - 1
|
|
while i < j
|
|
buffer[i], buffer[j] = buffer[j], buffer[i]
|
|
i += 1
|
|
j -= 1
|
|
end
|
|
return len + n_len
|
|
end
|
|
|
|
function filldigits64fixedlength(n2,buffer,len)
|
|
kTen7 = 10000000
|
|
part2 = n2 % kTen7
|
|
n2 = div(n2,kTen7)
|
|
part0, part1 = divrem(n2,kTen7)
|
|
len = filldigits32fixedlength(part0, 3, buffer, len)
|
|
len = filldigits32fixedlength(part1, 7, buffer, len)
|
|
len = filldigits32fixedlength(part2, 7, buffer, len)
|
|
return len
|
|
end
|
|
|
|
function filldigits64(n3,buffer,len)
|
|
kTen7 = 10000000
|
|
part2 = n3 % kTen7
|
|
n3 = div(n3,kTen7)
|
|
part0, part1 = divrem(n3,kTen7)
|
|
if part0 != 0
|
|
len = filldigits32(part0, buffer, len)
|
|
len = filldigits32fixedlength(part1, 7, buffer, len)
|
|
len = filldigits32fixedlength(part2, 7, buffer, len)
|
|
elseif part1 != 0
|
|
len = filldigits32(part1, buffer, len)
|
|
len = filldigits32fixedlength(part2, 7, buffer, len)
|
|
else
|
|
len = filldigits32(part2, buffer, len)
|
|
end
|
|
return len
|
|
end
|
|
|
|
function roundup(buffer, len, decimal_point)
|
|
if len == 1
|
|
buffer[1] = 0x31
|
|
decimal_point = 1
|
|
len = 2
|
|
return len, decimal_point
|
|
end
|
|
buffer[len - 1] += 1
|
|
for i = (len-1):-1:2
|
|
buffer[i] != 0x30 + 10 && return len, decimal_point
|
|
buffer[i] = 0x30
|
|
buffer[i - 1] += 1
|
|
end
|
|
if buffer[1] == 0x30 + 10
|
|
buffer[1] = 0x31
|
|
decimal_point += 1
|
|
end
|
|
return len, decimal_point
|
|
end
|
|
|
|
function fillfractionals(fractionals, exponent,
|
|
fractional_count, buffer,
|
|
len, decimal_point)
|
|
if -exponent <= 64
|
|
point = -exponent
|
|
for i = 1:fractional_count
|
|
fractionals == 0 && break
|
|
fractionals *= 5
|
|
point -= 1
|
|
digit = fractionals >> point
|
|
buffer[len] = 0x30 + digit
|
|
len += 1
|
|
fractionals -= UInt64(digit) << point
|
|
end
|
|
if ((fractionals >> (point - 1)) & 1) == 1
|
|
len, decimal_point = roundup(buffer, len, decimal_point)
|
|
end
|
|
else
|
|
fract128 = UInt128(fractionals) << 64
|
|
fract128 = shift(fract128,-exponent - 64)
|
|
point = 128
|
|
for i = 1:fractional_count
|
|
fract128 == 0 && break
|
|
fract128 *= 5
|
|
point -= 1
|
|
digit, fract128 = divrem2(fract128,point)
|
|
buffer[len] = 0x30 + digit
|
|
len += 1
|
|
end
|
|
if bitat(fract128,point - 1) == 1
|
|
len, decimal_point = roundup(buffer, len, decimal_point)
|
|
end
|
|
end
|
|
return len, decimal_point
|
|
end
|
|
|
|
low(x) = UInt64(x&0xffffffffffffffff)
|
|
high(x) = UInt64(x >>> 64)
|
|
bitat(x::UInt128,y) = y >= 64 ? (Int32(high(x) >> (y-64)) & 1) : (Int32(low(x) >> y) & 1)
|
|
function divrem2(x,power)
|
|
h = high(x)
|
|
l = low(x)
|
|
if power >= 64
|
|
result = Int32(h >> (power - 64))
|
|
h -= UInt64(result) << (power - 64)
|
|
return result, (UInt128(h) << 64) + l
|
|
else
|
|
part_low::UInt64 = l >> power
|
|
part_high::UInt64 = h << (64 - power)
|
|
result = Int32(part_low + part_high)
|
|
return result, UInt128(l - (part_low << power))
|
|
end
|
|
end
|
|
function shift(x::UInt128,amt)
|
|
if amt == 0
|
|
return x
|
|
elseif amt == -64
|
|
return x << 64
|
|
elseif amt == 64
|
|
return x >> 64
|
|
elseif amt <= 0
|
|
h = high(x); l = low(x)
|
|
h <<= -amt
|
|
h += l >> (64 + amt)
|
|
l <<= -amt
|
|
return (UInt128(h) << 64) + l
|
|
else
|
|
h = high(x); l = low(x)
|
|
l >>= amt
|
|
l += h << (64 - amt)
|
|
h >>= amt
|
|
return (UInt128(h) << 64) + l
|
|
end
|
|
end
|
|
|
|
function trimzeros(buffer, len, decimal_point)
|
|
while len > 1 && buffer[len - 1] == 0x30
|
|
len -= 1
|
|
end
|
|
first_non_zero::Int32 = 1
|
|
while first_non_zero < len && buffer[first_non_zero] == 0x30
|
|
first_non_zero += 1
|
|
end
|
|
if first_non_zero != 1
|
|
for i = first_non_zero:(len-1)
|
|
buffer[i - first_non_zero + 1] = buffer[i]
|
|
end
|
|
len -= first_non_zero-1
|
|
decimal_point -= first_non_zero-1
|
|
end
|
|
return len, decimal_point
|
|
end
|
|
|
|
function fastfixedtoa(v,mode,fractional_count,buffer)
|
|
v = Float64(v)
|
|
significand::UInt64 = _significand(v)
|
|
exponent = _exponent(v)
|
|
exponent > 20 && return false, 0, 0
|
|
fractional_count > 20 && return false, 0, 0
|
|
len = 1
|
|
if exponent + kDoubleSignificandSize > 64
|
|
kFive17 = divisor = Int64(5)^17
|
|
divisor_power = 17
|
|
dividend = significand
|
|
if exponent > divisor_power
|
|
dividend <<= exponent - divisor_power
|
|
quotient = div(dividend,divisor)
|
|
remainder = (dividend % divisor) << divisor_power
|
|
else
|
|
divisor <<= divisor_power - exponent
|
|
quotient = div(dividend,divisor)
|
|
remainder = (dividend % divisor) << exponent
|
|
end
|
|
len = filldigits32(quotient, buffer, len)
|
|
len = filldigits64fixedlength(remainder, buffer, len)
|
|
decimal_point = len-1
|
|
elseif exponent >= 0
|
|
significand <<= exponent
|
|
len = filldigits64(significand, buffer, len)
|
|
decimal_point = len-1
|
|
elseif exponent > -kDoubleSignificandSize
|
|
integrals = significand >> -exponent
|
|
fractionals = significand - (integrals << -exponent)
|
|
if integrals > 0xFFFFFFFF
|
|
len = filldigits64(integrals,buffer,len)
|
|
else
|
|
len = filldigits32(integrals%UInt32,buffer,len)
|
|
end
|
|
decimal_point = len-1
|
|
len, decimal_point = fillfractionals(fractionals,exponent,fractional_count,
|
|
buffer,len, decimal_point)
|
|
elseif exponent < -128
|
|
len = 1
|
|
decimal_point = -fractional_count
|
|
else
|
|
decimal_point = 0
|
|
len, decimal_point = fillfractionals(significand,exponent,fractional_count,
|
|
buffer,len, decimal_point)
|
|
end
|
|
len, decimal_point = trimzeros(buffer,len,decimal_point)
|
|
buffer[len] = 0
|
|
if (len-1) == 0
|
|
decimal_point = -fractional_count
|
|
end
|
|
return true, len, decimal_point
|
|
end
|