blob: 7b923e9518beb4d92fd7c17d16d240f496d114bd [file] [log] [blame]
/*
* 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 "Double.h"
#include <decaf/lang/Long.h>
#include <decaf/lang/ArrayPointer.h>
#include <limits>
#include <sstream>
#include <string.h>
using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
////////////////////////////////////////////////////////////////////////////////
const int Double::SIZE = 64;
const double Double::MAX_VALUE = 1.7976931348623157e+308;
const double Double::MIN_VALUE = 5e-324;
const double Double::NaN = std::numeric_limits<double>::quiet_NaN();
const double Double::POSITIVE_INFINITY = std::numeric_limits<double>::infinity();
const double Double::NEGATIVE_INFINITY = -std::numeric_limits<double>::infinity();
const long long Double::DOUBLE_SIGN_MASK = 0x8000000000000000LL;
const long long Double::DOUBLE_EXPONENT_MASK = 0x7FF0000000000000LL;
const long long Double::DOUBLE_MANTISSA_MASK = 0x000FFFFFFFFFFFFFLL;
const long long Double::DOUBLE_NAN_BITS = DOUBLE_EXPONENT_MASK | 0x0008000000000000LL;
////////////////////////////////////////////////////////////////////////////////
Double::Double(double value) : value(value) {
}
////////////////////////////////////////////////////////////////////////////////
Double::Double(const String& value) : value(0) {
this->value = Double::parseDouble(value);
}
////////////////////////////////////////////////////////////////////////////////
int Double::compareTo(const Double& d) const {
return Double::compare(this->value, d.value);
}
////////////////////////////////////////////////////////////////////////////////
int Double::compareTo(const double& d) const {
return Double::compare(this->value, d);
}
////////////////////////////////////////////////////////////////////////////////
std::string Double::toString() const {
return Double::toString(this->value);
}
////////////////////////////////////////////////////////////////////////////////
bool Double::isInfinite() const {
return Double::isInfinite(this->value);
}
////////////////////////////////////////////////////////////////////////////////
bool Double::isNaN() const {
return Double::isNaN(this->value);
}
////////////////////////////////////////////////////////////////////////////////
int Double::compare(double d1, double d2) {
long long l1, l2 = 0;
long long NaNbits = Double::doubleToLongBits(Double::NaN);
if ((l1 = Double::doubleToLongBits(d1)) == NaNbits) {
if (Double::doubleToLongBits(d2) == NaNbits) {
return 0;
}
return 1;
}
if ((l2 = Double::doubleToLongBits(d2)) == NaNbits) {
return -1;
}
if (d1 == d2) {
if (l1 == l2) {
return 0;
}
// check for -0
return l1 > l2 ? 1 : -1;
}
return d1 > d2 ? 1 : -1;
}
////////////////////////////////////////////////////////////////////////////////
long long Double::doubleToLongBits(double value) {
long long longValue = 0;
memcpy(&longValue, &value, sizeof(double));
if ((longValue & DOUBLE_EXPONENT_MASK) == DOUBLE_EXPONENT_MASK) {
if (longValue & DOUBLE_MANTISSA_MASK) {
return DOUBLE_NAN_BITS;
}
}
return longValue;
}
////////////////////////////////////////////////////////////////////////////////
long long Double::doubleToRawLongBits(double value) {
long long longValue = 0;
memcpy(&longValue, &value, sizeof(double));
return longValue;
}
////////////////////////////////////////////////////////////////////////////////
bool Double::isInfinite(double value) {
return (value == POSITIVE_INFINITY) || (value == NEGATIVE_INFINITY);
}
////////////////////////////////////////////////////////////////////////////////
bool Double::isNaN(double value) {
return value != value;
}
////////////////////////////////////////////////////////////////////////////////
double Double::longBitsToDouble(long long bits) {
double result = 0;
memcpy(&result, &bits, sizeof(long long));
return result;
}
////////////////////////////////////////////////////////////////////////////////
double Double::parseDouble(const String& value) {
// TODO - This is not going to parse the formats we say we do.
float result = 0.0;
ArrayPointer<char> buffer(value.length() + 1);
value.getChars(0, value.length(), buffer.get(), value.length() + 1, 0);
istringstream stream(buffer.get());
stream >> result;
// Not everything got read, meaning there wasn't just a number here.
if (!stream.eof()) {
throw exceptions::NumberFormatException(
__FILE__, __LINE__, "Failed to parse a valid float from input string: %s", value.c_str());
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
std::string Double::toHexString(double value) {
/*
* Reference: http://en.wikipedia.org/wiki/IEEE_754
*/
if (value != value) {
return "NaN";
}
if (value == POSITIVE_INFINITY) {
return "Infinity";
}
if (value == NEGATIVE_INFINITY) {
return "-Infinity";
}
unsigned long long bitValue = Double::doubleToLongBits(value);
bool negative = (bitValue & 0x8000000000000000LL) != 0;
// mask exponent bits and shift down
unsigned long long exponent = (bitValue & 0x7FF0000000000000LL) >> 52;
// mask significand bits and shift up
unsigned long long significand = bitValue & 0x000FFFFFFFFFFFFFLL;
if (exponent == 0 && significand == 0) {
return (negative ? "-0x0.0p0" : "0x0.0p0");
}
// Start with sign and hex indicator
std::string hexString(negative ? "-0x" : "0x");
if (exponent == 0) {
// denormal (subnormal) value
hexString.append("0.");
// significand is 52-bits, so there can be 13 hex digits
unsigned int fractionDigits = 13;
// remove trailing hex zeros, so Integer.toHexString() won't print
// them
while ((significand != 0) && ((significand & 0xF) == 0)) {
significand >>= 4;
fractionDigits--;
}
// this assumes Integer.toHexString() returns lowercase characters
std::string hexSignificand = Long::toHexString(significand);
// if there are digits left, then insert some '0' chars first
if (significand != 0 && fractionDigits > hexSignificand.length()) {
int digitDiff = fractionDigits - (int) hexSignificand.length();
while (digitDiff-- != 0) {
hexString.append("0");
}
}
hexString.append(hexSignificand);
hexString.append("p-1022");
} else {
// normal value
hexString.append("1.");
// significand is 52-bits, so there can be 13 hex digits
unsigned int fractionDigits = 13;
// remove trailing hex zeros, so Integer.toHexString() won't print
// them
while ((significand != 0) && ((significand & 0xF) == 0)) {
significand >>= 4;
fractionDigits--;
}
// this assumes Integer.toHexString() returns lowercase characters
std::string hexSignificand = Long::toHexString(significand);
// if there are digits left, then insert some '0' chars first
if (significand != 0 && fractionDigits > hexSignificand.length()) {
int digitDiff = fractionDigits - (int) hexSignificand.length();
while (digitDiff-- != 0) {
hexString.append("0");
}
}
hexString.append(hexSignificand);
hexString.append("p");
// remove exponent's 'bias' and convert to a string
hexString.append(Long::toString(exponent - 1023));
}
return hexString;
}
////////////////////////////////////////////////////////////////////////////////
std::string Double::toString(double value) {
// TODO - This is not going to output to the format we say we do.
ostringstream stream;
stream << value;
return stream.str();
}
////////////////////////////////////////////////////////////////////////////////
Double Double::valueOf(double value) {
return Double(value);
}
////////////////////////////////////////////////////////////////////////////////
Double Double::valueOf(const String& value) {
return valueOf(parseDouble(value));
}