blob: a30c8394ea6b72224ffa413a50dfafc5550d42da [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed 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 java.lang;
import static javaemul.internal.InternalPreconditions.checkNotNull;
import javaemul.internal.JsUtils;
import jsinterop.annotations.JsMethod;
/**
* Wraps a primitive <code>double</code> as an object.
*/
public final class Double extends Number implements Comparable<Double> {
public static final double MAX_VALUE = 1.7976931348623157e+308;
public static final double MIN_VALUE = 4.9e-324;
public static final double MIN_NORMAL = 2.2250738585072014e-308;
public static final int MAX_EXPONENT = 1023;
// ==Math.getExponent(Double.MAX_VALUE);
public static final int MIN_EXPONENT = -1022;
// ==Math.getExponent(Double.MIN_NORMAL);
public static final double NaN = 0d / 0d;
public static final double NEGATIVE_INFINITY = -1d / 0d;
public static final double POSITIVE_INFINITY = 1d / 0d;
public static final int SIZE = 64;
public static final int BYTES = SIZE / Byte.SIZE;
public static final Class<Double> TYPE = double.class;
// 2^512, 2^-512
private static final double POWER_512 = 1.3407807929942597E154;
private static final double POWER_MINUS_512 = 7.458340731200207E-155;
// 2^256, 2^-256
private static final double POWER_256 = 1.157920892373162E77;
private static final double POWER_MINUS_256 = 8.636168555094445E-78;
// 2^128, 2^-128
private static final double POWER_128 = 3.4028236692093846E38;
private static final double POWER_MINUS_128 = 2.9387358770557188E-39;
// 2^64, 2^-64
private static final double POWER_64 = 18446744073709551616.0;
private static final double POWER_MINUS_64 = 5.421010862427522E-20;
// 2^52, 2^-52
private static final double POWER_52 = 4503599627370496.0;
private static final double POWER_MINUS_52 = 2.220446049250313E-16;
// 2^32, 2^-32
private static final double POWER_32 = 4294967296.0;
private static final double POWER_MINUS_32 = 2.3283064365386963E-10;
// 2^31
private static final double POWER_31 = 2147483648.0;
// 2^20, 2^-20
private static final double POWER_20 = 1048576.0;
private static final double POWER_MINUS_20 = 9.5367431640625E-7;
// 2^16, 2^-16
private static final double POWER_16 = 65536.0;
private static final double POWER_MINUS_16 = 0.0000152587890625;
// 2^8, 2^-8
private static final double POWER_8 = 256.0;
private static final double POWER_MINUS_8 = 0.00390625;
// 2^4, 2^-4
private static final double POWER_4 = 16.0;
private static final double POWER_MINUS_4 = 0.0625;
// 2^2, 2^-2
private static final double POWER_2 = 4.0;
private static final double POWER_MINUS_2 = 0.25;
// 2^1, 2^-1
private static final double POWER_1 = 2.0;
private static final double POWER_MINUS_1 = 0.5;
// 2^-1022 (smallest double non-denorm)
private static final double POWER_MINUS_1022 = 2.2250738585072014E-308;
private static class PowersTable {
private static final double[] powers = {
POWER_512, POWER_256, POWER_128, POWER_64, POWER_32, POWER_16, POWER_8,
POWER_4, POWER_2, POWER_1
};
private static final double[] invPowers = {
POWER_MINUS_512, POWER_MINUS_256, POWER_MINUS_128, POWER_MINUS_64,
POWER_MINUS_32, POWER_MINUS_16, POWER_MINUS_8, POWER_MINUS_4, POWER_MINUS_2,
POWER_MINUS_1
};
}
public static int compare(double x, double y) {
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
if (x == y) {
return 0;
}
if (isNaN(x)) {
if (isNaN(y)) {
return 0;
} else {
return 1;
}
} else {
return -1;
}
}
public static long doubleToLongBits(double value) {
if (isNaN(value)) {
return 0x7ff8000000000000L;
}
boolean negative = false;
if (value == 0.0) {
if (1.0 / value == NEGATIVE_INFINITY) {
return 0x8000000000000000L; // -0.0
} else {
return 0x0L;
}
}
if (value < 0.0) {
negative = true;
value = -value;
}
if (isInfinite(value)) {
if (negative) {
return 0xfff0000000000000L;
} else {
return 0x7ff0000000000000L;
}
}
int exp = 0;
// Scale d by powers of 2 into the range [1.0, 2.0)
// If the exponent would go below -1023, scale into (0.0, 1.0) instead
if (value < 1.0) {
int bit = 512;
for (int i = 0; i < 10; i++, bit >>= 1) {
if (value < PowersTable.invPowers[i] && exp - bit >= -1023) {
value *= PowersTable.powers[i];
exp -= bit;
}
}
// Force into [1.0, 2.0) range
if (value < 1.0 && exp - 1 >= -1023) {
value *= 2.0;
exp--;
}
} else if (value >= 2.0) {
int bit = 512;
for (int i = 0; i < 10; i++, bit >>= 1) {
if (value >= PowersTable.powers[i]) {
value *= PowersTable.invPowers[i];
exp += bit;
}
}
}
if (exp > -1023) {
// Remove significand of non-denormalized mantissa
value -= 1.0;
} else {
// Insert 0 bit as significand of denormalized mantissa
value *= 0.5;
}
// Extract high 20 bits of mantissa
long ihi = (long) (value * POWER_20);
// Extract low 32 bits of mantissa
value -= ihi * POWER_MINUS_20;
long ilo = (long) (value * POWER_52);
// Exponent bits
ihi |= (exp + 1023) << 20;
// Sign bit
if (negative) {
ihi |= 0x80000000L;
}
return (ihi << 32) | ilo;
}
public static int hashCode(double d) {
return (int) d;
}
public static boolean isFinite(double x) {
return JsUtils.isFinite(x);
}
public static boolean isInfinite(double x) {
return !isNaN(x) && !isFinite(x);
}
public static boolean isNaN(double x) {
return JsUtils.isNaN(x);
}
public static double longBitsToDouble(long bits) {
long ihi = (long) (bits >> 32);
long ilo = (long) (bits & 0xffffffffL);
if (ihi < 0) {
ihi += 0x100000000L;
}
if (ilo < 0) {
ilo += 0x100000000L;
}
boolean negative = (ihi & 0x80000000) != 0;
int exp = (int) ((ihi >> 20) & 0x7ff);
ihi &= 0xfffff; // remove sign bit and exponent
if (exp == 0x0) {
double d = (ihi * POWER_MINUS_20) + (ilo * POWER_MINUS_52);
d *= POWER_MINUS_1022;
return negative ? (d == 0.0 ? -0.0 : -d) : d;
} else if (exp == 0x7ff) {
if (ihi == 0 && ilo == 0) {
return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
} else {
return Double.NaN;
}
}
// Normalize exponent
exp -= 1023;
double d = 1.0 + (ihi * POWER_MINUS_20) + (ilo * POWER_MINUS_52);
if (exp > 0) {
int bit = 512;
for (int i = 0; i < 10; i++, bit >>= 1) {
if (exp >= bit) {
d *= PowersTable.powers[i];
exp -= bit;
}
}
} else if (exp < 0) {
while (exp < 0) {
int bit = 512;
for (int i = 0; i < 10; i++, bit >>= 1) {
if (exp <= -bit) {
d *= PowersTable.invPowers[i];
exp += bit;
}
}
}
}
return negative ? -d : d;
}
public static double max(double a, double b) {
return Math.max(a, b);
}
public static double min(double a, double b) {
return Math.min(a, b);
}
public static double parseDouble(String s) throws NumberFormatException {
return __parseAndValidateDouble(s);
}
public static double sum(double a, double b) {
return a + b;
}
public static String toString(double b) {
return String.valueOf(b);
}
public static Double valueOf(double d) {
return new Double(d);
}
public static Double valueOf(String s) throws NumberFormatException {
return new Double(s);
}
public Double(double value) {
/*
* Call to $create(value) must be here so that the method is referenced and not
* pruned before new Double(value) is replaced by $create(value) by
* RewriteConstructorCallsForUnboxedTypes.
*/
$create(value);
}
public Double(String s) {
/*
* Call to $create(value) must be here so that the method is referenced and not
* pruned before new Double(value) is replaced by $create(value) by
* RewriteConstructorCallsForUnboxedTypes.
*/
$create(s);
}
@Override
public byte byteValue() {
return (byte) doubleValue();
}
@Override
public int compareTo(Double b) {
return compare(doubleValue(), b.doubleValue());
}
@Override
public double doubleValue() {
return JsUtils.unsafeCastToDouble(checkNotNull(this));
}
@Override
public boolean equals(Object o) {
return checkNotNull(this) == o;
}
@Override
public float floatValue() {
return (float) doubleValue();
}
/**
* Performance caution: using Double objects as map keys is not recommended.
* Using double values as keys is generally a bad idea due to difficulty
* determining exact equality. In addition, there is no efficient JavaScript
* equivalent of <code>doubleToIntBits</code>. As a result, this method
* computes a hash code by truncating the whole number portion of the double,
* which may lead to poor performance for certain value sets if Doubles are
* used as keys in a {@link java.util.HashMap}.
*/
@Override
public int hashCode() {
return hashCode(doubleValue());
}
@Override
public int intValue() {
return (int) doubleValue();
}
public boolean isInfinite() {
return isInfinite(doubleValue());
}
public boolean isNaN() {
return isNaN(doubleValue());
}
@Override
public long longValue() {
return (long) doubleValue();
}
@Override
public short shortValue() {
return (short) doubleValue();
}
@Override
public String toString() {
return toString(doubleValue());
}
// CHECKSTYLE_OFF: Utility Methods for unboxed Double.
protected static Double $create(double x) {
return JsUtils.uncheckedCast(x);
}
protected static Double $create(String s) {
return JsUtils.uncheckedCast(Double.parseDouble(s));
}
@JsMethod
protected static boolean $isInstance(Object instance) {
return "number".equals(JsUtils.typeOf(instance));
}
//CHECKSTYLE_ON: End utility methods
}