blob: 6e77be62a92b27516f7b11b727484ee5b402344d [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 "Float.h"
#include <decaf/lang/Integer.h>
#include <decaf/lang/ArrayPointer.h>
#include <limits>
#include <string.h>
using namespace std;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
////////////////////////////////////////////////////////////////////////////////
const int Float::SIZE = 32;
const float Float::MAX_VALUE = 3.40282346638528860e+38f;
const float Float::MIN_VALUE = 1.40129846432481707e-45f;
const float Float::NaN = std::numeric_limits<float>::quiet_NaN();
const float Float::POSITIVE_INFINITY = std::numeric_limits<float>::infinity();
const float Float::NEGATIVE_INFINITY = -std::numeric_limits<float>::infinity();
const unsigned int Float::SINGLE_EXPONENT_MASK = 0x7F800000;
const unsigned int Float::SINGLE_MANTISSA_MASK = 0x007FFFFF;
const unsigned int Float::SINGLE_NAN_BITS = (SINGLE_EXPONENT_MASK | 0x00400000);
////////////////////////////////////////////////////////////////////////////////
Float::Float(float value) : value(value) {
}
////////////////////////////////////////////////////////////////////////////////
Float::Float(double value) : value((float) value) {
}
////////////////////////////////////////////////////////////////////////////////
Float::Float(const String& value) : value(0) {
this->value = Float::parseFloat(value);
}
////////////////////////////////////////////////////////////////////////////////
int Float::compareTo(const Float& f) const {
return Float::compare(this->value, f.value);
}
////////////////////////////////////////////////////////////////////////////////
int Float::compareTo(const float& f) const {
return Float::compare(this->value, f);
}
////////////////////////////////////////////////////////////////////////////////
std::string Float::toString() const {
return Float::toString(this->value);
}
////////////////////////////////////////////////////////////////////////////////
bool Float::isInfinite() const {
return Float::isInfinite(this->value);
}
////////////////////////////////////////////////////////////////////////////////
bool Float::isNaN() const {
return Float::isNaN(this->value);
}
////////////////////////////////////////////////////////////////////////////////
int Float::compare(float f1, float f2) {
int i1, i2 = 0;
long NaNbits = Float::floatToIntBits(Float::NaN);
if ((i1 = Float::floatToIntBits(f1)) == NaNbits) {
if (Float::floatToIntBits(f2) == NaNbits) {
return 0;
}
return 1;
}
if ((i2 = Float::floatToIntBits(f2)) == NaNbits) {
return -1;
}
if (f1 == f2) {
if (i1 == i2) {
return 0;
}
// check for -0
return i1 > i2 ? 1 : -1;
}
return f1 > f2 ? 1 : -1;
}
////////////////////////////////////////////////////////////////////////////////
int Float::floatToIntBits(float value) {
int intValue = 0;
memcpy(&intValue, &value, sizeof(float));
if ((intValue & SINGLE_EXPONENT_MASK) == SINGLE_EXPONENT_MASK) {
if (intValue & SINGLE_MANTISSA_MASK) {
return SINGLE_NAN_BITS;
}
}
return intValue;
}
////////////////////////////////////////////////////////////////////////////////
int Float::floatToRawIntBits(float value) {
int intValue = 0;
memcpy(&intValue, &value, sizeof(float));
return intValue;
}
////////////////////////////////////////////////////////////////////////////////
float Float::intBitsToFloat(int bits) {
float floatValue = 0;
memcpy(&floatValue, &bits, sizeof(int));
return floatValue;
}
////////////////////////////////////////////////////////////////////////////////
bool Float::isInfinite(float value) {
return (value == POSITIVE_INFINITY) || (value == NEGATIVE_INFINITY);
}
////////////////////////////////////////////////////////////////////////////////
bool Float::isNaN(float value) {
return value != value;
}
////////////////////////////////////////////////////////////////////////////////
float Float::parseFloat(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 Float::toHexString(float 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 int bitValue = Float::floatToIntBits(value);
bool negative = (bitValue & 0x80000000) != 0;
// mask exponent bits and shift down
unsigned int exponent = (bitValue & 0x7f800000) >> 23;
// mask significand bits and shift up
// significand is 23-bits, so we shift to treat it like 24-bits
unsigned int significand = (bitValue & 0x007FFFFF) << 1;
if (exponent == 0 && significand == 0) {
return (negative ? "-0x0.0p0" : "0x0.0p0");
}
// Start with the correct sign and Hex indicator
std::string hexString(negative ? "-0x" : "0x");
if (exponent == 0) {
// denormal (subnormal) value
hexString.append("0.");
// significand is 23-bits, so there can be 6 hex digits
unsigned int fractionDigits = 6;
// 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 = Integer::toHexString(significand);
// if there are digits left, then insert some '0' chars first
if (significand != 0 && fractionDigits > hexSignificand.length()) {
unsigned int digitDiff = fractionDigits - (int) hexSignificand.length();
while (digitDiff-- != 0) {
hexString.append("0");
}
}
hexString.append(hexSignificand);
hexString.append("p-126");
} else {
// normal value
hexString.append("1.");
// significand is 23-bits, so there can be 6 hex digits
unsigned int fractionDigits = 6;
// 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 = Integer::toHexString(significand);
// if there are digits left, then insert some '0' chars first
if (significand != 0 && fractionDigits > hexSignificand.length()) {
unsigned 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(Integer::toString(exponent - 127));
}
return hexString;
}
////////////////////////////////////////////////////////////////////////////////
std::string Float::toString(float value) {
// TODO - This is not going to support the formats we say we do.
ostringstream stream;
stream << value;
return stream.str();
}
////////////////////////////////////////////////////////////////////////////////
Float Float::valueOf(float value) {
return Float(value);
}
////////////////////////////////////////////////////////////////////////////////
Float Float::valueOf(const String& value) {
return valueOf(parseFloat(value));
}