Ported harmony implementation of Double/Float <-> String

Double.toString(), Float.toString(), String.toFloat(), String.toDouble()
This commit is contained in:
Igor Chevdar
2017-05-29 11:59:16 +03:00
parent d6b8b4fb0f
commit 5a216953e2
14 changed files with 4172 additions and 47 deletions
+2
View File
@@ -42,6 +42,8 @@ void ThrowClassCastException();
void ThrowArithmeticException();
// Throws number format exception.
void ThrowNumberFormatException();
// Throws out of memory error.
void ThrowOutOfMemoryError();
#ifdef __cplusplus
} // extern "C"
-35
View File
@@ -703,33 +703,6 @@ void checkParsingErrors(const char* c_str, const char* end, std::string::size_ty
}
}
// TODO: Java Double.valueOf specification requires mandatory binary exponent character (p) in the string parsed if the string is a hex one.
// See: http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#valueOf-java.lang.String-
// E.g.
// "0x77p0".toDouble() // OK for both Kotlin/JVM and Kotlin/Native.
// "0x77".toDouble() // throws NumberFormatException in Kotlin/JVM and OK in Kotlin/Native.
// Do we need to handle such case? Or it is OK to consume such strings?
KFloat parseFloat(KString value) {
const KChar* utf16 = CharArrayAddressOfElementAt(value, 0);
std::string utf8;
utf8::utf16to8(utf16, utf16 + value->count_, back_inserter(utf8));
char* end = nullptr;
KFloat result = strtof(utf8.c_str(), &end);
checkParsingErrors(utf8.c_str(), end, utf8.size());
return result;
}
KDouble parseDouble(KString value) {
const KChar* utf16 =
CharArrayAddressOfElementAt(value, 0);
std::string utf8;
utf8::utf16to8(utf16, utf16 + value->count_, back_inserter(utf8));
char* end = nullptr;
KDouble result = strtod(utf8.c_str(), &end);
checkParsingErrors(utf8.c_str(), end, utf8.size());
return result;
}
} // namespace
extern "C" {
@@ -1172,12 +1145,4 @@ OBJ_GETTER0(Kotlin_io_Console_readLine) {
RETURN_RESULT_OF(CreateStringFromCString, data);
}
KFloat Kotlin_String_parseFloat(KString value) {
return parseFloat(value);
}
KDouble Kotlin_String_parseDouble(KString value) {
return parseDouble(value);
}
} // extern "C"
+904
View File
@@ -0,0 +1,904 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "cbigint.h"
#if defined(LINUX) || defined(FREEBSD) || defined(ZOS) || defined(MACOSX) || defined(AIX)
#define USE_LL
#endif
#ifdef HY_LITTLE_ENDIAN
#define at(i) (i)
#else
#define at(i) ((i)^1)
/* the sequence for halfAt is -1, 2, 1, 4, 3, 6, 5, 8... */
/* and it should correspond to 0, 1, 2, 3, 4, 5, 6, 7... */
#define halfAt(i) (-((-(i)) ^ 1))
#endif
#define HIGH_IN_U64(u64) ((u64) >> 32)
#if defined(USE_LL)
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFLL)
#else
#if defined(USE_L)
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFL)
#else
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFF)
#endif /* USE_L */
#endif /* USE_LL */
#if defined(USE_LL)
#define TEN_E1 (0xALL)
#define TEN_E2 (0x64LL)
#define TEN_E3 (0x3E8LL)
#define TEN_E4 (0x2710LL)
#define TEN_E5 (0x186A0LL)
#define TEN_E6 (0xF4240LL)
#define TEN_E7 (0x989680LL)
#define TEN_E8 (0x5F5E100LL)
#define TEN_E9 (0x3B9ACA00LL)
#define TEN_E19 (0x8AC7230489E80000LL)
#else
#if defined(USE_L)
#define TEN_E1 (0xAL)
#define TEN_E2 (0x64L)
#define TEN_E3 (0x3E8L)
#define TEN_E4 (0x2710L)
#define TEN_E5 (0x186A0L)
#define TEN_E6 (0xF4240L)
#define TEN_E7 (0x989680L)
#define TEN_E8 (0x5F5E100L)
#define TEN_E9 (0x3B9ACA00L)
#define TEN_E19 (0x8AC7230489E80000L)
#else
#define TEN_E1 (0xA)
#define TEN_E2 (0x64)
#define TEN_E3 (0x3E8)
#define TEN_E4 (0x2710)
#define TEN_E5 (0x186A0)
#define TEN_E6 (0xF4240)
#define TEN_E7 (0x989680)
#define TEN_E8 (0x5F5E100)
#define TEN_E9 (0x3B9ACA00)
#define TEN_E19 (0x8AC7230489E80000)
#endif /* USE_L */
#endif /* USE_LL */
#define TIMES_TEN(x) (((x) << 3) + ((x) << 1))
#define bitSection(x, mask, shift) (((x) & (mask)) >> (shift))
#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
#define CREATE_DOUBLE_BITS(normalizedM, e) (((normalizedM) & MANTISSA_MASK) | (((U_64)((e) + E_OFFSET)) << 52))
#if defined(USE_LL)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
#define EXPONENT_MASK (0x7FF0000000000000LL)
#define NORMAL_MASK (0x0010000000000000LL)
#define SIGN_MASK (0x8000000000000000LL)
#else
#if defined(USE_L)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
#define EXPONENT_MASK (0x7FF0000000000000L)
#define NORMAL_MASK (0x0010000000000000L)
#define SIGN_MASK (0x8000000000000000L)
#else
#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
#define EXPONENT_MASK (0x7FF0000000000000)
#define NORMAL_MASK (0x0010000000000000)
#define SIGN_MASK (0x8000000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define E_OFFSET (1075)
#define FLOAT_MANTISSA_MASK (0x007FFFFF)
#define FLOAT_EXPONENT_MASK (0x7F800000)
#define FLOAT_NORMAL_MASK (0x00800000)
#define FLOAT_E_OFFSET (150)
IDATA
simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
{
/* assumes length > 0 */
IDATA index = 1;
*arg1 += arg2;
if (arg2 <= *arg1)
return 0;
else if (length == 1)
return 1;
while (++arg1[index] == 0 && ++index < length);
return (IDATA) index == length;
}
IDATA
addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
/* addition is limited by length of arg1 as it this function is
* storing the result in arg1 */
/* fix for cc (GCC) 3.2 20020903 (Red Hat Linux 8.0 3.2-7): code generated does not
* do the temp1 + temp2 + carry addition correct. carry is 64 bit because gcc has
* subtle issues when you mix 64 / 32 bit maths. */
U_64 temp1, temp2, temp3; /* temporary variables to help the SH-4, and gcc */
U_64 carry;
IDATA index;
if (length1 == 0 || length2 == 0)
{
return 0;
}
else if (length1 < length2)
{
length2 = length1;
}
carry = 0;
index = 0;
do
{
temp1 = arg1[index];
temp2 = arg2[index];
temp3 = temp1 + temp2;
arg1[index] = temp3 + carry;
if (arg2[index] < arg1[index])
carry = 0;
else if (arg2[index] != arg1[index])
carry = 1;
}
while (++index < length2);
if (!carry)
return 0;
else if (index == length1)
return 1;
while (++arg1[index] == 0 && ++index < length1);
return (IDATA) index == length1;
}
void
subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
/* assumes arg1 > arg2 */
IDATA index;
for (index = 0; index < length1; ++index)
arg1[index] = ~arg1[index];
simpleAddHighPrecision (arg1, length1, 1);
while (length2 > 0 && arg2[length2 - 1] == 0)
--length2;
addHighPrecision (arg1, length1, arg2, length2);
for (index = 0; index < length1; ++index)
arg1[index] = ~arg1[index];
simpleAddHighPrecision (arg1, length1, 1);
}
U_32
simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
{
/* assumes arg2 only holds 32 bits of information */
U_64 product;
IDATA index;
index = 0;
product = 0;
do
{
product =
HIGH_IN_U64 (product) + arg2 * LOW_U32_FROM_PTR (arg1 + index);
LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
product =
HIGH_IN_U64 (product) + arg2 * HIGH_U32_FROM_PTR (arg1 + index);
HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
}
while (++index < length);
return HIGH_U32_FROM_VAR (product);
}
void
simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2,
U_32 * result)
{
/* Assumes result can hold the product and arg2 only holds 32 bits
of information */
U_64 product;
IDATA index, resultIndex;
index = resultIndex = 0;
product = 0;
do
{
product =
HIGH_IN_U64 (product) + result[at (resultIndex)] +
arg2 * LOW_U32_FROM_PTR (arg1 + index);
result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
++resultIndex;
product =
HIGH_IN_U64 (product) + result[at (resultIndex)] +
arg2 * HIGH_U32_FROM_PTR (arg1 + index);
result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
++resultIndex;
}
while (++index < length);
result[at (resultIndex)] += HIGH_U32_FROM_VAR (product);
if (result[at (resultIndex)] < HIGH_U32_FROM_VAR (product))
{
/* must be careful with ++ operator and macro expansion */
++resultIndex;
while (++result[at (resultIndex)] == 0)
++resultIndex;
}
}
#ifndef HY_LITTLE_ENDIAN
void simpleMultiplyAddHighPrecisionBigEndianFix(U_64 *arg1, IDATA length, U_64 arg2, U_32 *result) {
/* Assumes result can hold the product and arg2 only holds 32 bits
of information */
U_64 product;
IDATA index, resultIndex;
index = resultIndex = 0;
product = 0;
do {
product = HIGH_IN_U64(product) + result[halfAt(resultIndex)] + arg2 * LOW_U32_FROM_PTR(arg1 + index);
result[halfAt(resultIndex)] = LOW_U32_FROM_VAR(product);
++resultIndex;
product = HIGH_IN_U64(product) + result[halfAt(resultIndex)] + arg2 * HIGH_U32_FROM_PTR(arg1 + index);
result[halfAt(resultIndex)] = LOW_U32_FROM_VAR(product);
++resultIndex;
} while (++index < length);
result[halfAt(resultIndex)] += HIGH_U32_FROM_VAR(product);
if (result[halfAt(resultIndex)] < HIGH_U32_FROM_VAR(product)) {
/* must be careful with ++ operator and macro expansion */
++resultIndex;
while (++result[halfAt(resultIndex)] == 0) ++resultIndex;
}
}
#endif
void
multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2,
U_64 * result, IDATA length)
{
/* assumes result is large enough to hold product */
U_64 *temp;
U_32 *resultIn32;
IDATA count, index;
if (length1 < length2)
{
temp = arg1;
arg1 = arg2;
arg2 = temp;
count = length1;
length1 = length2;
length2 = count;
}
memset (result, 0, sizeof (U_64) * length);
/* length1 > length2 */
resultIn32 = (U_32 *) result;
index = -1;
for (count = 0; count < length2; ++count)
{
simpleMultiplyAddHighPrecision (arg1, length1, LOW_IN_U64 (arg2[count]),
resultIn32 + (++index));
#ifdef HY_LITTLE_ENDIAN
simpleMultiplyAddHighPrecision(arg1, length1, HIGH_IN_U64(arg2[count]), resultIn32 + (++index));
#else
simpleMultiplyAddHighPrecisionBigEndianFix(arg1, length1, HIGH_IN_U64(arg2[count]), resultIn32 + (++index));
#endif
}
}
U_32
simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit)
{
/* assumes digit is less than 32 bits */
U_64 arg;
IDATA index = 0;
digit <<= 32;
do
{
arg = LOW_IN_U64 (arg1[index]);
digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
arg = HIGH_IN_U64 (arg1[index]);
digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
}
while (++index < length);
return HIGH_U32_FROM_VAR (digit);
}
void
simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2)
{
/* assumes length > 0 */
IDATA index, offset;
if (arg2 >= 64)
{
offset = arg2 >> 6;
index = length;
while (--index - offset >= 0)
arg1[index] = arg1[index - offset];
do
{
arg1[index] = 0;
}
while (--index >= 0);
arg2 &= 0x3F;
}
if (arg2 == 0)
return;
while (--length > 0)
{
arg1[length] = arg1[length] << arg2 | arg1[length - 1] >> (64 - arg2);
}
*arg1 <<= arg2;
}
IDATA
highestSetBit (U_64 * y)
{
U_32 x;
IDATA result;
if (*y == 0)
return 0;
#if defined(USE_LL)
if (*y & 0xFFFFFFFF00000000LL)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#else
#if defined(USE_L)
if (*y & 0xFFFFFFFF00000000L)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#else
if (*y & 0xFFFFFFFF00000000)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#endif /* USE_L */
#endif /* USE_LL */
if (x & 0xFFFF0000)
{
x = bitSection (x, 0xFFFF0000, 16);
result += 16;
}
if (x & 0xFF00)
{
x = bitSection (x, 0xFF00, 8);
result += 8;
}
if (x & 0xF0)
{
x = bitSection (x, 0xF0, 4);
result += 4;
}
if (x > 0x7)
return result + 4;
else if (x > 0x3)
return result + 3;
else if (x > 0x1)
return result + 2;
else
return result + 1;
}
IDATA
lowestSetBit (U_64 * y)
{
U_32 x;
IDATA result;
if (*y == 0)
return 0;
#if defined(USE_LL)
if (*y & 0x00000000FFFFFFFFLL)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#else
#if defined(USE_L)
if (*y & 0x00000000FFFFFFFFL)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#else
if (*y & 0x00000000FFFFFFFF)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#endif /* USE_L */
#endif /* USE_LL */
if (!(x & 0xFFFF))
{
x = bitSection (x, 0xFFFF0000, 16);
result += 16;
}
if (!(x & 0xFF))
{
x = bitSection (x, 0xFF00, 8);
result += 8;
}
if (!(x & 0xF))
{
x = bitSection (x, 0xF0, 4);
result += 4;
}
if (x & 0x1)
return result + 1;
else if (x & 0x2)
return result + 2;
else if (x & 0x4)
return result + 3;
else
return result + 4;
}
IDATA
highestSetBitHighPrecision (U_64 * arg, IDATA length)
{
IDATA highBit;
while (--length >= 0)
{
highBit = highestSetBit (arg + length);
if (highBit)
return highBit + 64 * length;
}
return 0;
}
IDATA
lowestSetBitHighPrecision (U_64 * arg, IDATA length)
{
IDATA lowBit, index = -1;
while (++index < length)
{
lowBit = lowestSetBit (arg + index);
if (lowBit)
return lowBit + 64 * index;
}
return 0;
}
IDATA
compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
while (--length1 >= 0 && arg1[length1] == 0);
while (--length2 >= 0 && arg2[length2] == 0);
if (length1 > length2)
return 1;
else if (length1 < length2)
return -1;
else if (length1 > -1)
{
do
{
if (arg1[length1] > arg2[length1])
return 1;
else if (arg1[length1] < arg2[length1])
return -1;
}
while (--length1 >= 0);
}
return 0;
}
KDouble
toDoubleHighPrecision (U_64 * arg, IDATA length)
{
IDATA highBit;
U_64 mantissa, test64;
U_32 test;
KDouble result;
while (length > 0 && arg[length - 1] == 0)
--length;
if (length == 0)
result = 0.0;
else if (length > 16)
{
DOUBLE_TO_LONGBITS (result) = EXPONENT_MASK;
}
else if (length == 1)
{
highBit = highestSetBit (arg);
if (highBit <= 53)
{
highBit = 53 - highBit;
mantissa = *arg << highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, -highBit);
}
else
{
highBit -= 53;
mantissa = *arg >> highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, highBit);
/* perform rounding, round to even in case of tie */
test = (LOW_U32_FROM_PTR (arg) << (11 - highBit)) & 0x7FF;
if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
}
}
else
{
highBit = highestSetBit (arg + (--length));
if (highBit <= 53)
{
highBit = 53 - highBit;
if (highBit > 0)
{
mantissa =
(arg[length] << highBit) | (arg[length - 1] >>
(64 - highBit));
}
else
{
mantissa = arg[length];
}
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, length * 64 - highBit);
/* perform rounding, round to even in case of tie */
test64 = arg[--length] << highBit;
if (test64 > SIGN_MASK || ((test64 == SIGN_MASK) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
else if (test64 == SIGN_MASK)
{
while (--length >= 0)
{
if (arg[length] != 0)
{
DOUBLE_TO_LONGBITS (result) =
DOUBLE_TO_LONGBITS (result) + 1;
break;
}
}
}
}
else
{
highBit -= 53;
mantissa = arg[length] >> highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, length * 64 + highBit);
/* perform rounding, round to even in case of tie */
test = (LOW_U32_FROM_PTR (arg + length) << (11 - highBit)) & 0x7FF;
if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
else if (test == 0x400)
{
do
{
if (arg[--length] != 0)
{
DOUBLE_TO_LONGBITS (result) =
DOUBLE_TO_LONGBITS (result) + 1;
break;
}
}
while (length > 0);
}
}
}
return result;
}
IDATA
tenToTheEHighPrecision (U_64 * result, IDATA length, int e)
{
/* size test */
if (length < ((e / 19) + 1))
return 0;
memset (result, 0, length * sizeof (U_64));
*result = 1;
if (e == 0)
return 1;
length = 1;
length = timesTenToTheEHighPrecision (result, length, e);
/* bad O(n) way of doing it, but simple */
/*
do {
overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
if (overflow)
result[length++] = overflow;
} while (--e);
*/
return length;
}
IDATA
timesTenToTheEHighPrecision (U_64 * result, IDATA length, int e)
{
/* assumes result can hold value */
U_64 overflow;
int exp10 = e;
if (e == 0)
return length;
/* bad O(n) way of doing it, but simple */
/*
do {
overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
if (overflow)
result[length++] = overflow;
} while (--e);
*/
/* Replace the current implementation which performs a
* "multiplication" by 10 e number of times with an actual
* multiplication. 10e19 is the largest exponent to the power of ten
* that will fit in a 64-bit integer, and 10e9 is the largest exponent to
* the power of ten that will fit in a 64-bit integer. Not sure where the
* break-even point is between an actual multiplication and a
* simpleAappendDecimalDigit() so just pick 10e3 as that point for
* now.
*/
while (exp10 >= 19)
{
overflow = simpleMultiplyHighPrecision64 (result, length, TEN_E19);
if (overflow)
result[length++] = overflow;
exp10 -= 19;
}
while (exp10 >= 9)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E9);
if (overflow)
result[length++] = overflow;
exp10 -= 9;
}
if (exp10 == 0)
return length;
else if (exp10 == 1)
{
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 2)
{
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 3)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E3);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 4)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E4);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 5)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E5);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 6)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E6);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 7)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E7);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 8)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E8);
if (overflow)
result[length++] = overflow;
}
return length;
}
U_64
doubleMantissa (KDouble z)
{
U_64 m = DOUBLE_TO_LONGBITS (z);
if ((m & EXPONENT_MASK) != 0)
m = (m & MANTISSA_MASK) | NORMAL_MASK;
else
m = (m & MANTISSA_MASK);
return m;
}
IDATA
doubleExponent (KDouble z)
{
/* assumes positive double */
IDATA k = HIGH_U32_FROM_VAR (z) >> 20;
if (k)
k -= E_OFFSET;
else
k = 1 - E_OFFSET;
return k;
}
UDATA
floatMantissa (KFloat z)
{
UDATA m = (UDATA) FLOAT_TO_INTBITS (z);
if ((m & FLOAT_EXPONENT_MASK) != 0)
m = (m & FLOAT_MANTISSA_MASK) | FLOAT_NORMAL_MASK;
else
m = (m & FLOAT_MANTISSA_MASK);
return m;
}
IDATA
floatExponent (KFloat z)
{
/* assumes positive float */
IDATA k = FLOAT_TO_INTBITS (z) >> 23;
if (k)
k -= FLOAT_E_OFFSET;
else
k = 1 - FLOAT_E_OFFSET;
return k;
}
/* Allow a 64-bit value in arg2 */
U_64
simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2)
{
U_64 intermediate, *pArg1, carry1, carry2, prod1, prod2, sum;
IDATA index;
U_32 buf32;
index = 0;
intermediate = 0;
pArg1 = arg1 + index;
carry1 = carry2 = 0;
do
{
if ((*pArg1 != 0) || (intermediate != 0))
{
prod1 =
(U_64) LOW_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
sum = intermediate + prod1;
if ((sum < prod1) || (sum < intermediate))
{
carry1 = 1;
}
else
{
carry1 = 0;
}
prod1 =
(U_64) LOW_U32_FROM_VAR (arg2) * (U_64) HIGH_U32_FROM_PTR (pArg1);
prod2 =
(U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
intermediate = carry2 + HIGH_IN_U64 (sum) + prod1 + prod2;
if ((intermediate < prod1) || (intermediate < prod2))
{
carry2 = 1;
}
else
{
carry2 = 0;
}
LOW_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (sum);
buf32 = HIGH_U32_FROM_PTR (pArg1);
HIGH_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (intermediate);
intermediate = carry1 + HIGH_IN_U64 (intermediate)
+ (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) buf32;
}
pArg1++;
}
while (++index < length);
return intermediate;
}
+57
View File
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(cbigint_h)
#define cbigint_h
#include "fltconst.h"
#include "../Types.h"
//#include "vmi.h"
#define LOW_U32_FROM_VAR(u64) LOW_U32_FROM_LONG64(u64)
#define LOW_U32_FROM_PTR(u64ptr) LOW_U32_FROM_LONG64_PTR(u64ptr)
#define HIGH_U32_FROM_VAR(u64) HIGH_U32_FROM_LONG64(u64)
#define HIGH_U32_FROM_PTR(u64ptr) HIGH_U32_FROM_LONG64_PTR(u64ptr)
#if defined(__cplusplus)
extern "C"
{
#endif
void multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
IDATA length2, U_64 * result, IDATA length);
U_32 simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit);
KDouble toDoubleHighPrecision (U_64 * arg, IDATA length);
IDATA tenToTheEHighPrecision (U_64 * result, IDATA length, int e);
U_64 doubleMantissa (KDouble z);
IDATA compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
IDATA highestSetBitHighPrecision (U_64 * arg, IDATA length);
void subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
IDATA doubleExponent (KDouble z);
U_32 simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
IDATA addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
void simpleMultiplyAddHighPrecisionBigEndianFix (U_64 * arg1, IDATA length, U_64 arg2, U_32 * result);
IDATA lowestSetBit (U_64 * y);
IDATA timesTenToTheEHighPrecision (U_64 * result, IDATA length, int e);
void simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2, U_32 * result);
IDATA highestSetBit (U_64 * y);
IDATA lowestSetBitHighPrecision (U_64 * arg, IDATA length);
void simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2);
UDATA floatMantissa (KFloat z);
U_64 simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2);
IDATA simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
IDATA floatExponent (KFloat z);
#if defined(__cplusplus)
}
#endif
#endif /* cbigint_h */
+863
View File
@@ -0,0 +1,863 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <math.h>
#include "cbigint.h"
#include "../Natives.h"
#include "../Exceptions.h"
#include "../utf8.h"
#include <stdlib.h>
#include <string>
#if defined(LINUX) || defined(FREEBSD) || defined(ZOS) || defined(MACOSX) || defined(AIX)
#define USE_LL
#endif
#define LOW_I32_FROM_VAR(u64) LOW_I32_FROM_LONG64(u64)
#define LOW_I32_FROM_PTR(u64ptr) LOW_I32_FROM_LONG64_PTR(u64ptr)
#define HIGH_I32_FROM_VAR(u64) HIGH_I32_FROM_LONG64(u64)
#define HIGH_I32_FROM_PTR(u64ptr) HIGH_I32_FROM_LONG64_PTR(u64ptr)
#define MAX_ACCURACY_WIDTH 17
#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
extern "C" {
KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e);
void Konan_NumberConverter_bigIntDigitGeneratorInstImpl (KRef results,
KRef uArray,
KLong f,
KInt e,
KBoolean isDenormalized,
KBoolean mantissaIsZero,
KInt p);
KDouble Konan_NumberConverter_ceil(KDouble x) {
return ceil(x);
}
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value);
}
KDouble createDouble (const char *s, KInt e);
KDouble createDouble1 (U_64 * f, IDATA length, KInt e);
KDouble doubleAlgorithm (U_64 * f, IDATA length, KInt e, KDouble z);
U_64 dblparse_shiftRight64 (U_64 * lp, volatile int mbe);
static const KDouble tens[] = {
1.0,
1.0e1,
1.0e2,
1.0e3,
1.0e4,
1.0e5,
1.0e6,
1.0e7,
1.0e8,
1.0e9,
1.0e10,
1.0e11,
1.0e12,
1.0e13,
1.0e14,
1.0e15,
1.0e16,
1.0e17,
1.0e18,
1.0e19,
1.0e20,
1.0e21,
1.0e22
};
#define tenToTheE(e) (*(tens + (e)))
#define LOG5_OF_TWO_TO_THE_N 23
#define INV_LOG_OF_TEN_BASE_2 (0.30102999566398114)
#define DOUBLE_MIN_VALUE 5.0e-324
#define sizeOfTenToTheE(e) (((e) / 19) + 1)
#if defined(USE_LL)
#define INFINITE_LONGBITS (0x7FF0000000000000LL)
#else
#if defined(USE_L)
#define INFINITE_LONGBITS (0x7FF0000000000000L)
#else
#define INFINITE_LONGBITS (0x7FF0000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define MINIMUM_LONGBITS (0x1)
#if defined(USE_LL)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
#define EXPONENT_MASK (0x7FF0000000000000LL)
#define NORMAL_MASK (0x0010000000000000LL)
#else
#if defined(USE_L)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
#define EXPONENT_MASK (0x7FF0000000000000L)
#define NORMAL_MASK (0x0010000000000000L)
#else
#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
#define EXPONENT_MASK (0x7FF0000000000000)
#define NORMAL_MASK (0x0010000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
/* Keep a count of the number of times we decrement and increment to
* approximate the double, and attempt to detect the case where we
* could potentially toggle back and forth between decrementing and
* incrementing. It is possible for us to be stuck in the loop when
* incrementing by one or decrementing by one may exceed or stay below
* the value that we are looking for. In this case, just break out of
* the loop if we toggle between incrementing and decrementing for more
* than twice.
*/
#define INCREMENT_DOUBLE(_x, _decCount, _incCount) \
{ \
++DOUBLE_TO_LONGBITS(_x); \
_incCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define DECREMENT_DOUBLE(_x, _decCount, _incCount) \
{ \
--DOUBLE_TO_LONGBITS(_x); \
_decCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0)
#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
#define release(r) if ((r)) free((r));
/*NB the Number converter methods are synchronized so it is possible to
*have global data for use by bigIntDigitGenerator */
#define RM_SIZE 21
#define STemp_SIZE 22
KDouble createDouble (const char *s, KInt e)
{
/* assumes s is a null terminated string with at least one
* character in it */
U_64 def[DEFAULT_WIDTH];
U_64 defBackup[DEFAULT_WIDTH];
U_64 *f, *fNoOverflow, *g, *tempBackup;
U_32 overflow;
KDouble result;
IDATA index = 1;
int unprocessedDigits = 0;
f = def;
fNoOverflow = defBackup;
*f = 0;
tempBackup = g = 0;
do
{
if (*s >= '0' && *s <= '9')
{
/* Make a back up of f before appending, so that we can
* back out of it if there is no more room, i.e. index >
* MAX_ACCURACY_WIDTH.
*/
memcpy (fNoOverflow, f, sizeof (U_64) * index);
overflow =
simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
if (overflow)
{
f[index++] = overflow;
/* There is an overflow, but there is no more room
* to store the result. We really only need the top 52
* bits anyway, so we must back out of the overflow,
* and ignore the rest of the string.
*/
if (index >= MAX_ACCURACY_WIDTH)
{
index--;
memcpy (f, fNoOverflow, sizeof (U_64) * index);
break;
}
if (tempBackup)
{
fNoOverflow = tempBackup;
}
}
}
else
index = -1;
}
while (index > 0 && *(++s) != '\0');
/* We've broken out of the parse loop either because we've reached
* the end of the string or we've overflowed the maximum accuracy
* limit of a double. If we still have unprocessed digits in the
* given string, then there are three possible results:
* 1. (unprocessed digits + e) == 0, in which case we simply
* convert the existing bits that are already parsed
* 2. (unprocessed digits + e) < 0, in which case we simply
* convert the existing bits that are already parsed along
* with the given e
* 3. (unprocessed digits + e) > 0 indicates that the value is
* simply too big to be stored as a double, so return Infinity
*/
if ((unprocessedDigits = strlen (s)) > 0)
{
e += unprocessedDigits;
if (index > -1)
{
if (e == 0)
result = toDoubleHighPrecision (f, index);
else if (e < 0)
result = createDouble1 (f, index, e);
else
{
DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
}
}
else
{
LOW_I32_FROM_VAR (result) = -1;
HIGH_I32_FROM_VAR (result) = -1;
}
}
else
{
if (index > -1)
{
if (e == 0)
result = toDoubleHighPrecision (f, index);
else
result = createDouble1 (f, index, e);
}
else
{
LOW_I32_FROM_VAR (result) = -1;
HIGH_I32_FROM_VAR (result) = -1;
}
}
return result;
}
KDouble
createDouble1 (U_64 * f, IDATA length, KInt e)
{
IDATA numBits;
KDouble result;
#define APPROX_MIN_MAGNITUDE -309
#define APPROX_MAX_MAGNITUDE 309
numBits = highestSetBitHighPrecision (f, length) + 1;
numBits -= lowestSetBitHighPrecision (f, length);
if (numBits < 54 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
{
return toDoubleHighPrecision (f, length) * tenToTheE (e);
}
else if (numBits < 54 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
{
return toDoubleHighPrecision (f, length) / tenToTheE (-e);
}
else if (e >= 0 && e < APPROX_MAX_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) * pow (10.0, (double) e);
}
else if (e >= APPROX_MAX_MAGNITUDE)
{
/* Convert the partial result to make sure that the
* non-exponential part is not zero. This check fixes the case
* where the user enters 0.0e309! */
result = toDoubleHighPrecision (f, length);
/* Don't go straight to zero as the fact that x*0 = 0 independent of x might
cause the algorithm to produce an incorrect result. Instead try the min value
first and let it fall to zero if need be. */
if (result == 0.0)
DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
else
DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
}
else if (e > APPROX_MIN_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) / pow (10.0, (double) -e);
}
if (e <= APPROX_MIN_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) * pow (10.0, (double) (e + 52));
result = result * pow (10.0, (double) -52);
}
/* Don't go straight to zero as the fact that x*0 = 0 independent of x might
cause the algorithm to produce an incorrect result. Instead try the min value
first and let it fall to zero if need be. */
if (result == 0.0)
DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
return doubleAlgorithm (f, length, e, result);
}
U_64
dblparse_shiftRight64 (U_64 * lp, volatile int mbe)
{
U_64 b1Value = 0;
U_32 hi = HIGH_U32_FROM_LONG64_PTR (lp);
U_32 lo = LOW_U32_FROM_LONG64_PTR (lp);
int srAmt;
if (mbe == 0)
return 0;
if (mbe >= 128)
{
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
return 0;
}
/* Certain platforms do not handle de-referencing a 64-bit value
* from a pointer on the stack correctly (e.g. MVL-hh/XScale)
* because the pointer may not be properly aligned, so we'll have
* to handle two 32-bit chunks. */
if (mbe < 32)
{
LOW_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64 (b1Value) = lo << (32 - mbe);
LOW_U32_FROM_LONG64_PTR (lp) = (hi << (32 - mbe)) | (lo >> mbe);
HIGH_U32_FROM_LONG64_PTR (lp) = hi >> mbe;
}
else if (mbe == 32)
{
LOW_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64 (b1Value) = lo;
LOW_U32_FROM_LONG64_PTR (lp) = hi;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe < 64)
{
srAmt = mbe - 32;
LOW_U32_FROM_LONG64 (b1Value) = lo << (32 - srAmt);
HIGH_U32_FROM_LONG64 (b1Value) = (hi << (32 - srAmt)) | (lo >> srAmt);
LOW_U32_FROM_LONG64_PTR (lp) = hi >> srAmt;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe == 64)
{
LOW_U32_FROM_LONG64 (b1Value) = lo;
HIGH_U32_FROM_LONG64 (b1Value) = hi;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe < 96)
{
srAmt = mbe - 64;
b1Value = *lp;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64 (b1Value) >>= srAmt;
LOW_U32_FROM_LONG64 (b1Value) |= (hi << (32 - srAmt));
HIGH_U32_FROM_LONG64 (b1Value) >>= srAmt;
}
else if (mbe == 96)
{
LOW_U32_FROM_LONG64 (b1Value) = hi;
HIGH_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
}
else
{
LOW_U32_FROM_LONG64 (b1Value) = hi >> (mbe - 96);
HIGH_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
}
return b1Value;
}
#if defined(WIN32)
/* disable global optimizations on the microsoft compiler for the
* doubleAlgorithm function otherwise it won't compile */
#pragma optimize("g",off)
#endif
/* The algorithm for the function doubleAlgorithm() below can be found
* in:
*
* "How to Read Floating-Point Numbers Accurately", William D.
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
*
* There is a possibility that the function will end up in an endless
* loop if the given approximating floating-point number (a very small
* floating-point whose value is very close to zero) straddles between
* two approximating integer values. We modified the algorithm slightly
* to detect the case where it oscillates back and forth between
* incrementing and decrementing the floating-point approximation. It
* is currently set such that if the oscillation occurs more than twice
* then return the original approximation.
*/
KDouble doubleAlgorithm (U_64 * f, IDATA length, KInt e, KDouble z)
{
U_64 m;
IDATA k, comparison, comparison2;
U_64 *x, *y, *D, *D2;
IDATA xLength, yLength, DLength, D2Length, decApproxCount, incApproxCount;
//PORT_ACCESS_FROM_ENV (env);
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
decApproxCount = incApproxCount = 0;
do
{
m = doubleMantissa (z);
k = doubleExponent (z);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
if (e >= 0 && k >= 0)
{
xLength = sizeOfTenToTheE (e) + length;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
yLength = (k >> 6) + 2;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
simpleShiftLeftHighPrecision (y, yLength, k);
}
else if (e >= 0)
{
xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = 1;
allocateU64 (y, 1);
*y = m;
}
else if (k >= 0)
{
xLength = length;
x = f;
yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
simpleShiftLeftHighPrecision (y, yLength, k);
}
else
{
xLength = length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = sizeOfTenToTheE (-e) + 1;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
}
comparison = compareHighPrecision (x, xLength, y, yLength);
if (comparison > 0)
{ /* x > y */
DLength = xLength;
allocateU64 (D, DLength);
memcpy (D, x, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, y, yLength);
}
else if (comparison)
{ /* y > x */
DLength = yLength;
allocateU64 (D, DLength);
memcpy (D, y, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, x, xLength);
}
else
{ /* y == x */
DLength = 1;
allocateU64 (D, 1);
*D = 0;
}
D2Length = DLength + 1;
allocateU64 (D2, D2Length);
m <<= 1;
multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
m >>= 1;
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else
{
break;
}
}
else if (comparison2 == 0)
{
if ((LOW_U32_FROM_VAR (m) & 1) == 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else if (comparison < 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
break;
}
else
{
INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
break;
}
}
else if (comparison < 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
if (DOUBLE_TO_LONGBITS (z) == INFINITE_LONGBITS)
break;
INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
}
while (1);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
return z;
OutOfMemory:
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
DOUBLE_TO_LONGBITS (z) = -2;
return z;
}
#if defined(WIN32)
#pragma optimize("",on) /*restore optimizations */
#endif
KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e)
{
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
std::string utf8;
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
const char *str = utf8.c_str();
auto dbl = createDouble (str, e);
if (!ERROR_OCCURED (dbl))
{
return dbl;
}
else if (LOW_I32_FROM_VAR (dbl) == (I_32) - 1)
{ /* NumberFormatException */
ThrowNumberFormatException();
}
else
{ /* OutOfMemoryError */
ThrowOutOfMemoryError();
}
return 0.0;
}
/* The algorithm for this particular function can be found in:
*
* Printing Floating-Point Numbers Quickly and Accurately, Robert
* G. Burger, and R. Kent Dybvig, Programming Language Design and
* Implementation (PLDI) 1996, pp.108-116.
*
* The previous implementation of this function combined m+ and m- into
* one single M which caused some inaccuracy of the last digit. The
* particular case below shows this inaccuracy:
*
* System.out.println(new Double((1.234123412431233E107)).toString());
* System.out.println(new Double((1.2341234124312331E107)).toString());
* System.out.println(new Double((1.2341234124312332E107)).toString());
*
* outputs the following:
*
* 1.234123412431233E107
* 1.234123412431233E107
* 1.234123412431233E107
*
* instead of:
*
* 1.234123412431233E107
* 1.2341234124312331E107
* 1.2341234124312331E107
*
*/
void Konan_NumberConverter_bigIntDigitGeneratorInstImpl (KRef results,
KRef uArray,
KLong f,
KInt e,
KBoolean isDenormalized,
KBoolean mantissaIsZero,
KInt p)
{
int RLength, SLength, TempLength, mplus_Length, mminus_Length;
int high, low, i;
int k, firstK, U;
int getCount, setCount;
U_64 R[RM_SIZE], S[STemp_SIZE], mplus[RM_SIZE], mminus[RM_SIZE], Temp[STemp_SIZE];
memset (R, 0, RM_SIZE * sizeof (U_64));
memset (S, 0, STemp_SIZE * sizeof (U_64));
memset (mplus, 0, RM_SIZE * sizeof (U_64));
memset (mminus, 0, RM_SIZE * sizeof (U_64));
memset (Temp, 0, STemp_SIZE * sizeof (U_64));
if (e >= 0)
{
*R = f;
*mplus = *mminus = 1;
simpleShiftLeftHighPrecision (mminus, RM_SIZE, e);
if (f != (2 << (p - 1)))
{
simpleShiftLeftHighPrecision (R, RM_SIZE, e + 1);
*S = 2;
/*
* m+ = m+ << e results in 1.0e23 to be printed as
* 0.9999999999999999E23
* m+ = m+ << e+1 results in 1.0e23 to be printed as
* 1.0e23 (caused too much rounding)
* 470fffffffffffff = 2.0769187434139308E34
* 4710000000000000 = 2.076918743413931E34
*/
simpleShiftLeftHighPrecision (mplus, RM_SIZE, e);
}
else
{
simpleShiftLeftHighPrecision (R, RM_SIZE, e + 2);
*S = 4;
simpleShiftLeftHighPrecision (mplus, RM_SIZE, e + 1);
}
}
else
{
if (isDenormalized || (f != (2 << (p - 1))))
{
*R = f << 1;
*S = 1;
simpleShiftLeftHighPrecision (S, STemp_SIZE, 1 - e);
*mplus = *mminus = 1;
}
else
{
*R = f << 2;
*S = 1;
simpleShiftLeftHighPrecision (S, STemp_SIZE, 2 - e);
*mplus = 2;
*mminus = 1;
}
}
k = (int) ceil ((e + p - 1) * INV_LOG_OF_TEN_BASE_2 - 1e-10);
if (k > 0)
{
timesTenToTheEHighPrecision (S, STemp_SIZE, k);
}
else
{
timesTenToTheEHighPrecision (R, RM_SIZE, -k);
timesTenToTheEHighPrecision (mplus, RM_SIZE, -k);
timesTenToTheEHighPrecision (mminus, RM_SIZE, -k);
}
RLength = mplus_Length = mminus_Length = RM_SIZE;
SLength = TempLength = STemp_SIZE;
memset (Temp + RM_SIZE, 0, (STemp_SIZE - RM_SIZE) * sizeof (U_64));
memcpy (Temp, R, RM_SIZE * sizeof (U_64));
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
while (SLength > 1 && S[SLength - 1] == 0)
--SLength;
TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
addHighPrecision (Temp, TempLength, mplus, mplus_Length);
if (compareHighPrecision (Temp, TempLength, S, SLength) >= 0)
{
firstK = k;
}
else
{
firstK = k - 1;
simpleAppendDecimalDigitHighPrecision (R, ++RLength, 0);
simpleAppendDecimalDigitHighPrecision (mplus, ++mplus_Length, 0);
simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
}
getCount = setCount = 0;
do
{
U = 0;
for (i = 3; i >= 0; --i)
{
TempLength = SLength + 1;
Temp[SLength] = 0;
memcpy (Temp, S, SLength * sizeof (U_64));
simpleShiftLeftHighPrecision (Temp, TempLength, i);
if (compareHighPrecision (R, RLength, Temp, TempLength) >= 0)
{
subtractHighPrecision (R, RLength, Temp, TempLength);
U += 1 << i;
}
}
low = compareHighPrecision (R, RLength, mminus, mminus_Length) <= 0;
memset (Temp + RLength, 0, (STemp_SIZE - RLength) * sizeof (U_64));
memcpy (Temp, R, RLength * sizeof (U_64));
TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
addHighPrecision (Temp, TempLength, mplus, mplus_Length);
high = compareHighPrecision (Temp, TempLength, S, SLength) >= 0;
if (low || high)
break;
simpleAppendDecimalDigitHighPrecision (R, ++RLength, 0);
simpleAppendDecimalDigitHighPrecision (mplus, ++mplus_Length, 0);
simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
}
while (1);
simpleShiftLeftHighPrecision (R, ++RLength, 1);
if (low && !high)
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
else if (high && !low)
Kotlin_IntArray_set(uArray, setCount++, U + 1);
//uArray[setCount++] = U + 1;
else if (compareHighPrecision (R, RLength, S, SLength) < 0)
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
else
Kotlin_IntArray_set(uArray, setCount++, U + 1);
//uArray[setCount++] = U + 1;
Kotlin_IntArray_set(results, 0, setCount);
// fid = (*env)->GetFieldID (env, clazz, "setCount", "I");
// (*env)->SetIntField (env, inst, fid, setCount);
Kotlin_IntArray_set(results, 1, getCount);
// fid = (*env)->GetFieldID (env, clazz, "getCount", "I");
// (*env)->SetIntField (env, inst, fid, getCount);
Kotlin_IntArray_set(results, 2, firstK);
// fid = (*env)->GetFieldID (env, clazz, "firstK", "I");
// (*env)->SetIntField (env, inst, fid, firstK);
}
+160
View File
@@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(fltconst_h)
#define fltconst_h
#include "hycomp.h"
/* IEEE floats consist of: sign bit, exponent field, significand field
single: 31 = sign bit, 30..23 = exponent (8 bits), 22..0 = significand (23 bits)
double: 63 = sign bit, 62..52 = exponent (11 bits), 51..0 = significand (52 bits)
inf == (all exponent bits set) and (all mantissa bits clear)
nan == (all exponent bits set) and (at least one mantissa bit set)
finite == (at least one exponent bit clear)
zero == (all exponent bits clear) and (all mantissa bits clear)
denormal == (all exponent bits clear) and (at least one mantissa bit set)
positive == sign bit clear
negative == sign bit set
*/
#define MAX_U32_DOUBLE (ESDOUBLE) (4294967296.0) /* 2^32 */
#define MAX_U32_SINGLE (ESSINGLE) (4294967296.0) /* 2^32 */
#define HY_POS_PI (ESDOUBLE)(3.141592653589793)
#ifdef HY_LITTLE_ENDIAN
#ifdef HY_PLATFORM_DOUBLE_ORDER
#define DOUBLE_LO_OFFSET 0
#define DOUBLE_HI_OFFSET 1
#else
#define DOUBLE_LO_OFFSET 1
#define DOUBLE_HI_OFFSET 0
#endif
#define LONG_LO_OFFSET 0
#define LONG_HI_OFFSET 1
#else
#ifdef HY_PLATFORM_DOUBLE_ORDER
#define DOUBLE_LO_OFFSET 1
#define DOUBLE_HI_OFFSET 0
#else
#define DOUBLE_LO_OFFSET 0
#define DOUBLE_HI_OFFSET 1
#endif
#define LONG_LO_OFFSET 1
#define LONG_HI_OFFSET 0
#endif
#define RETURN_FINITE 0
#define RETURN_NAN 1
#define RETURN_POS_INF 2
#define RETURN_NEG_INF 3
#define DOUBLE_SIGN_MASK_HI 0x80000000
#define DOUBLE_EXPONENT_MASK_HI 0x7FF00000
#define DOUBLE_MANTISSA_MASK_LO 0xFFFFFFFF
#define DOUBLE_MANTISSA_MASK_HI 0x000FFFFF
#define SINGLE_SIGN_MASK 0x80000000
#define SINGLE_EXPONENT_MASK 0x7F800000
#define SINGLE_MANTISSA_MASK 0x007FFFFF
#define SINGLE_NAN_BITS (SINGLE_EXPONENT_MASK | 0x00400000)
typedef union u64u32dbl_tag {
U_64 u64val;
U_32 u32val[2];
I_32 i32val[2];
double dval;
} U64U32DBL;
/* Replace P_FLOAT_HI and P_FLOAT_LOW */
/* These macros are used to access the high and low 32-bit parts of a double (64-bit) value. */
#define LOW_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_LO_OFFSET])
#define HIGH_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_HI_OFFSET])
#define LOW_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_LO_OFFSET])
#define HIGH_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_HI_OFFSET])
#define LOW_U32_FROM_DBL(dbl) LOW_U32_FROM_DBL_PTR(&(dbl))
#define HIGH_U32_FROM_DBL(dbl) HIGH_U32_FROM_DBL_PTR(&(dbl))
#define LOW_I32_FROM_DBL(dbl) LOW_I32_FROM_DBL_PTR(&(dbl))
#define HIGH_I32_FROM_DBL(dbl) HIGH_I32_FROM_DBL_PTR(&(dbl))
#define LOW_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_LO_OFFSET])
#define HIGH_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_HI_OFFSET])
#define LOW_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_LO_OFFSET])
#define HIGH_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_HI_OFFSET])
#define LOW_U32_FROM_LONG64(long64) LOW_U32_FROM_LONG64_PTR(&(long64))
#define HIGH_U32_FROM_LONG64(long64) HIGH_U32_FROM_LONG64_PTR(&(long64))
#define LOW_I32_FROM_LONG64(long64) LOW_I32_FROM_LONG64_PTR(&(long64))
#define HIGH_I32_FROM_LONG64(long64) HIGH_I32_FROM_LONG64_PTR(&(long64))
#define IS_ZERO_DBL_PTR(dblptr) ((LOW_U32_FROM_DBL_PTR(dblptr) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0) || (HIGH_U32_FROM_DBL_PTR(dblptr) == DOUBLE_SIGN_MASK_HI)))
#define IS_ONE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0x3ff00000 || HIGH_U32_FROM_DBL_PTR(dblptr) == 0xbff00000) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
#define IS_NAN_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) | (HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI)))
#define IS_INF_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & (DOUBLE_EXPONENT_MASK_HI|DOUBLE_MANTISSA_MASK_HI)) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
#define IS_DENORMAL_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI) != 0 || (LOW_U32_FROM_DBL_PTR(dblptr) != 0)))
#define IS_FINITE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) < DOUBLE_EXPONENT_MASK_HI)
#define IS_POSITIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) == 0)
#define IS_NEGATIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) != 0)
#define IS_NEGATIVE_MAX_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0xFFEFFFFF) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0xFFFFFFFF))
#define IS_ZERO_DBL(dbl) IS_ZERO_DBL_PTR(&(dbl))
#define IS_ONE_DBL(dbl) IS_ONE_DBL_PTR(&(dbl))
#define IS_NAN_DBL(dbl) IS_NAN_DBL_PTR(&(dbl))
#define IS_INF_DBL(dbl) IS_INF_DBL_PTR(&(dbl))
#define IS_DENORMAL_DBL(dbl) IS_DENORMAL_DBL_PTR(&(dbl))
#define IS_FINITE_DBL(dbl) IS_FINITE_DBL_PTR(&(dbl))
#define IS_POSITIVE_DBL(dbl) IS_POSITIVE_DBL_PTR(&(dbl))
#define IS_NEGATIVE_DBL(dbl) IS_NEGATIVE_DBL_PTR(&(dbl))
#define IS_NEGATIVE_MAX_DBL(dbl) IS_NEGATIVE_MAX_DBL_PTR(&(dbl))
#define IS_ZERO_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)0)
#define IS_ONE_SNGL_PTR(fltptr) ((*U32P((fltptr)) == 0x3f800000) || (*U32P((fltptr)) == 0xbf800000))
#define IS_NAN_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) > (U_32)SINGLE_EXPONENT_MASK)
#define IS_INF_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)SINGLE_EXPONENT_MASK)
#define IS_DENORMAL_SNGL_PTR(fltptr) (((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK)-(U_32)1) < (U_32)SINGLE_MANTISSA_MASK)
#define IS_FINITE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) < (U_32)SINGLE_EXPONENT_MASK)
#define IS_POSITIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) == (U_32)0)
#define IS_NEGATIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) != (U_32)0)
#define IS_ZERO_SNGL(flt) IS_ZERO_SNGL_PTR(&(flt))
#define IS_ONE_SNGL(flt) IS_ONE_SNGL_PTR(&(flt))
#define IS_NAN_SNGL(flt) IS_NAN_SNGL_PTR(&(flt))
#define IS_INF_SNGL(flt) IS_INF_SNGL_PTR(&(flt))
#define IS_DENORMAL_SNGL(flt) IS_DENORMAL_SNGL_PTR(&(flt))
#define IS_FINITE_SNGL(flt) IS_FINITE_SNGL_PTR(&(flt))
#define IS_POSITIVE_SNGL(flt) IS_POSITIVE_SNGL_PTR(&(flt))
#define IS_NEGATIVE_SNGL(flt) IS_NEGATIVE_SNGL_PTR(&(flt))
#define SET_NAN_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | 0x00080000); LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_PZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = 0; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_SIGN_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_PINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_EXPONENT_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | DOUBLE_SIGN_MASK_HI); LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NAN_SNGL_PTR(fltptr) *U32P((fltptr)) = ((U_32)SINGLE_NAN_BITS)
#define SET_PZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = 0
#define SET_NZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_SIGN_MASK
#define SET_PINF_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_EXPONENT_MASK
#define SET_NINF_SNGL_PTR(fltptr) *U32P((fltptr)) = (SINGLE_EXPONENT_MASK | SINGLE_SIGN_MASK)
#if defined(HY_WORD64)
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) ((U64U32DBL *)(aDoublePtr))->u64val = ((U64U32DBL *)(dstPtr))->u64val
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) ((U64U32DBL *)(dstPtr))->u64val = ((U64U32DBL *)(aDoublePtr))->u64val
#define STORE_LONG(dstPtr, hi, lo) ((U64U32DBL *)(dstPtr))->u64val = (((U_64)(hi)) << 32) | (lo)
#else
/* on some platforms (HP720) we cannot reference an unaligned float. Build them by hand, one U_32 at a time. */
#if defined(ATOMIC_FLOAT_ACCESS)
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(dstPtr) = HIGH_U32_FROM_DBL_PTR(aDoublePtr); LOW_U32_FROM_DBL_PTR(dstPtr) = LOW_U32_FROM_DBL_PTR(aDoublePtr)
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(aDoublePtr) = HIGH_U32_FROM_DBL_PTR(dstPtr); LOW_U32_FROM_DBL_PTR(aDoublePtr) = LOW_U32_FROM_DBL_PTR(dstPtr)
#else
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) (*(dstPtr) = *(aDoublePtr))
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) (*(aDoublePtr) = *(dstPtr))
#endif
#define STORE_LONG(dstPtr, hi, lo) HIGH_U32_FROM_LONG64_PTR(dstPtr) = (hi); LOW_U32_FROM_LONG64_PTR(dstPtr) = (lo)
#endif /* HY_WORD64 */
#define PTR_SINGLE_VALUE(dstPtr, aSinglePtr) (*U32P(aSinglePtr) = *U32P(dstPtr))
#define PTR_SINGLE_STORE(dstPtr, aSinglePtr) *((U_32 *)(dstPtr)) = (*U32P(aSinglePtr))
#endif /* fltconst_h */
+559
View File
@@ -0,0 +1,559 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <math.h>
#include "cbigint.h"
#include "../Natives.h"
#include "../Exceptions.h"
#include "../utf8.h"
#include <stdlib.h>
#include <string>
#if defined(LINUX) || defined(FREEBSD) || defined(MACOSX) || defined(ZOS) || defined(AIX)
#define USE_LL
#endif
#ifdef HY_LITTLE_ENDIAN
#define LOW_I32_FROM_PTR(ptr64) (*(I_32 *) (ptr64))
#else
#define LOW_I32_FROM_PTR(ptr64) (*(((I_32 *) (ptr64)) + 1))
#endif
#define MAX_ACCURACY_WIDTH 8
#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
extern "C" {
KFloat
Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e);
}
KFloat createFloat1 (U_64 * f, IDATA length, KInt e);
KFloat floatAlgorithm (U_64 * f, IDATA length, KInt e, KFloat z);
KFloat createFloat (const char *s, KInt e);
static const U_32 tens[] = {
0x3f800000,
0x41200000,
0x42c80000,
0x447a0000,
0x461c4000,
0x47c35000,
0x49742400,
0x4b189680,
0x4cbebc20,
0x4e6e6b28,
0x501502f9 /* 10 ^ 10 in float */
};
#define tenToTheE(e) (*((KFloat *) (tens + (e))))
#define LOG5_OF_TWO_TO_THE_N 11
#define sizeOfTenToTheE(e) (((e) / 19) + 1)
#define INFINITE_INTBITS (0x7F800000)
#define MINIMUM_INTBITS (1)
#define MANTISSA_MASK (0x007FFFFF)
#define EXPONENT_MASK (0x7F800000)
#define NORMAL_MASK (0x00800000)
#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
/* Keep a count of the number of times we decrement and increment to
* approximate the double, and attempt to detect the case where we
* could potentially toggle back and forth between decrementing and
* incrementing. It is possible for us to be stuck in the loop when
* incrementing by one or decrementing by one may exceed or stay below
* the value that we are looking for. In this case, just break out of
* the loop if we toggle between incrementing and decrementing for more
* than twice.
*/
#define INCREMENT_FLOAT(_x, _decCount, _incCount) \
{ \
++FLOAT_TO_INTBITS(_x); \
_incCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define DECREMENT_FLOAT(_x, _decCount, _incCount) \
{ \
--FLOAT_TO_INTBITS(_x); \
_decCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
#define release(r) if ((r)) free((r));
KFloat
createFloat (const char *s, KInt e)
{
/* assumes s is a null terminated string with at least one
* character in it */
U_64 def[DEFAULT_WIDTH];
U_64 defBackup[DEFAULT_WIDTH];
U_64 *f, *fNoOverflow, *g, *tempBackup;
U_32 overflow;
KFloat result;
IDATA index = 1;
int unprocessedDigits = 0;
f = def;
fNoOverflow = defBackup;
*f = 0;
tempBackup = g = 0;
do
{
if (*s >= '0' && *s <= '9')
{
/* Make a back up of f before appending, so that we can
* back out of it if there is no more room, i.e. index >
* MAX_ACCURACY_WIDTH.
*/
memcpy (fNoOverflow, f, sizeof (U_64) * index);
overflow =
simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
if (overflow)
{
f[index++] = overflow;
/* There is an overflow, but there is no more room
* to store the result. We really only need the top 52
* bits anyway, so we must back out of the overflow,
* and ignore the rest of the string.
*/
if (index >= MAX_ACCURACY_WIDTH)
{
index--;
memcpy (f, fNoOverflow, sizeof (U_64) * index);
break;
}
if (tempBackup)
{
fNoOverflow = tempBackup;
}
}
}
else
index = -1;
}
while (index > 0 && *(++s) != '\0');
/* We've broken out of the parse loop either because we've reached
* the end of the string or we've overflowed the maximum accuracy
* limit of a double. If we still have unprocessed digits in the
* given string, then there are three possible results:
* 1. (unprocessed digits + e) == 0, in which case we simply
* convert the existing bits that are already parsed
* 2. (unprocessed digits + e) < 0, in which case we simply
* convert the existing bits that are already parsed along
* with the given e
* 3. (unprocessed digits + e) > 0 indicates that the value is
* simply too big to be stored as a double, so return Infinity
*/
if ((unprocessedDigits = strlen (s)) > 0)
{
e += unprocessedDigits;
if (index > -1)
{
if (e <= 0)
{
result = createFloat1 (f, index, e);
}
else
{
FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
}
}
else
{
result = *(KFloat *) & index;
}
}
else
{
if (index > -1)
{
result = createFloat1 (f, index, e);
}
else
{
result = *(KFloat *) & index;
}
}
return result;
}
KFloat
createFloat1 (U_64 * f, IDATA length, KInt e)
{
IDATA numBits;
KDouble dresult;
KFloat result;
numBits = highestSetBitHighPrecision (f, length) + 1;
if (numBits < 25 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
{
return ((KFloat) LOW_I32_FROM_PTR (f)) * tenToTheE (e);
}
else if (numBits < 25 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
{
return ((KFloat) LOW_I32_FROM_PTR (f)) / tenToTheE (-e);
}
else if (e >= 0 && e < 39)
{
result = (KFloat) (toDoubleHighPrecision (f, length) * pow (10.0, (double) e));
}
else if (e >= 39)
{
/* Convert the partial result to make sure that the
* non-exponential part is not zero. This check fixes the case
* where the user enters 0.0e309! */
result = (KFloat) toDoubleHighPrecision (f, length);
if (result == 0.0)
FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
else
FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
}
else if (e > -309)
{
int dexp;
U_32 fmant, fovfl;
U_64 dmant;
dresult = toDoubleHighPrecision (f, length) / pow (10.0, (double) -e);
if (IS_DENORMAL_DBL (dresult))
{
FLOAT_TO_INTBITS (result) = 0;
return result;
}
dexp = doubleExponent (dresult) + 51;
dmant = doubleMantissa (dresult);
/* Is it too small to be represented by a single-precision
* float? */
if (dexp <= -155)
{
FLOAT_TO_INTBITS (result) = 0;
return result;
}
/* Is it a denormalized single-precision float? */
if ((dexp <= -127) && (dexp > -155))
{
/* Only interested in 24 msb bits of the 53-bit double mantissa */
fmant = (U_32) (dmant >> 29);
fovfl = ((U_32) (dmant & 0x1FFFFFFF)) << 3;
while ((dexp < -127) && ((fmant | fovfl) != 0))
{
if ((fmant & 1) != 0)
{
fovfl |= 0x80000000;
}
fovfl >>= 1;
fmant >>= 1;
dexp++;
}
if ((fovfl & 0x80000000) != 0)
{
if ((fovfl & 0x7FFFFFFC) != 0)
{
fmant++;
}
else if ((fmant & 1) != 0)
{
fmant++;
}
}
else if ((fovfl & 0x40000000) != 0)
{
if ((fovfl & 0x3FFFFFFC) != 0)
{
fmant++;
}
}
FLOAT_TO_INTBITS (result) = fmant;
}
else
{
result = (KFloat) dresult;
}
}
/* Don't go straight to zero as the fact that x*0 = 0 independent
* of x might cause the algorithm to produce an incorrect result.
* Instead try the min value first and let it fall to zero if need
* be.
*/
if (e <= -309 || FLOAT_TO_INTBITS (result) == 0)
FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
return floatAlgorithm (f, length, e, (KFloat) result);
}
#if defined(WIN32)
/* disable global optimizations on the microsoft compiler for the
* floatAlgorithm function otherwise it won't properly compile */
#pragma optimize("g",off)
#endif
/* The algorithm for the function floatAlgorithm() below can be found
* in:
*
* "How to Read Floating-Point Numbers Accurately", William D.
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
*
* There is a possibility that the function will end up in an endless
* loop if the given approximating floating-point number (a very small
* floating-point whose value is very close to zero) straddles between
* two approximating integer values. We modified the algorithm slightly
* to detect the case where it oscillates back and forth between
* incrementing and decrementing the floating-point approximation. It
* is currently set such that if the oscillation occurs more than twice
* then return the original approximation.
*/
KFloat
floatAlgorithm (U_64 * f, IDATA length, KInt e, KFloat z)
{
U_64 m;
IDATA k, comparison, comparison2;
U_64 *x, *y, *D, *D2;
IDATA xLength, yLength, DLength, D2Length;
IDATA decApproxCount, incApproxCount;
//PORT_ACCESS_FROM_ENV (env);
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
decApproxCount = incApproxCount = 0;
do
{
m = floatMantissa (z);
k = floatExponent (z);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
if (e >= 0 && k >= 0)
{
xLength = sizeOfTenToTheE (e) + length;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
yLength = (k >> 6) + 2;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
simpleShiftLeftHighPrecision (y, yLength, k);
}
else if (e >= 0)
{
xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = 1;
allocateU64 (y, 1);
*y = m;
}
else if (k >= 0)
{
xLength = length;
x = f;
yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
simpleShiftLeftHighPrecision (y, yLength, k);
}
else
{
xLength = length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = sizeOfTenToTheE (-e) + 1;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
}
comparison = compareHighPrecision (x, xLength, y, yLength);
if (comparison > 0)
{ /* x > y */
DLength = xLength;
allocateU64 (D, DLength);
memcpy (D, x, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, y, yLength);
}
else if (comparison)
{ /* y > x */
DLength = yLength;
allocateU64 (D, DLength);
memcpy (D, y, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, x, xLength);
}
else
{ /* y == x */
DLength = 1;
allocateU64 (D, 1);
*D = 0;
}
D2Length = DLength + 1;
allocateU64 (D2, D2Length);
m <<= 1;
multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
m >>= 1;
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else
{
break;
}
}
else if (comparison2 == 0)
{
if ((m & 1) == 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else if (comparison < 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
break;
}
else
{
INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
break;
}
}
else if (comparison < 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
if (FLOAT_TO_INTBITS (z) == EXPONENT_MASK)
break;
INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
}
while (1);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
return z;
OutOfMemory:
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
FLOAT_TO_INTBITS (z) = -2;
return z;
}
#if defined(WIN32)
#pragma optimize("",on) /*restore optimizations */
#endif
KFloat
Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e)
{
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
std::string utf8;
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
const char *str = utf8.c_str();
auto flt = createFloat (str, e);
if (((I_32) FLOAT_TO_INTBITS (flt)) >= 0)
{
return flt;
}
else if (((I_32) FLOAT_TO_INTBITS (flt)) == (I_32) - 1)
{ /* NumberFormatException */
ThrowNumberFormatException();
}
else
{ /* OutOfMemoryError */
ThrowOutOfMemoryError();
}
return 0.0;
}
+523
View File
@@ -0,0 +1,523 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !defined(hycomp_h)
#define hycomp_h
// TODO: Move to settings
#define MACOSX
/**
* USE_PROTOTYPES: Use full ANSI prototypes.
*
* CLOCK_PRIMS: We want the timer/clock prims to be used
*
* LITTLE_ENDIAN: This is for the intel machines or other
* little endian processors. Defaults to big endian.
*
* NO_LVALUE_CASTING: This is for compilers that don't like the left side
* of assigns to be cast. It hacks around to do the
* right thing.
*
* ATOMIC_FLOAT_ACCESS: So that float operations will work.
*
* LINKED_USER_PRIMITIVES: Indicates that user primitives are statically linked
* with the VM executeable.
*
* OLD_SPACE_SIZE_DIFF: The 68k uses a different amount of old space.
* This "legitimizes" the change.
*
* SIMPLE_SIGNAL: For machines that don't use real signals in C.
* (eg: PC, 68k)
*
* OS_NAME_LOOKUP: Use nlist to lookup user primitive addresses.
*
* VMCALL: Tag for all functions called by the VM.
*
* VMAPICALL: Tag for all functions called via the PlatformFunction
* callWith: mechanism.
*
* SYS_FLOAT: For some math functions where extended types (80 or 96 bits) are returned
* Most platforms return as a double
*
* FLOAT_EXTENDED: If defined, the type name for extended precision floats.
*
* PLATFORM_IS_ASCII: Must be defined if the platform is ASCII
*
* EXE_EXTENSION_CHAR: the executable has a delimiter that we want to stop at as part of argv[0].
*/
/**
* By default order doubles in the native (that is big/little endian) ordering.
*/
#define HY_PLATFORM_DOUBLE_ORDER
/**
* Define common types:
* <ul>
* <li><code>U_32 / I_32</code> - unsigned/signed 32 bits</li>
* <li><code>U_16 / I_16</code> - unsigned/signed 16 bits</li>
* <li><code>U_8 / I_8</code> - unsigned/signed 8 bits (bytes -- not to be
* confused with char)</li>
* </ul>
*/
typedef int I_32;
typedef short I_16;
typedef signed char I_8; /* chars can be unsigned */
typedef unsigned int U_32;
typedef unsigned short U_16;
typedef unsigned char U_8;
/**
* Define platform specific types:
* <ul>
* <li><code>U_64 / I_64</code> - unsigned/signed 64 bits</li>
* </ul>
*/
#if defined(LINUX) || defined(FREEBSD) || defined(AIX) || defined(MACOSX)
#define DATA_TYPES_DEFINED
/* NOTE: Linux supports different processors -- do not assume 386 */
#if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X)
typedef unsigned long int U_64; /* 64bits */
typedef long int I_64;
#define TOC_UNWRAP_ADDRESS(wrappedPointer) ((void *) (wrappedPointer)[0])
#define TOC_STORE_TOC(dest,wrappedPointer) (dest = ((UDATA*)wrappedPointer)[1])
#define HY_WORD64
#else
typedef long long I_64;
typedef unsigned long long U_64;
#endif
#if defined(HYS390X) || defined(HYS390) || defined(HYPPC64) || defined(HYPPC32)
#define HY_BIG_ENDIAN
#else
#define HY_LITTLE_ENDIAN
#endif
#if defined(HYPPC32) && defined(LINUX)
#define VA_PTR(valist) (&valist[0])
#endif
typedef double SYS_FLOAT;
#define HYCONST64(x) x##LL
#define NO_LVALUE_CASTING
#define FLOAT_EXTENDED long double
#define PLATFORM_IS_ASCII
#define PLATFORM_LINE_DELIMITER "\012"
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_STR "/"
#define PATH_SEPARATOR ':'
#define PATH_SEPARATOR_STR ":"
#if defined(AIX)
#define LIBPATH_ENV_VAR "LIBPATH"
#else
#if defined(MACOSX)
#define LIBPATH_ENV_VAR "DYLD_LIBRARY_PATH"
#else
#define LIBPATH_ENV_VAR "LD_LIBRARY_PATH"
#endif
#endif
#if defined(MACOSX)
#define PLATFORM_DLL_EXTENSION ".dylib"
#else
#define PLATFORM_DLL_EXTENSION ".so"
#endif
/**
* No priorities on Linux
*/
#define HY_PRIORITY_MAP {0,0,0,0,0,0,0,0,0,0,0,0}
typedef U_32 BOOLEAN;
#endif
/* Win32 - Windows 3.1 & NT using Win32 */
#if defined(WIN32)
#define HY_LITTLE_ENDIAN
/* Define 64-bit integers for Windows */
typedef __int64 I_64;
typedef unsigned __int64 U_64;
typedef double SYS_FLOAT;
#define NO_LVALUE_CASTING
#define VMAPICALL _stdcall
#define VMCALL _cdecl
#define EXE_EXTENSION_CHAR '.'
#define DIR_SEPARATOR '\\'
#define DIR_SEPARATOR_STR "\\"
#define PATH_SEPARATOR ';'
#define PATH_SEPARATOR_STR ";"
#define LIBPATH_ENV_VAR "PATH"
/* Modifications for the Alpha running WIN-NT */
#if defined(_ALPHA_)
#undef small /* defined as char in rpcndr.h */
typedef double FLOAT_EXTENDED;
#endif
#define HY_PRIORITY_MAP { \
THREAD_PRIORITY_IDLE, /* 0 */\
THREAD_PRIORITY_LOWEST, /* 1 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 2 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 3 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 4 */\
THREAD_PRIORITY_NORMAL, /* 5 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 6 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 7 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 8 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 9 */\
THREAD_PRIORITY_HIGHEST, /*10 */\
THREAD_PRIORITY_TIME_CRITICAL /*11 */}
#endif /* defined(WIN32) */
#if defined(ZOS)
#define HY_BIG_ENDIAN
#define DATA_TYPES_DEFINED
typedef unsigned int BOOLEAN;
#if defined (HYS390X)
typedef unsigned long U_64;
typedef long I_64;
#else
typedef signed long long I_64;
typedef unsigned long long U_64;
#endif
typedef double SYS_FLOAT;
#define HYCONST64(x) x##LL
#define NO_LVALUE_CASTING
#define PLATFORM_LINE_DELIMITER "\012"
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_STR "/"
#define PATH_SEPARATOR ':'
#define PATH_SEPARATOR_STR ":"
#define LIBPATH_ENV_VAR "LIBPATH"
#define VA_PTR(valist) (&valist[0])
typedef struct {
#if !defined(HYS390X)
char stuff[16];
#endif
char *ada;
void (*rawFnAddress)();
} HyFunctionDescriptor_T;
#define TOC_UNWRAP_ADDRESS(wrappedPointer) (((HyFunctionDescriptor_T *) (wrappedPointer))->rawFnAddress)
#define PLATFORM_DLL_EXTENSION ".so"
#ifdef HYS390X
#ifndef HY_WORD64
#define HY_WORD64
#endif /* ifndef HY_WORD64 */
#endif /* HYS390X */
#endif /* ZOS */
#if !defined(VMCALL)
#define VMCALL
#define VMAPICALL
#endif
#define PVMCALL VMCALL *
#define GLOBAL_DATA(symbol) ((void*)&(symbol))
#define GLOBAL_TABLE(symbol) GLOBAL_DATA(symbol)
/**
* Define platform specific types:
* <ul>
* <li><code>UDATA</code> - unsigned data, can be used as an integer or
* pointer storage</li>
* <li><code>IDATA</code> - signed data, can be used as an integer or
* pointer storage</li>
* </ul>
*/
/* FIXME: POINTER64 */
#if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X) || defined(POINTER64)
typedef I_64 IDATA;
typedef U_64 UDATA;
#else /* this is default for non-64bit systems */
typedef I_32 IDATA;
typedef U_32 UDATA;
#endif /* defined(HYX86_64) */
#if !defined(DATA_TYPES_DEFINED)
/* no generic U_64 or I_64 */
/* don't typedef BOOLEAN since it's already def'ed on Win32 */
#define BOOLEAN UDATA
#ifndef HY_BIG_ENDIAN
#define HY_LITTLE_ENDIAN
#endif
#endif
#if !defined(HYCONST64)
#define HYCONST64(x) x##L
#endif
#if !defined(HY_DEFAULT_SCHED)
/**
* By default, pthreads platforms use the <code>SCHED_OTHER</code> thread
* scheduling policy.
*/
#define HY_DEFAULT_SCHED SCHED_OTHER
#endif
#if !defined(HY_PRIORITY_MAP)
/**
* If no priority map if provided, priorities will be determined
* algorithmically.
*/
#endif
#if !defined(FALSE)
#define FALSE ((BOOLEAN) 0)
#if !defined(TRUE)
#define TRUE ((BOOLEAN) (!FALSE))
#endif
#endif
#if !defined(NULL)
#if defined(__cplusplus)
#define NULL (0)
#else
#define NULL ((void *)0)
#endif
#endif
#define USE_PROTOTYPES
#if defined(USE_PROTOTYPES)
#define PROTOTYPE(x) x
#define VARARGS , ...
#else
#define PROTOTYPE(x) ()
#define VARARGS
#endif
/**
* Assign the default line delimiter, if it was not set.
*/
#if !defined(PLATFORM_LINE_DELIMITER)
#define PLATFORM_LINE_DELIMITER "\015\012"
#endif
/**
* Set the max path length, if it was not set.
*/
#if !defined(MAX_IMAGE_PATH_LENGTH)
#define MAX_IMAGE_PATH_LENGTH (2048)
#endif
typedef double ESDOUBLE;
typedef float ESSINGLE;
/**
* Helpers for U_64s.
*/
#define CLEAR_U64(u64) (u64 = (U_64)0)
#define LOW_LONG(l) (*((U_32 *) &(l)))
#define HIGH_LONG(l) (*(((U_32 *) &(l)) + 1))
#define I8(x) ((I_8) (x))
#define I8P(x) ((I_8 *) (x))
#define U16(x) ((U_16) (x))
#define I16(x) ((I_16) (x))
#define I16P(x) ((I_16 *) (x))
#define U32(x) ((U_32) (x))
#define I32(x) ((I_32) (x))
#define I32P(x) ((I_32 *) (x))
#define U16P(x) ((U_16 *) (x))
#define U32P(x) ((U_32 *) (x))
#define OBJP(x) ((HyObject *) (x))
#define OBJPP(x) ((HyObject **) (x))
#define OBJPPP(x) ((HyObject ***) (x))
#define CLASSP(x) ((Class *) (x))
#define CLASSPP(x) ((Class **) (x))
#define BYTEP(x) ((BYTE *) (x))
/**
* Test - was conflicting with OS2.h
*/
#define ESCHAR(x) ((CHARACTER) (x))
#define FLT(x) ((FLOAT) x)
#define FLTP(x) ((FLOAT *) (x))
#if defined(NO_LVALUE_CASTING)
#define LI8(x) (*((I_8 *) &(x)))
#define LI8P(x) (*((I_8 **) &(x)))
#define LU16(x) (*((U_16 *) &(x)))
#define LI16(x) (*((I_16 *) &(x)))
#define LU32(x) (*((U_32 *) &(x)))
#define LI32(x) (*((I_32 *) &(x)))
#define LI32P(x) (*((I_32 **) &(x)))
#define LU16P(x) (*((U_16 **) &(x)))
#define LU32P(x) (*((U_32 **) &(x)))
#define LOBJP(x) (*((HyObject **) &(x)))
#define LOBJPP(x) (*((HyObject ***) &(x)))
#define LOBJPPP(x) (*((HyObject ****) &(x))
#define LCLASSP(x) (*((Class **) &(x)))
#define LBYTEP(x) (*((BYTE **) &(x)))
#define LCHAR(x) (*((CHARACTER) &(x)))
#define LFLT(x) (*((FLOAT) &x))
#define LFLTP(x) (*((FLOAT *) &(x)))
#else
#define LI8(x) I8((x))
#define LI8P(x) I8P((x))
#define LU16(x) U16((x))
#define LI16(x) I16((x))
#define LU32(x) U32((x))
#define LI32(x) I32((x))
#define LI32P(x) I32P((x))
#define LU16P(x) U16P((x))
#define LU32P(x) U32P((x))
#define LOBJP(x) OBJP((x))
#define LOBJPP(x) OBJPP((x))
#define LOBJPPP(x) OBJPPP((x))
#define LIOBJP(x) IOBJP((x))
#define LCLASSP(x) CLASSP((x))
#define LBYTEP(x) BYTEP((x))
#define LCHAR(x) CHAR((x))
#define LFLT(x) FLT((x))
#define LFLTP(x) FLTP((x))
#endif
/**
* Macros for converting between words and longs and accessing bits.
*/
#define HIGH_WORD(x) U16(U32((x)) >> 16)
#define LOW_WORD(x) U16(U32((x)) & 0xFFFF)
#define LOW_BIT(o) (U32((o)) & 1)
#define LOW_2_BITS(o) (U32((o)) & 3)
#define LOW_3_BITS(o) (U32((o)) & 7)
#define LOW_4_BITS(o) (U32((o)) & 15)
#define MAKE_32(h, l) ((U32((h)) << 16) | U32((l)))
#define MAKE_64(h, l) ((((I_64)(h)) << 32) | (l))
#if defined(__cplusplus)
#define HY_CFUNC "C"
#define HY_CDATA "C"
#else
#define HY_CFUNC
#define HY_CDATA
#endif
/**
* Macros for tagging functions which read/write the vm thread.
*/
#define READSVMTHREAD
#define WRITESVMTHREAD
#define REQUIRESSTACKFRAME
/**
* Macro for tagging functions, which never return.
*/
#if defined(__GNUC__)
/**
* On GCC, we can actually pass this information on to the compiler.
*/
#define NORETURN __attribute__((noreturn))
#else
#define NORETURN
#endif
/**
* On some systems va_list is an array type. This is probably in
* violation of the ANSI C spec, but it's not entirely clear. Because of
* this, we end up with an undesired extra level of indirection if we take
* the address of a va_list argument.
*
* To get it right, always use the VA_PTR macro
*/
#if !defined(VA_PTR)
#define VA_PTR(valist) (&valist)
#endif
#if !defined(TOC_UNWRAP_ADDRESS)
#define TOC_UNWRAP_ADDRESS(wrappedPointer) (wrappedPointer)
#endif
#if !defined(TOC_STORE_TOC)
#define TOC_STORE_TOC(dest,wrappedPointer)
#endif
/**
* Macros for accessing I_64 values.
*/
#if defined(ATOMIC_LONG_ACCESS)
#define PTR_LONG_STORE(dstPtr, aLongPtr) ((*U32P(dstPtr) = *U32P(aLongPtr)), (*(U32P(dstPtr)+1) = *(U32P(aLongPtr)+1)))
#define PTR_LONG_VALUE(dstPtr, aLongPtr) ((*U32P(aLongPtr) = *U32P(dstPtr)), (*(U32P(aLongPtr)+1) = *(U32P(dstPtr)+1)))
#else
#define PTR_LONG_STORE(dstPtr, aLongPtr) (*(dstPtr) = *(aLongPtr))
#define PTR_LONG_VALUE(dstPtr, aLongPtr) (*(aLongPtr) = *(dstPtr))
#endif
/**
* Macro used when declaring tables which require relocations.
*/
#if !defined(HYCONST_TABLE)
#define HYCONST_TABLE const
#endif
/**
* ANSI qsort is not always available.
*/
#if !defined(HY_SORT)
#define HY_SORT(base, nmemb, size, compare) qsort((base), (nmemb), (size), (compare))
#endif
/**
* Helper macros for storing/restoring pointers to jlong.
*/
#define jlong2addr(a, x) ((a *)((IDATA)(x)))
#define addr2jlong(x) ((jlong)((IDATA)(x)))
#endif /* hycomp_h */
@@ -0,0 +1,415 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package konan.internal
import kotlin.comparisons.*
/**
* Takes a String and an integer exponent. The String should hold a positive
* integer value (or zero). The exponent will be used to calculate the
* floating point number by taking the positive integer the String
* represents and multiplying by 10 raised to the power of the
* exponent. Returns the closest double value to the real number.
* @param s
* * the String that will be parsed to a floating point
* *
* @param e
* * an int represent the 10 to part
* *
* @return the double closest to the real number
* *
* *
* @exception NumberFormatException
* * if the String doesn't represent a positive integer value
*/
@SymbolName("Konan_FloatingPointParser_parseDoubleImpl")
private external fun parseDoubleImpl(s: String, e: Int): Double
/**
* Takes a String and an integer exponent. The String should hold a positive
* integer value (or zero). The exponent will be used to calculate the
* floating point number by taking the positive integer the String
* represents and multiplying by 10 raised to the power of the
* exponent. Returns the closest float value to the real number.
* @param s
* * the String that will be parsed to a floating point
* *
* @param e
* * an int represent the 10 to part
* *
* @return the float closest to the real number
* *
* *
* @exception NumberFormatException
* * if the String doesn't represent a positive integer value
*/
@SymbolName("Konan_FloatingPointParser_parseFloatImpl")
private external fun parseFloatImpl(s: String, e: Int): Float
/**
* Used to parse a string and return either a single or double precision
* floating point number.
*/
object FloatingPointParser {
/*
* All number with exponent larger than MAX_EXP can be treated as infinity.
* All number with exponent smaller than MIN_EXP can be treated as zero.
* Exponent is 10 based.
* Eg. double's min value is 5e-324, so double "1e-325" should be parsed as 0.0
*/
private val FLOAT_MIN_EXP = -46
private val FLOAT_MAX_EXP = 38
private val DOUBLE_MIN_EXP = -324
private val DOUBLE_MAX_EXP = 308
private class StringExponentPair(var s: String, var e: Int, var negative: Boolean)
/**
* Takes a String and does some initial parsing. Should return a
* StringExponentPair containing a String with no leading or trailing white
* space and trailing zeroes eliminated. The exponent of the
* StringExponentPair will be used to calculate the floating point number by
* taking the positive integer the String represents and multiplying by 10
* raised to the power of the exponent.
* @param s
* * the String that will be parsed to a floating point
* *
* @param length
* * the length of s
* *
* @return a StringExponentPair with necessary values
* *
* *
* @exception NumberFormatException
* * if the String doesn't pass basic tests
*/
private fun initialParse(s: String, length: Int): StringExponentPair {
var s = s
var length = length
var negative = false
var c: Char
var start: Int
var end: Int
val decimal: Int
var shift: Int
var e = 0
start = 0
if (length == 0)
throw NumberFormatException(s)
c = s[length - 1]
if (c == 'D' || c == 'd' || c == 'F' || c == 'f') {
length--
if (length == 0)
throw NumberFormatException(s)
}
end = maxOf(s.indexOf('E'), s.indexOf('e'))
if (end > -1) {
if (end + 1 == length)
throw NumberFormatException(s)
var exponent_offset = end + 1
if (s[exponent_offset] == '+') {
if (s[exponent_offset + 1] == '-') {
throw NumberFormatException(s)
}
exponent_offset++ // skip the plus sign
if (exponent_offset == length)
throw NumberFormatException(s)
}
val strExp = s.substring(exponent_offset, length)
try {
e = strExp.toInt()
} catch (ex: NumberFormatException) {
// strExp is not empty, so there are 2 situations the exception be thrown
// if the string is invalid we should throw exception, if the actual number
// is out of the range of Integer, we can still parse the original number to
// double or float.
var ch: Char
for (i in 0..strExp.length - 1) {
ch = strExp[i]
if (ch < '0' || ch > '9') {
if (i == 0 && ch == '-')
continue
// ex contains the exponent substring only so throw
// a new exception with the correct string.
throw NumberFormatException(s)
}
}
e = if (strExp[0] == '-') Int.MIN_VALUE else Int.MAX_VALUE
}
} else {
end = length
}
if (length == 0)
throw NumberFormatException(s)
c = s[start]
if (c == '-') {
++start
--length
negative = true
} else if (c == '+') {
++start
--length
}
if (length == 0)
throw NumberFormatException(s)
decimal = s.indexOf('.')
if (decimal > -1) {
shift = end - decimal - 1
// Prevent e overflow, shift >= 0.
if (e >= 0 || e - Int.MIN_VALUE > shift) {
e -= shift
}
s = s.substring(start, decimal) + s.substring(decimal + 1, end)
} else {
s = s.substring(start, end)
}
length = s.length
if (length == 0)
throw NumberFormatException()
end = length
while (end > 1 && s[end - 1] == '0')
--end
start = 0
while (start < end - 1 && s[start] == '0')
start++
if (end != length || start != 0) {
shift = length - end
if (e <= 0 || Int.MAX_VALUE - e > shift) {
e += shift
}
s = s.substring(start, end)
}
// Trim the length of very small numbers, natives can only handle down to E-309.
val APPROX_MIN_MAGNITUDE = -359
val MAX_DIGITS = 52
length = s.length
if (length > MAX_DIGITS && e < APPROX_MIN_MAGNITUDE) {
val d = minOf(APPROX_MIN_MAGNITUDE - e, length - 1)
s = s.substring(0, length - d)
e += d
}
return StringExponentPair(s, e, negative)
}
/*
* Assumes the string is trimmed.
*/
private fun parseDoubleName(namedDouble: String, length: Int): Double {
// Valid strings are only +Nan, NaN, -Nan, +Infinity, Infinity, -Infinity.
if (length != 3 && length != 4 && length != 8 && length != 9) {
throw NumberFormatException()
}
var negative = false
var cmpstart = 0
when (namedDouble[0]) {
'-' -> {
negative = true
cmpstart = 1
}
'+' -> cmpstart = 1
}
if (namedDouble.regionMatches(cmpstart, "Infinity", 0, 8, ignoreCase = false)) {
return if (negative)
Double.NEGATIVE_INFINITY
else
Double.POSITIVE_INFINITY
}
if (namedDouble.regionMatches(cmpstart, "NaN", 0, 3, ignoreCase = false)) {
return Double.NaN
}
throw NumberFormatException()
}
/*
* Assumes the string is trimmed.
*/
private fun parseFloatName(namedFloat: String, length: Int): Float {
// Valid strings are only +Nan, NaN, -Nan, +Infinity, Infinity, -Infinity.
if (length != 3 && length != 4 && length != 8 && length != 9) {
throw NumberFormatException()
}
var negative = false
var cmpstart = 0
when (namedFloat[0]) {
'-' -> {
negative = true
cmpstart = 1
}
'+' -> cmpstart = 1
}
if (namedFloat.regionMatches(cmpstart, "Infinity", 0, 8, ignoreCase = false)) {
return if (negative) Float.NEGATIVE_INFINITY else Float.POSITIVE_INFINITY
}
if (namedFloat.regionMatches(cmpstart, "NaN", 0, 3, ignoreCase = false)) {
return Float.NaN
}
throw NumberFormatException()
}
/*
* Answers true if the string should be parsed as a hex encoding.
* Assumes the string is trimmed.
*/
private fun parseAsHex(s: String): Boolean {
val length = s.length
if (length < 2) {
return false
}
var first = s[0]
var second = s[1]
if (first == '+' || first == '-') {
// Move along.
if (length < 3) {
return false
}
first = second
second = s[2]
}
return first == '0' && (second == 'x' || second == 'X')
}
/**
* Returns the closest double value to the real number in the string.
* @param s
* * the String that will be parsed to a floating point
* *
* @return the double closest to the real number
* *
* *
* @exception NumberFormatException
* * if the String doesn't represent a double
*/
fun parseDouble(s: String): Double {
var s = s
s = s.trim { it <= ' ' }
val length = s.length
if (length == 0) {
throw NumberFormatException(s)
}
// See if this could be a named double.
val last = s[length - 1]
if (last == 'y' || last == 'N') {
return parseDoubleName(s, length)
}
// See if it could be a hexadecimal representation.
if (parseAsHex(s)) {
TODO("Hex format is not supported")
//return HexStringParser.parseDouble(s)
}
val info = initialParse(s, length)
// Two kinds of situation will directly return 0.0:
// 1. info.s is 0;
// 2. actual exponent is less than Double.MIN_EXPONENT.
if ("0" == info.s || info.e + info.s.length - 1 < DOUBLE_MIN_EXP) {
return if (info.negative) -0.0 else 0.0
}
// If actual exponent is larger than Double.MAX_EXPONENT, return infinity.
// Prevent overflow, check twice.
if (info.e > DOUBLE_MAX_EXP || info.e + info.s.length - 1 > DOUBLE_MAX_EXP) {
return if (info.negative) Double.NEGATIVE_INFINITY else Double.POSITIVE_INFINITY
}
var result = parseDoubleImpl(info.s, info.e)
if (info.negative)
result = -result
return result
}
/**
* Returns the closest float value to the real number in the string.
* @param s
* * the String that will be parsed to a floating point
* *
* @return the float closest to the real number
* *
* *
* @exception NumberFormatException
* * if the String doesn't represent a float
*/
fun parseFloat(s: String): Float {
var s = s
s = s.trim { it <= ' ' }
val length = s.length
if (length == 0) {
throw NumberFormatException(s)
}
// See if this could be a named float.
val last = s[length - 1]
if (last == 'y' || last == 'N') {
return parseFloatName(s, length)
}
// See if it could be a hexadecimal representation.
if (parseAsHex(s)) {
TODO("Hex format is not supported")
//return HexStringParser.parseFloat(s)
}
val info = initialParse(s, length)
// Two kinds of situation will directly return 0.0f.
// 1. info.s is 0;
// 2. actual exponent is less than Float.MIN_EXPONENT.
if ("0" == info.s || info.e + info.s.length - 1 < FLOAT_MIN_EXP) {
return if (info.negative) -0.0f else 0.0f
}
// If actual exponent is larger than Float.MAX_EXPONENT, return infinity.
// Prevent overflow, check twice.
if (info.e > FLOAT_MAX_EXP || info.e + info.s.length - 1 > FLOAT_MAX_EXP) {
return if (info.negative) Float.NEGATIVE_INFINITY else Float.POSITIVE_INFINITY
}
var result = parseFloatImpl(info.s, info.e)
if (info.negative)
result = -result
return result
}
}
@@ -0,0 +1,366 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package konan.internal
// TODO: Enable as soon as regexes are supported.
/*
* Parses hex string to a single or double precision floating point number.
*/
//internal class HexStringParser(private val EXPONENT_WIDTH: Int, private val MANTISSA_WIDTH: Int) {
//
// private val EXPONENT_BASE: Long
//
// private val MAX_EXPONENT: Long
//
// private val MIN_EXPONENT: Long
//
// private val MANTISSA_MASK: Long
//
// private var sign: Long = 0
//
// private var exponent: Long = 0
//
// private var mantissa: Long = 0
//
// private var abandonedNumber = "" //$NON-NLS-1$
//
// init {
//
// this.EXPONENT_BASE = (-1L shl EXPONENT_WIDTH - 1).inv()
// this.MAX_EXPONENT = (-1L shl EXPONENT_WIDTH).inv()
// this.MIN_EXPONENT = (-(MANTISSA_WIDTH + 1)).toLong()
// this.MANTISSA_MASK = (-1L shl MANTISSA_WIDTH).inv()
// }
//
// private fun parse(hexString: String): Long {
// val hexSegments = getSegmentsFromHexString(hexString)
// val signStr = hexSegments[0]
// val significantStr = hexSegments[1]
// val exponentStr = hexSegments[2]
//
// parseHexSign(signStr)
// parseExponent(exponentStr)
// parseMantissa(significantStr)
//
// sign = sign shl (MANTISSA_WIDTH + EXPONENT_WIDTH)
// exponent = exponent shl MANTISSA_WIDTH
// return sign or exponent or mantissa
// }
//
// /*
// * Parses the sign field.
// */
// private fun parseHexSign(signStr: String) {
// this.sign = (if (signStr == "-") 1 else 0).toLong() //$NON-NLS-1$
// }
//
// /*
// * Parses the exponent field.
// */
// private fun parseExponent(exponentStr: String) {
// var exponentStr = exponentStr
// val leadingChar = exponentStr[0]
// val expSign = if (leadingChar == '-') -1 else 1
// if (!Character.isDigit(leadingChar)) {
// exponentStr = exponentStr.substring(1)
// }
//
// try {
// exponent = expSign * exponentStr.toLong()
// checkedAddExponent(EXPONENT_BASE)
// } catch (e: NumberFormatException) {
// exponent = expSign * Long.MAX_VALUE
// }
//
// }
//
// /*
// * Parses the mantissa field.
// */
// private fun parseMantissa(significantStr: String) {
// val strings = significantStr.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() //$NON-NLS-1$
// val strIntegerPart = strings[0]
// val strDecimalPart = if (strings.size > 1) strings[1] else "" //$NON-NLS-1$
//
// var significand = getNormalizedSignificand(strIntegerPart, strDecimalPart)
// if (significand == "0") { //$NON-NLS-1$
// setZero()
// return
// }
//
// val offset = getOffset(strIntegerPart, strDecimalPart)
// checkedAddExponent(offset.toLong())
//
// if (exponent >= MAX_EXPONENT) {
// setInfinite()
// return
// }
//
// if (exponent <= MIN_EXPONENT) {
// setZero()
// return
// }
//
// if (significand.length > MAX_SIGNIFICANT_LENGTH) {
// abandonedNumber = significand.substring(MAX_SIGNIFICANT_LENGTH)
// significand = significand.substring(0, MAX_SIGNIFICANT_LENGTH)
// }
//
// mantissa = significand.toLong(HEX_RADIX)
//
// if (exponent >= 1) {
// processNormalNumber()
// } else {
// processSubNormalNumber()
// }
//
// }
//
// private fun setInfinite() {
// exponent = MAX_EXPONENT
// mantissa = 0
// }
//
// private fun setZero() {
// exponent = 0
// mantissa = 0
// }
//
// private fun signum(x: Long) = when {
// x == 0L -> 0
// x > 0L -> 1
// else -> -1
// }
//
// /*
// * Sets the exponent variable to Long.MAX_VALUE or -Long.MAX_VALUE if
// * overflow or underflow happens.
// */
// private fun checkedAddExponent(offset: Long) {
// val result = exponent + offset
// val expSign = signum(exponent)
// if (expSign * signum(offset) > 0 && expSign * signum(result) < 0) {
// exponent = expSign * Long.MAX_VALUE
// } else {
// exponent = result
// }
// }
//
// private fun processNormalNumber() {
// val desiredWidth = MANTISSA_WIDTH + 2
// fitMantissaInDesiredWidth(desiredWidth)
// round()
// mantissa = mantissa and MANTISSA_MASK
// }
//
// private fun processSubNormalNumber() {
// var desiredWidth = MANTISSA_WIDTH + 1
// desiredWidth += exponent.toInt()//lends bit from mantissa to exponent
// exponent = 0
// fitMantissaInDesiredWidth(desiredWidth)
// round()
// mantissa = mantissa and MANTISSA_MASK
// }
//
// /*
// * Adjusts the mantissa to desired width for further analysis.
// */
// private fun fitMantissaInDesiredWidth(desiredWidth: Int) {
// val bitLength = countBitsLength(mantissa)
// if (bitLength > desiredWidth) {
// discardTrailingBits((bitLength - desiredWidth).toLong())
// } else {
// mantissa = mantissa shl (desiredWidth - bitLength)
// }
// }
//
// /*
// * Stores the discarded bits to abandonedNumber.
// */
// private fun discardTrailingBits(num: Long) {
// val mask = (-1L shl num.toInt()).inv()
// abandonedNumber += mantissa and mask
// mantissa = mantissa shr num.toInt()
// }
//
// /*
// * The value is rounded up or down to the nearest infinitely precise result.
// * If the value is exactly halfway between two infinitely precise results,
// * then it should be rounded up to the nearest infinitely precise even.
// */
// private fun round() {
// val result = abandonedNumber.replace("0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
// val moreThanZero = result.length > 0
//
// val lastDiscardedBit = (mantissa and 1L).toInt()
// mantissa = mantissa shr 1
// val tailBitInMantissa = (mantissa and 1L).toInt()
//
// if (lastDiscardedBit == 1 && (moreThanZero || tailBitInMantissa == 1)) {
// val oldLength = countBitsLength(mantissa)
// mantissa += 1L
// val newLength = countBitsLength(mantissa)
//
// //Rounds up to exponent when whole bits of mantissa are one-bits.
// if (oldLength >= MANTISSA_WIDTH && newLength > oldLength) {
// checkedAddExponent(1)
// }
// }
// }
//
// /*
// * Returns the normalized significand after removing the leading zeros.
// */
// private fun getNormalizedSignificand(strIntegerPart: String, strDecimalPart: String): String {
// var significand = strIntegerPart + strDecimalPart
// significand = significand.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$//$NON-NLS-2$
// if (significand.length == 0) {
// significand = "0" //$NON-NLS-1$
// }
// return significand
// }
//
// /*
// * Calculates the offset between the normalized number and unnormalized
// * number. In a normalized representation, significand is represented by the
// * characters "0x1." followed by a lowercase hexadecimal representation of
// * the rest of the significand as a fraction.
// */
// private fun getOffset(strIntegerPart: String, strDecimalPart: String): Int {
// var strIntegerPart = strIntegerPart
// strIntegerPart = strIntegerPart.replaceFirst("^0+".toRegex(), "") //$NON-NLS-1$ //$NON-NLS-2$
//
// // If the Integer part is a nonzero number.
// if (strIntegerPart.length != 0) {
// val leadingNumber = strIntegerPart.substring(0, 1)
// return (strIntegerPart.length - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
// }
//
// // If the Integer part is a zero number.
// var i = 0
// while (i < strDecimalPart.length && strDecimalPart[i] == '0') {
// i++
// }
// if (i == strDecimalPart.length) {
// return 0
// }
// val leadingNumber = strDecimalPart.substring(i, i + 1)
// return (-i - 1) * 4 + countBitsLength(leadingNumber.toLong(HEX_RADIX)) - 1
// }
//
// fun numberOfLeadingZeros(i: Long): Int {
// // HD, Figure 5-6
// if (i == 0L)
// return 64
// var n = 1
// var x = (i ushr 32).toInt()
// if (x == 0) {
// n += 32
// x = i.toInt()
// }
// if (x ushr 16 == 0) {
// n += 16
// x = x shl 16
// }
// if (x ushr 24 == 0) {
// n += 8
// x = x shl 8
// }
// if (x ushr 28 == 0) {
// n += 4
// x = x shl 4
// }
// if (x ushr 30 == 0) {
// n += 2
// x = x shl 2
// }
// n -= x ushr 31
// return n
// }
//
// private fun countBitsLength(value: Long): Int {
// val leadingZeros = numberOfLeadingZeros(value)
// return java.lang.Long.SIZE - leadingZeros
// }
//
// companion object {
//
// private val DOUBLE_EXPONENT_WIDTH = 11
//
// private val DOUBLE_MANTISSA_WIDTH = 52
//
// private val FLOAT_EXPONENT_WIDTH = 8
//
// private val FLOAT_MANTISSA_WIDTH = 23
//
// private val HEX_RADIX = 16
//
// private val MAX_SIGNIFICANT_LENGTH = 15
//
// private val HEX_SIGNIFICANT = "0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)" //$NON-NLS-1$
//
// private val BINARY_EXPONENT = "[pP]([+-]?\\d+)" //$NON-NLS-1$
//
// private val FLOAT_TYPE_SUFFIX = "[fFdD]?" //$NON-NLS-1$
//
// private val HEX_PATTERN = "[\\x00-\\x20]*([+-]?)$HEX_SIGNIFICANT" + //$NON-NLS-1$
//
// BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*" //$NON-NLS-1$
//
// private val PATTERN = Pattern.compile(HEX_PATTERN)
//
// /*
// * Parses the hex string to a double number.
// */
// fun parseDouble(hexString: String): Double {
// val parser = HexStringParser(DOUBLE_EXPONENT_WIDTH,
// DOUBLE_MANTISSA_WIDTH)
// val result = parser.parse(hexString)
// return java.lang.Double.longBitsToDouble(result)
// }
//
// /*
// * Parses the hex string to a float number.
// */
// fun parseFloat(hexString: String): Float {
// val parser = HexStringParser(FLOAT_EXPONENT_WIDTH,
// FLOAT_MANTISSA_WIDTH)
// val result = parser.parse(hexString).toInt()
// return java.lang.Float.intBitsToFloat(result)
// }
//
// /*
// * Analyzes the hex string and extracts the sign and digit segments.
// */
// private fun getSegmentsFromHexString(hexString: String): Array<String> {
// val matcher = PATTERN.matcher(hexString)
// if (!matcher.matches()) {
// throw NumberFormatException()
// }
//
// val hexSegments = arrayOf(
// matcher.group(1),
// matcher.group(2),
// matcher.group(3)
// )
//
// return hexSegments
// }
// }
//}
@@ -0,0 +1,310 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package konan.internal
@SymbolName("Konan_NumberConverter_bigIntDigitGeneratorInstImpl")
private external fun bigIntDigitGeneratorInstImpl(results: IntArray, uArray: IntArray, f: Long, e: Int,
isDenormalized: Boolean, mantissaIsZero: Boolean, p: Int)
@SymbolName("Konan_NumberConverter_ceil")
private external fun ceil(x: Double): Double
class NumberConverter {
private var setCount: Int = 0 // Number of times u and k have been gotten.
private var getCount: Int = 0 // Number of times u and k have been set.
private val uArray = IntArray(64)
private var firstK: Int = 0
private fun convertDouble(inputNumber: Double): String {
val p = 1023 + 52 // The power offset (precision).
val signMask = 0x7FFFFFFFFFFFFFFFL + 1 // The mask to get the sign of.
// The number.
val eMask = 0x7FF0000000000000L // The mask to get the power bits.
val fMask = 0x000FFFFFFFFFFFFFL // The mask to get the significand.
// Bits.
val inputNumberBits = inputNumber.bits()
// The value of the sign... 0 is positive, ~0 is negative.
val signString = if (inputNumberBits and signMask == 0L) "" else "-"
// The value of the 'power bits' of the inputNumber.
val e = (inputNumberBits and eMask shr 52).toInt()
// The value of the 'significand bits' of the inputNumber.
var f = inputNumberBits and fMask
val mantissaIsZero = f == 0L
var pow = 0
var numBits = 52
if (e == 2047)
return if (mantissaIsZero) signString + "Infinity" else "NaN"
if (e == 0) {
if (mantissaIsZero)
return signString + "0.0"
if (f == 1L)
// Special case to increase precision even though 2 * Double.MIN_VALUE is 1.0e-323.
return signString + "4.9E-324"
pow = 1 - p // A denormalized number.
var ff = f
while (ff and 0x0010000000000000L == 0L) {
ff = ff shl 1
numBits--
}
} else {
// 0 < e < 2047.
// A "normalized" number.
f = f or 0x0010000000000000L
pow = e - p
}
if (-59 < pow && pow < 6 || pow == -59 && !mantissaIsZero)
longDigitGenerator(f, pow, e == 0, mantissaIsZero, numBits)
else
bigIntDigitGeneratorInstImpl(f, pow, e == 0, mantissaIsZero, numBits)
if (inputNumber >= 1e7 || inputNumber <= -1e7
|| inputNumber > -1e-3 && inputNumber < 1e-3)
return signString + freeFormatExponential()
return signString + freeFormat()
}
private fun convertFloat(inputNumber: Float): String {
val p = 127 + 23 // The power offset (precision).
val signMask = 0x7FFFFFFF + 1 // The mask to get the sign of the number.
val eMask = 0x7F800000 // The mask to get the power bits.
val fMask = 0x007FFFFF // The mask to get the significand bits.
val inputNumberBits = inputNumber.bits()
// The value of the sign... 0 is positive, ~0 is negative.
val signString = if (inputNumberBits and signMask == 0) "" else "-"
// The value of the 'power bits' of the inputNumber.
val e = inputNumberBits and eMask shr 23
// The value of the 'significand bits' of the inputNumber.
var f = inputNumberBits and fMask
val mantissaIsZero = f == 0
var pow = 0
var numBits = 23
if (e == 255)
return if (mantissaIsZero) signString + "Infinity" else "NaN"
if (e == 0) {
if (mantissaIsZero)
return signString + "0.0"
pow = 1 - p // A denormalized number.
if (f < 8) { // Want more precision with smallest values.
f = f shl 2
pow -= 2
}
var ff = f
while (ff and 0x00800000 == 0) {
ff = ff shl 1
numBits--
}
} else {
// 0 < e < 255.
// A "normalized" number.
f = f or 0x00800000
pow = e - p
}
if (-59 < pow && pow < 35 || pow == -59 && !mantissaIsZero)
longDigitGenerator(f.toLong(), pow, e == 0, mantissaIsZero, numBits)
else
bigIntDigitGeneratorInstImpl(f.toLong(), pow, e == 0, mantissaIsZero, numBits)
if (inputNumber >= 1e7f || inputNumber <= -1e7f
|| inputNumber > -1e-3f && inputNumber < 1e-3f)
return signString + freeFormatExponential()
return signString + freeFormat()
}
private fun freeFormatExponential(): String {
// Corresponds to process "Free-Format Exponential".
val formattedDecimal = CharArray(25)
formattedDecimal[0] = ('0' + uArray[getCount++])
formattedDecimal[1] = '.'
// The position the next character is to be inserted into formattedDecimal.
var charPos = 2
var k = firstK
val expt = k
while (true) {
k--
if (getCount >= setCount)
break
formattedDecimal[charPos++] = ('0' + uArray[getCount++])
}
if (k == expt - 1)
formattedDecimal[charPos++] = '0'
formattedDecimal[charPos++] = 'E'
return fromCharArray(formattedDecimal, 0, charPos) + expt.toString()
}
private fun freeFormat(): String {
// Corresponds to process "Free-Format".
val formattedDecimal = CharArray(25)
// The position the next character is to be inserted into formattedDecimal.
var charPos = 0
var k = firstK
if (k < 0) {
formattedDecimal[0] = '0'
formattedDecimal[1] = '.'
charPos += 2
for (i in k + 1 .. -1)
formattedDecimal[charPos++] = '0'
}
var u = uArray[getCount++]
do {
if (u != -1)
formattedDecimal[charPos++] = ('0' + u)
else if (k >= -1)
formattedDecimal[charPos++] = '0'
if (k == 0)
formattedDecimal[charPos++] = '.'
k--
u = if (getCount < setCount) uArray[getCount++] else -1
} while (u != -1 || k >= -1)
return fromCharArray(formattedDecimal, 0, charPos)
}
private fun bigIntDigitGeneratorInstImpl(f: Long, e: Int,
isDenormalized: Boolean, mantissaIsZero: Boolean, p: Int) {
val results = IntArray(3)
bigIntDigitGeneratorInstImpl(results, uArray, f, e, isDenormalized, mantissaIsZero, p)
setCount = results[0]
getCount = results[1]
firstK = results[2]
}
private fun longDigitGenerator(f: Long, e: Int, isDenormalized: Boolean,
mantissaIsZero: Boolean, p: Int) {
var r: Long
var s: Long
var m: Long
if (e >= 0) {
m = 1L shl e
if (!mantissaIsZero) {
r = f shl e + 1
s = 2
} else {
r = f shl e + 2
s = 4
}
} else {
m = 1
if (isDenormalized || !mantissaIsZero) {
r = f shl 1
s = 1L shl 1 - e
} else {
r = f shl 2
s = 1L shl 2 - e
}
}
val k = ceil((e + p - 1) * invLogOfTenBaseTwo - 1e-10).toInt()
if (k > 0) {
s *= TEN_TO_THE[k]
} else if (k < 0) {
val scale = TEN_TO_THE[-k]
r *= scale
m = if (m == 1L) scale else m * scale
}
if (r + m > s) { // Was M_plus.
firstK = k
} else {
firstK = k - 1
r *= 10
m *= 10
}
setCount = 0
getCount = setCount // Reset indices.
var low: Boolean
var high: Boolean
var u: Int
val si = longArrayOf(s, s shl 1, s shl 2, s shl 3)
while (true) {
// Set U to be floor (r / s) and r to be the remainder
// using a kind of "binary search" to find the answer.
// It's a lot quicker than actually dividing since we know
// the answer will be between 0 and 10.
u = 0
var remainder: Long
for (i in 3 downTo 0) {
remainder = r - si[i]
if (remainder >= 0) {
r = remainder
u += 1 shl i
}
}
low = r < m // Was M_minus.
high = r + m > s // Was M_plus.
if (low || high)
break
r *= 10
m *= 10
uArray[setCount++] = u
}
if (low && !high)
uArray[setCount++] = u
else if (high && !low)
uArray[setCount++] = u + 1
else if (r shl 1 < s)
uArray[setCount++] = u
else
uArray[setCount++] = u + 1
}
companion object {
private val invLogOfTenBaseTwo = 0.30102999566398114251
private val TEN_TO_THE = LongArray(20)
init {
TEN_TO_THE[0] = 1L
for (i in 1 until TEN_TO_THE.size) {
TEN_TO_THE[i] = TEN_TO_THE[i - 1] * 10
}
}
private val converter: NumberConverter
get() = NumberConverter()
fun convert(input: Double): String {
return converter.convertDouble(input)
}
fun convert(input: Float): String {
return converter.convertFloat(input)
}
}
}
@@ -45,6 +45,11 @@ internal fun ThrowNumberFormatException() : Nothing {
throw NumberFormatException()
}
@ExportForCppRuntime
internal fun ThrowOutOfMemoryError() : Nothing {
throw OutOfMemoryError()
}
fun ThrowNoWhenBranchMatchedException(): Nothing {
throw NoWhenBranchMatchedException()
}
+4 -4
View File
@@ -16,6 +16,8 @@
package kotlin
import konan.internal.NumberConverter
/**
* Represents a 8-bit signed integer.
* On the JVM, non-nullable values of this type are represented as values of the primitive type `byte`.
@@ -1151,8 +1153,7 @@ public final class Float : Number(), Comparable<Float> {
public override fun equals(other: Any?): Boolean =
other is Float && konan.internal.areEqualByValue(this, other)
@SymbolName("Kotlin_Float_toString")
external public override fun toString(): String
public override fun toString() = NumberConverter.convert(this)
public override fun hashCode(): Int {
return bits()
@@ -1371,8 +1372,7 @@ public final class Double : Number(), Comparable<Double> {
public override fun equals(other: Any?): Boolean =
other is Double && konan.internal.areEqualByValue(this, other)
@SymbolName("Kotlin_Double_toString")
external public override fun toString(): String
public override fun toString() = NumberConverter.convert(this)
public override fun hashCode(): Int {
return bits().hashCode()
@@ -16,6 +16,8 @@
package kotlin.text
import konan.internal.FloatingPointParser
/**
* Returns a string representation of this [Byte] value in the specified [radix].
*/
@@ -118,28 +120,22 @@ public inline fun String.toLong(): Long = toLongOrNull() ?: throw NumberFormatEx
@kotlin.internal.InlineOnly
public inline fun String.toLong(radix: Int): Long = toLongOrNull(radix) ?: throw NumberFormatException()
@SymbolName("Kotlin_String_parseFloat")
external private fun parseFloat(value: String): Float
/**
* Parses the string as a [Float] number and returns the result.
* @throws NumberFormatException if the string is not a valid representation of a number.
*/
@kotlin.internal.InlineOnly
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun String.toFloat(): Float = parseFloat(this)
public inline fun String.toFloat(): Float = FloatingPointParser.parseFloat(this)
@SymbolName("Kotlin_String_parseDouble")
external private fun parseDouble(value: String): Double
/**
* Parses the string as a [Double] number and returns the result.
* @throws NumberFormatException if the string is not a valid representation of a number.
*/
@kotlin.internal.InlineOnly
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun String.toDouble(): Double = parseDouble(this)
public inline fun String.toDouble(): Double = FloatingPointParser.parseDouble(this)
/**