Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
495
julia-0.6.2/share/julia/base/grisu/bignums.jl
Normal file
495
julia-0.6.2/share/julia/base/grisu/bignums.jl
Normal file
@@ -0,0 +1,495 @@
|
||||
# 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.
|
||||
|
||||
module Bignums
|
||||
|
||||
import Base: ==, <
|
||||
|
||||
export Bignum
|
||||
|
||||
const kMaxSignificantBits = 3584
|
||||
|
||||
const Chunk = UInt32
|
||||
const DoubleChunk = UInt64
|
||||
|
||||
const kChunkSize = sizeof(Chunk) * 8
|
||||
const kDoubleChunkSize = sizeof(DoubleChunk) * 8
|
||||
# With bigit size of 28 we loose some bits, but a double still fits easily
|
||||
# into two chunks, and more importantly we can use the Comba multiplication.
|
||||
const kBigitSize = 28
|
||||
const kBigitMask = Chunk((1 << kBigitSize) - 1)
|
||||
# Every instance allocates kBigitLength chunks on the stack. Bignums cannot
|
||||
# grow. There are no checks if the stack-allocated space is sufficient.
|
||||
const kBigitCapacity = div(kMaxSignificantBits, kBigitSize)
|
||||
|
||||
mutable struct Bignum
|
||||
bigits::Vector{UInt32}
|
||||
used_digits::Int32
|
||||
exponent::Int32
|
||||
function Bignum()
|
||||
bigits = Vector{UInt32}(kBigitCapacity)
|
||||
@inbounds for i = 1:kBigitCapacity
|
||||
bigits[i] = 0
|
||||
end
|
||||
new(bigits,0,0)
|
||||
end
|
||||
end
|
||||
|
||||
==(a::Bignum,b::Bignum) = compare(a,b) == 0
|
||||
<(a::Bignum,b::Bignum) = compare(a,b) < 0
|
||||
|
||||
times10!(x::Bignum) = multiplybyuint32!(x,UInt32(10))
|
||||
|
||||
plusequal(a,b,c) = pluscompare(a,b,c) == 0
|
||||
pluslessequal(a,b,c) = pluscompare(a,b,c) <= 0
|
||||
plusless(a,b,c) = pluscompare(a,b,c) < 0
|
||||
lessequal(a::Bignum,b::Bignum) = compare(a,b) <= 0
|
||||
less(a::Bignum,b::Bignum) = compare(a,b) < 0
|
||||
|
||||
bigitlength(x::Bignum) = x.used_digits + x.exponent
|
||||
|
||||
bitsize(value) = 8 * sizeof(value)
|
||||
|
||||
function zero!(x::Bignum)
|
||||
for i = 1:x.used_digits
|
||||
@inbounds x.bigits[i] = 0
|
||||
end
|
||||
x.used_digits = 0
|
||||
x.exponent = 0
|
||||
return
|
||||
end
|
||||
|
||||
function clamp!(x::Bignum)
|
||||
@inbounds while (x.used_digits > 0 && x.bigits[x.used_digits] == 0)
|
||||
x.used_digits -= 1
|
||||
end
|
||||
x.used_digits == 0 && (x.exponent = 0)
|
||||
return
|
||||
end
|
||||
|
||||
isclamped(x::Bignum) = x.used_digits == 0 || x.bigits[x.used_digits] != 0
|
||||
|
||||
function align!(x::Bignum,other::Bignum)
|
||||
@inbounds if x.exponent > other.exponent
|
||||
zero_digits = x.exponent - other.exponent
|
||||
for i = x.used_digits:-1:1
|
||||
x.bigits[i + zero_digits] = x.bigits[i]
|
||||
end
|
||||
for i = 1:zero_digits
|
||||
x.bigits[i] = 0
|
||||
end
|
||||
x.used_digits += zero_digits
|
||||
x.exponent -= zero_digits
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function bigitshiftleft!(x::Bignum,shift_amount)
|
||||
carry::UInt32 = 0
|
||||
@inbounds begin
|
||||
for i = 1:x.used_digits
|
||||
new_carry::Chunk = x.bigits[i] >> (kBigitSize - shift_amount)
|
||||
x.bigits[i] = ((x.bigits[i] << shift_amount) + carry) & kBigitMask
|
||||
carry = new_carry
|
||||
end
|
||||
if carry != 0
|
||||
x.bigits[x.used_digits+1] = carry
|
||||
x.used_digits += 1
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function subtracttimes!(x::Bignum,other::Bignum,factor)
|
||||
if factor < 3
|
||||
for i = 1:factor
|
||||
subtractbignum!(x,other)
|
||||
end
|
||||
return
|
||||
end
|
||||
borrow::Chunk = 0
|
||||
exponent_diff = other.exponent - x.exponent
|
||||
@inbounds begin
|
||||
for i = 1:other.used_digits
|
||||
product::DoubleChunk = DoubleChunk(factor) * other.bigits[i]
|
||||
remove::DoubleChunk = borrow + product
|
||||
difference::Chunk = (x.bigits[i+exponent_diff] - (remove & kBigitMask)) % Chunk
|
||||
x.bigits[i+exponent_diff] = difference & kBigitMask
|
||||
borrow = ((difference >> (kChunkSize - 1)) + (remove >> kBigitSize)) % Chunk
|
||||
end
|
||||
for i = (other.used_digits + exponent_diff + 1):x.used_digits
|
||||
borrow == 0 && return
|
||||
difference::Chunk = x.bigits[i] - borrow
|
||||
x.bigits[i] = difference & kBigitMask
|
||||
borrow = difference >> (kChunkSize - 1)
|
||||
end
|
||||
end
|
||||
clamp!(x)
|
||||
end
|
||||
|
||||
function assignuint16!(x::Bignum,value::UInt16)
|
||||
zero!(x)
|
||||
value == 0 && return
|
||||
x.bigits[1] = value
|
||||
x.used_digits = 1
|
||||
return
|
||||
end
|
||||
|
||||
const kUInt64Size = 64
|
||||
function assignuint64!(x::Bignum,value::UInt64)
|
||||
zero!(x)
|
||||
value == 0 && return
|
||||
needed_bigits = div(kUInt64Size,kBigitSize) + 1
|
||||
@inbounds for i = 1:needed_bigits
|
||||
x.bigits[i] = value & kBigitMask
|
||||
value >>= kBigitSize
|
||||
end
|
||||
x.used_digits = needed_bigits
|
||||
clamp!(x)
|
||||
end
|
||||
|
||||
function assignbignum!(x::Bignum,other::Bignum)
|
||||
x.exponent = other.exponent
|
||||
@inbounds begin
|
||||
for i = 1:other.used_digits
|
||||
x.bigits[i] = other.bigits[i]
|
||||
end
|
||||
for i = (other.used_digits+1):x.used_digits
|
||||
x.bigits[i] = 0
|
||||
end
|
||||
end
|
||||
x.used_digits = other.used_digits
|
||||
return
|
||||
end
|
||||
|
||||
function adduint64!(x::Bignum,operand::UInt64)
|
||||
operand == 0 && return
|
||||
other = Bignum()
|
||||
assignuint64!(other,operand)
|
||||
addbignum!(x,other)
|
||||
end
|
||||
|
||||
function addbignum!(x::Bignum,other::Bignum)
|
||||
align!(x,other)
|
||||
carry::Chunk = 0
|
||||
bigit_pos = other.exponent - x.exponent
|
||||
@inbounds for i = 1:other.used_digits
|
||||
sum::Chunk = x.bigits[bigit_pos+1] + other.bigits[i] + carry
|
||||
x.bigits[bigit_pos+1] = sum & kBigitMask
|
||||
carry = sum >> kBigitSize
|
||||
bigit_pos += 1
|
||||
end
|
||||
@inbounds while carry != 0
|
||||
sum = x.bigits[bigit_pos+1] + carry
|
||||
x.bigits[bigit_pos+1] = sum & kBigitMask
|
||||
carry = sum >> kBigitSize
|
||||
bigit_pos += 1
|
||||
end
|
||||
x.used_digits = max(bigit_pos,x.used_digits)
|
||||
return
|
||||
end
|
||||
|
||||
function subtractbignum!(x::Bignum,other::Bignum)
|
||||
align!(x,other)
|
||||
offset = other.exponent - x.exponent
|
||||
borrow = Chunk(0)
|
||||
@inbounds begin
|
||||
for i = 1:other.used_digits
|
||||
difference = x.bigits[i+offset] - other.bigits[i] - borrow
|
||||
x.bigits[i+offset] = difference & kBigitMask
|
||||
borrow = difference >> (kChunkSize - 1)
|
||||
end
|
||||
i = other.used_digits+1
|
||||
while borrow != 0
|
||||
difference = x.bigits[i+offset] - borrow
|
||||
x.bigits[i+offset] = difference & kBigitMask
|
||||
borrow = difference >> (kChunkSize - 1)
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
clamp!(x)
|
||||
end
|
||||
|
||||
function shiftleft!(x::Bignum,shift_amount)
|
||||
x.used_digits == 0 && return
|
||||
x.exponent += div(shift_amount,kBigitSize)
|
||||
local_shift = shift_amount % kBigitSize
|
||||
bigitshiftleft!(x,local_shift)
|
||||
end
|
||||
|
||||
function multiplybyuint32!(x::Bignum,factor::UInt32)
|
||||
factor == 1 && return
|
||||
if factor == 0
|
||||
zero!(x)
|
||||
return
|
||||
end
|
||||
x.used_digits == 0 && return
|
||||
carry::DoubleChunk = 0
|
||||
@inbounds begin
|
||||
for i = 1:x.used_digits
|
||||
product::DoubleChunk = (factor % DoubleChunk) * x.bigits[i] + carry
|
||||
x.bigits[i] = (product & kBigitMask) % Chunk
|
||||
carry = product >> kBigitSize
|
||||
end
|
||||
while carry != 0
|
||||
x.bigits[x.used_digits+1] = carry & kBigitMask
|
||||
x.used_digits += 1
|
||||
carry >>= kBigitSize
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
function multiplybyuint64!(x::Bignum,factor::UInt64)
|
||||
factor == 1 && return
|
||||
if factor == 0
|
||||
zero!(x)
|
||||
return
|
||||
end
|
||||
carry::UInt64 = 0
|
||||
low::UInt64 = factor & 0xFFFFFFFF
|
||||
high::UInt64 = factor >> 32
|
||||
@inbounds begin
|
||||
for i = 1:x.used_digits
|
||||
product_low::UInt64 = low * x.bigits[i]
|
||||
product_high::UInt64 = high * x.bigits[i]
|
||||
tmp::UInt64 = (carry & kBigitMask) + product_low
|
||||
x.bigits[i] = tmp & kBigitMask
|
||||
carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
|
||||
(product_high << (32 - kBigitSize))
|
||||
end
|
||||
while carry != 0
|
||||
x.bigits[x.used_digits+1] = carry & kBigitMask
|
||||
x.used_digits += 1
|
||||
carry >>= kBigitSize
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
const kFive27 = UInt64(0x6765c793fa10079d)
|
||||
const kFive1 = UInt16(5)
|
||||
const kFive2 = UInt16(kFive1 * 5)
|
||||
const kFive3 = UInt16(kFive2 * 5)
|
||||
const kFive4 = UInt16(kFive3 * 5)
|
||||
const kFive5 = UInt16(kFive4 * 5)
|
||||
const kFive6 = UInt16(kFive5 * 5)
|
||||
const kFive7 = UInt32(kFive6 * 5)
|
||||
const kFive8 = UInt32(kFive7 * 5)
|
||||
const kFive9 = UInt32(kFive8 * 5)
|
||||
const kFive10 = UInt32(kFive9 * 5)
|
||||
const kFive11 = UInt32(kFive10 * 5)
|
||||
const kFive12 = UInt32(kFive11 * 5)
|
||||
const kFive13 = UInt32(kFive12 * 5)
|
||||
const kFive1_to_12 = UInt32[kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
|
||||
kFive7, kFive8, kFive9, kFive10, kFive11, kFive12]
|
||||
function multiplybypoweroften!(x::Bignum,exponent)
|
||||
exponent == 0 && return
|
||||
x.used_digits == 0 && return
|
||||
remaining_exponent = exponent
|
||||
while remaining_exponent >= 27
|
||||
multiplybyuint64!(x,kFive27)
|
||||
remaining_exponent -= 27
|
||||
end
|
||||
while remaining_exponent >= 13
|
||||
multiplybyuint32!(x,kFive13)
|
||||
remaining_exponent -= 13
|
||||
end
|
||||
remaining_exponent > 0 && multiplybyuint32!(x,
|
||||
kFive1_to_12[remaining_exponent])
|
||||
shiftleft!(x,exponent)
|
||||
end
|
||||
|
||||
function square!(x::Bignum)
|
||||
product_length = 2 * x.used_digits
|
||||
(1 << (2 * (kChunkSize - kBigitSize))) <= x.used_digits && error("unimplemented")
|
||||
accumulator::DoubleChunk = 0
|
||||
copy_offset = x.used_digits
|
||||
@inbounds begin
|
||||
for i = 1:x.used_digits
|
||||
x.bigits[copy_offset + i] = x.bigits[i]
|
||||
end
|
||||
for i = 1:x.used_digits
|
||||
bigit_index1 = i-1
|
||||
bigit_index2 = 0
|
||||
while bigit_index1 >= 0
|
||||
chunk1::Chunk = x.bigits[copy_offset + bigit_index1 + 1]
|
||||
chunk2::Chunk = x.bigits[copy_offset + bigit_index2 + 1]
|
||||
accumulator += (chunk1 % DoubleChunk) * chunk2
|
||||
bigit_index1 -= 1
|
||||
bigit_index2 += 1
|
||||
end
|
||||
x.bigits[i] = (accumulator % Chunk) & kBigitMask
|
||||
accumulator >>= kBigitSize
|
||||
end
|
||||
for i = x.used_digits+1:product_length
|
||||
bigit_index1 = x.used_digits - 1
|
||||
bigit_index2 = i - bigit_index1 - 1
|
||||
while bigit_index2 < x.used_digits
|
||||
chunk1::Chunk = x.bigits[copy_offset + bigit_index1 + 1]
|
||||
chunk2::Chunk = x.bigits[copy_offset + bigit_index2 + 1]
|
||||
accumulator += (chunk1 % DoubleChunk) * chunk2
|
||||
bigit_index1 -= 1
|
||||
bigit_index2 += 1
|
||||
end
|
||||
x.bigits[i] = (accumulator % Chunk) & kBigitMask
|
||||
accumulator >>= kBigitSize
|
||||
end
|
||||
end
|
||||
x.used_digits = product_length
|
||||
x.exponent *= 2
|
||||
clamp!(x)
|
||||
end
|
||||
|
||||
function assignpoweruint16!(x::Bignum,base::UInt16,power_exponent::Int)
|
||||
if power_exponent == 0
|
||||
assignuint16!(x,UInt16(1))
|
||||
return
|
||||
end
|
||||
zero!(x)
|
||||
shifts::Int = 0
|
||||
while base & UInt16(1) == UInt16(0)
|
||||
base >>= UInt16(1)
|
||||
shifts += 1
|
||||
end
|
||||
bit_size::Int = 0
|
||||
tmp_base::Int= base
|
||||
while tmp_base != 0
|
||||
tmp_base >>= 1
|
||||
bit_size += 1
|
||||
end
|
||||
final_size = bit_size * power_exponent
|
||||
mask::Int = 1
|
||||
while power_exponent >= mask
|
||||
mask <<= 1
|
||||
end
|
||||
mask >>= 2
|
||||
this_value::UInt64 = base
|
||||
delayed_multiplication = false
|
||||
max_32bits::UInt64 = 0xFFFFFFFF
|
||||
while mask != 0 && this_value <= max_32bits
|
||||
this_value *= this_value
|
||||
if (power_exponent & mask) != 0
|
||||
base_bits_mask::UInt64 = ~(UInt64(1) << (64 - bit_size) - 1)
|
||||
high_bits_zero = (this_value & base_bits_mask) == 0
|
||||
if high_bits_zero
|
||||
this_value *= base
|
||||
else
|
||||
delayed_multiplication = true
|
||||
end
|
||||
end
|
||||
mask >>= 1
|
||||
end
|
||||
assignuint64!(x,this_value)
|
||||
delayed_multiplication && multiplybyuint32!(x,UInt32(base))
|
||||
while mask != 0
|
||||
square!(x)
|
||||
(power_exponent & mask) != 0 && multiplybyuint32!(x,UInt32(base))
|
||||
mask >>= 1
|
||||
end
|
||||
shiftleft!(x,shifts * power_exponent)
|
||||
end
|
||||
|
||||
function dividemodulointbignum!(x::Bignum,other::Bignum)
|
||||
bigitlength(x) < bigitlength(other) && return UInt16(0)
|
||||
align!(x,other)
|
||||
result::UInt16 = 0
|
||||
@inbounds begin
|
||||
while bigitlength(x) > bigitlength(other)
|
||||
result += x.bigits[x.used_digits] % UInt16
|
||||
subtracttimes!(x,other,x.bigits[x.used_digits])
|
||||
end
|
||||
this_bigit::Chunk = x.bigits[x.used_digits]
|
||||
other_bigit::Chunk = other.bigits[other.used_digits]
|
||||
if other.used_digits == 1
|
||||
quotient = reinterpret(Int32,div(this_bigit,other_bigit))
|
||||
x.bigits[x.used_digits] = this_bigit - other_bigit * reinterpret(UInt32,quotient)
|
||||
result += quotient % UInt16
|
||||
clamp!(x)
|
||||
return result
|
||||
end
|
||||
end
|
||||
division_estimate = reinterpret(Int32,div(this_bigit,other_bigit+Chunk(1)))
|
||||
result += division_estimate % UInt16
|
||||
subtracttimes!(x,other,division_estimate)
|
||||
other_bigit * (division_estimate+1) > this_bigit && return result
|
||||
while lessequal(other, x)
|
||||
subtractbignum!(x,other)
|
||||
result += UInt16(1)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function pluscompare(a::Bignum,b::Bignum,c::Bignum)
|
||||
bigitlength(a) < bigitlength(b) && return pluscompare(b,a,c)
|
||||
bigitlength(a) + 1 < bigitlength(c) && return -1
|
||||
bigitlength(a) > bigitlength(c) && return 1
|
||||
a.exponent >= bigitlength(b) && bigitlength(a) < bigitlength(c) && return -1
|
||||
borrow::Chunk = 0
|
||||
min_exponent = min(a.exponent,b.exponent,c.exponent)
|
||||
for i = (bigitlength(c)-1):-1:min_exponent
|
||||
chunk_a::Chunk = bigitat(a,i)
|
||||
chunk_b::Chunk = bigitat(b,i)
|
||||
chunk_c::Chunk = bigitat(c,i)
|
||||
sum::Chunk = chunk_a + chunk_b
|
||||
if sum > chunk_c + borrow
|
||||
return 1
|
||||
else
|
||||
borrow = chunk_c + borrow - sum
|
||||
borrow > 1 && return -1
|
||||
borrow <<= kBigitSize
|
||||
end
|
||||
end
|
||||
borrow == 0 && return 0
|
||||
return -1
|
||||
end
|
||||
|
||||
function compare(a::Bignum,b::Bignum)
|
||||
bigit_length_a = bigitlength(a)
|
||||
bigit_length_b = bigitlength(b)
|
||||
bigit_length_a < bigit_length_b && return -1
|
||||
bigit_length_a > bigit_length_b && return 1
|
||||
for i = (bigit_length_a-1):-1:min(a.exponent,b.exponent)
|
||||
bigit_a::Chunk = bigitat(a,i)
|
||||
bigit_b::Chunk = bigitat(b,i)
|
||||
bigit_a < bigit_b && return -1
|
||||
bigit_a > bigit_b && return 1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function bigitat(x::Bignum,index)
|
||||
index >= bigitlength(x) && return Chunk(0)
|
||||
index < x.exponent && return Chunk(0)
|
||||
@inbounds ret = x.bigits[index - x.exponent+1]::Chunk
|
||||
return ret
|
||||
end
|
||||
|
||||
end # module
|
||||
Reference in New Issue
Block a user