blob: 4a00177c2881d93bb903d449c6070a67b0e9db4f [file] [log] [blame]
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// This file is available under and governed by the GNU General Public
// License version 2 only, as published by the Free Software Foundation.
// However, the following notice accompanied the original version of this
// file:
//
// Copyright 2010 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.
package jdk.nashorn.internal.runtime.doubleconv;
class FixedDtoa {
// Represents a 128bit type. This class should be replaced by a native type on
// platforms that support 128bit integers.
static class UInt128 {
private static final long kMask32 = 0xFFFFFFFFL;
// Value == (high_bits_ << 64) + low_bits_
private long high_bits_;
private long low_bits_;
UInt128(final long high_bits, final long low_bits) {
this.high_bits_ = high_bits;
this.low_bits_ = low_bits;
}
void multiply(final int multiplicand) {
long accumulator;
accumulator = (low_bits_ & kMask32) * multiplicand;
long part = accumulator & kMask32;
accumulator >>>= 32;
accumulator = accumulator + (low_bits_ >>> 32) * multiplicand;
low_bits_ = (accumulator << 32) + part;
accumulator >>>= 32;
accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
part = accumulator & kMask32;
accumulator >>>= 32;
accumulator = accumulator + (high_bits_ >>> 32) * multiplicand;
high_bits_ = (accumulator << 32) + part;
assert ((accumulator >>> 32) == 0);
}
void shift(final int shift_amount) {
assert (-64 <= shift_amount && shift_amount <= 64);
if (shift_amount == 0) {
return;
} else if (shift_amount == -64) {
high_bits_ = low_bits_;
low_bits_ = 0;
} else if (shift_amount == 64) {
low_bits_ = high_bits_;
high_bits_ = 0;
} else if (shift_amount <= 0) {
high_bits_ <<= -shift_amount;
high_bits_ += low_bits_ >>> (64 + shift_amount);
low_bits_ <<= -shift_amount;
} else {
low_bits_ >>>= shift_amount;
low_bits_ += high_bits_ << (64 - shift_amount);
high_bits_ >>>= shift_amount;
}
}
// Modifies *this to *this MOD (2^power).
// Returns *this DIV (2^power).
int divModPowerOf2(final int power) {
if (power >= 64) {
final int result = (int) (high_bits_ >>> (power - 64));
high_bits_ -= (long) (result) << (power - 64);
return result;
} else {
final long part_low = low_bits_ >>> power;
final long part_high = high_bits_ << (64 - power);
final int result = (int) (part_low + part_high);
high_bits_ = 0;
low_bits_ -= part_low << power;
return result;
}
}
boolean isZero() {
return high_bits_ == 0 && low_bits_ == 0;
}
int bitAt(final int position) {
if (position >= 64) {
return (int) (high_bits_ >>> (position - 64)) & 1;
} else {
return (int) (low_bits_ >>> position) & 1;
}
}
};
static final int kDoubleSignificandSize = 53; // Includes the hidden bit.
static void fillDigits32FixedLength(int number, final int requested_length,
final DtoaBuffer buffer) {
for (int i = requested_length - 1; i >= 0; --i) {
buffer.chars[buffer.length + i] = (char) ('0' + Integer.remainderUnsigned(number, 10));
number = Integer.divideUnsigned(number, 10);
}
buffer.length += requested_length;
}
static void fillDigits32(int number, final DtoaBuffer buffer) {
int number_length = 0;
// We fill the digits in reverse order and exchange them afterwards.
while (number != 0) {
final int digit = Integer.remainderUnsigned(number, 10);
number = Integer.divideUnsigned(number, 10);
buffer.chars[buffer.length + number_length] = (char) ('0' + digit);
number_length++;
}
// Exchange the digits.
int i = buffer.length;
int j = buffer.length + number_length - 1;
while (i < j) {
final char tmp = buffer.chars[i];
buffer.chars[i] = buffer.chars[j];
buffer.chars[j] = tmp;
i++;
j--;
}
buffer.length += number_length;
}
static void fillDigits64FixedLength(long number, final DtoaBuffer buffer) {
final int kTen7 = 10000000;
// For efficiency cut the number into 3 uint32_t parts, and print those.
final int part2 = (int) Long.remainderUnsigned(number, kTen7);
number = Long.divideUnsigned(number, kTen7);
final int part1 = (int) Long.remainderUnsigned(number, kTen7);
final int part0 = (int) Long.divideUnsigned(number, kTen7);
fillDigits32FixedLength(part0, 3, buffer);
fillDigits32FixedLength(part1, 7, buffer);
fillDigits32FixedLength(part2, 7, buffer);
}
static void FillDigits64(long number, final DtoaBuffer buffer) {
final int kTen7 = 10000000;
// For efficiency cut the number into 3 uint32_t parts, and print those.
final int part2 = (int) Long.remainderUnsigned(number, kTen7);
number = Long.divideUnsigned(number, kTen7);
final int part1 = (int) Long.remainderUnsigned(number, kTen7);
final int part0 = (int) Long.divideUnsigned(number, kTen7);
if (part0 != 0) {
fillDigits32(part0, buffer);
fillDigits32FixedLength(part1, 7, buffer);
fillDigits32FixedLength(part2, 7, buffer);
} else if (part1 != 0) {
fillDigits32(part1, buffer);
fillDigits32FixedLength(part2, 7, buffer);
} else {
fillDigits32(part2, buffer);
}
}
static void roundUp(final DtoaBuffer buffer) {
// An empty buffer represents 0.
if (buffer.length == 0) {
buffer.chars[0] = '1';
buffer.decimalPoint = 1;
buffer.length = 1;
return;
}
// Round the last digit until we either have a digit that was not '9' or until
// we reached the first digit.
buffer.chars[buffer.length - 1]++;
for (int i = buffer.length - 1; i > 0; --i) {
if (buffer.chars[i] != '0' + 10) {
return;
}
buffer.chars[i] = '0';
buffer.chars[i - 1]++;
}
// If the first digit is now '0' + 10, we would need to set it to '0' and add
// a '1' in front. However we reach the first digit only if all following
// digits had been '9' before rounding up. Now all trailing digits are '0' and
// we simply switch the first digit to '1' and update the decimal-point
// (indicating that the point is now one digit to the right).
if (buffer.chars[0] == '0' + 10) {
buffer.chars[0] = '1';
buffer.decimalPoint++;
}
}
// The given fractionals number represents a fixed-point number with binary
// point at bit (-exponent).
// Preconditions:
// -128 <= exponent <= 0.
// 0 <= fractionals * 2^exponent < 1
// The buffer holds the result.
// The function will round its result. During the rounding-process digits not
// generated by this function might be updated, and the decimal-point variable
// might be updated. If this function generates the digits 99 and the buffer
// already contained "199" (thus yielding a buffer of "19999") then a
// rounding-up will change the contents of the buffer to "20000".
static void fillFractionals(long fractionals, final int exponent,
final int fractional_count, final DtoaBuffer buffer) {
assert (-128 <= exponent && exponent <= 0);
// 'fractionals' is a fixed-decimalPoint number, with binary decimalPoint at bit
// (-exponent). Inside the function the non-converted remainder of fractionals
// is a fixed-decimalPoint number, with binary decimalPoint at bit 'decimalPoint'.
if (-exponent <= 64) {
// One 64 bit number is sufficient.
assert (fractionals >>> 56 == 0);
int point = -exponent;
for (int i = 0; i < fractional_count; ++i) {
if (fractionals == 0) break;
// Instead of multiplying by 10 we multiply by 5 and adjust the point
// location. This way the fractionals variable will not overflow.
// Invariant at the beginning of the loop: fractionals < 2^point.
// Initially we have: point <= 64 and fractionals < 2^56
// After each iteration the point is decremented by one.
// Note that 5^3 = 125 < 128 = 2^7.
// Therefore three iterations of this loop will not overflow fractionals
// (even without the subtraction at the end of the loop body). At this
// time point will satisfy point <= 61 and therefore fractionals < 2^point
// and any further multiplication of fractionals by 5 will not overflow.
fractionals *= 5;
point--;
final int digit = (int) (fractionals >>> point);
assert (digit <= 9);
buffer.chars[buffer.length] = (char) ('0' + digit);
buffer.length++;
fractionals -= (long) (digit) << point;
}
// If the first bit after the point is set we have to round up.
assert (fractionals == 0 || point - 1 >= 0);
if ((fractionals != 0) && ((fractionals >>> (point - 1)) & 1) == 1) {
roundUp(buffer);
}
} else { // We need 128 bits.
assert (64 < -exponent && -exponent <= 128);
final UInt128 fractionals128 = new UInt128(fractionals, 0);
fractionals128.shift(-exponent - 64);
int point = 128;
for (int i = 0; i < fractional_count; ++i) {
if (fractionals128.isZero()) break;
// As before: instead of multiplying by 10 we multiply by 5 and adjust the
// point location.
// This multiplication will not overflow for the same reasons as before.
fractionals128.multiply(5);
point--;
final int digit = fractionals128.divModPowerOf2(point);
assert (digit <= 9);
buffer.chars[buffer.length] = (char) ('0' + digit);
buffer.length++;
}
if (fractionals128.bitAt(point - 1) == 1) {
roundUp(buffer);
}
}
}
// Removes leading and trailing zeros.
// If leading zeros are removed then the decimal point position is adjusted.
static void trimZeros(final DtoaBuffer buffer) {
while (buffer.length > 0 && buffer.chars[buffer.length - 1] == '0') {
buffer.length--;
}
int first_non_zero = 0;
while (first_non_zero < buffer.length && buffer.chars[first_non_zero] == '0') {
first_non_zero++;
}
if (first_non_zero != 0) {
for (int i = first_non_zero; i < buffer.length; ++i) {
buffer.chars[i - first_non_zero] = buffer.chars[i];
}
buffer.length -= first_non_zero;
buffer.decimalPoint -= first_non_zero;
}
}
static boolean fastFixedDtoa(final double v,
final int fractional_count,
final DtoaBuffer buffer) {
final long kMaxUInt32 = 0xFFFFFFFFL;
final long l = IeeeDouble.doubleToLong(v);
long significand = IeeeDouble.significand(l);
final int exponent = IeeeDouble.exponent(l);
// v = significand * 2^exponent (with significand a 53bit integer).
// If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
// don't know how to compute the representation. 2^73 ~= 9.5*10^21.
// If necessary this limit could probably be increased, but we don't need
// more.
if (exponent > 20) return false;
if (fractional_count > 20) return false;
// At most kDoubleSignificandSize bits of the significand are non-zero.
// Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
// bits: 0..11*..0xxx..53*..xx
if (exponent + kDoubleSignificandSize > 64) {
// The exponent must be > 11.
//
// We know that v = significand * 2^exponent.
// And the exponent > 11.
// We simplify the task by dividing v by 10^17.
// The quotient delivers the first digits, and the remainder fits into a 64
// bit number.
// Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
final long kFive17 = 0xB1A2BC2EC5L; // 5^17
long divisor = kFive17;
final int divisor_power = 17;
long dividend = significand;
final int quotient;
final long remainder;
// Let v = f * 2^e with f == significand and e == exponent.
// Then need q (quotient) and r (remainder) as follows:
// v = q * 10^17 + r
// f * 2^e = q * 10^17 + r
// f * 2^e = q * 5^17 * 2^17 + r
// If e > 17 then
// f * 2^(e-17) = q * 5^17 + r/2^17
// else
// f = q * 5^17 * 2^(17-e) + r/2^e
if (exponent > divisor_power) {
// We only allow exponents of up to 20 and therefore (17 - e) <= 3
dividend <<= exponent - divisor_power;
quotient = (int) Long.divideUnsigned(dividend, divisor);
remainder = Long.remainderUnsigned(dividend, divisor) << divisor_power;
} else {
divisor <<= divisor_power - exponent;
quotient = (int) Long.divideUnsigned(dividend, divisor);
remainder = Long.remainderUnsigned(dividend, divisor) << exponent;
}
fillDigits32(quotient, buffer);
fillDigits64FixedLength(remainder, buffer);
buffer.decimalPoint = buffer.length;
} else if (exponent >= 0) {
// 0 <= exponent <= 11
significand <<= exponent;
FillDigits64(significand, buffer);
buffer.decimalPoint = buffer.length;
} else if (exponent > -kDoubleSignificandSize) {
// We have to cut the number.
final long integrals = significand >>> -exponent;
final long fractionals = significand - (integrals << -exponent);
if (Long.compareUnsigned(integrals, kMaxUInt32) > 0) {
FillDigits64(integrals, buffer);
} else {
fillDigits32((int) (integrals), buffer);
}
buffer.decimalPoint = buffer.length;
fillFractionals(fractionals, exponent, fractional_count, buffer);
} else if (exponent < -128) {
// This configuration (with at most 20 digits) means that all digits must be
// 0.
assert (fractional_count <= 20);
buffer.reset();
buffer.decimalPoint = -fractional_count;
} else {
buffer.decimalPoint = 0;
fillFractionals(significand, exponent, fractional_count, buffer);
}
trimZeros(buffer);
if (buffer.length == 0) {
// The string is empty and the decimal_point thus has no importance. Mimick
// Gay's dtoa and and set it to -fractional_count.
buffer.decimalPoint = -fractional_count;
}
return true;
}
}