Ported harmony implementation of Double/Float <-> String
Double.toString(), Float.toString(), String.toFloat(), String.toDouble()
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user