Commit 825a5d74 authored by oleg@chromium.org's avatar oleg@chromium.org

Improve Math.round(). Fix the bug in r4146. Further improve performance by...

Improve Math.round(). Fix the bug in r4146. Further improve performance by checking the exponent instead of comparing doubles. Add several tests for numbers near the limits of SMI and several tests from WebKit.

Review URL: http://codereview.chromium.org/1008004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4180 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c8a27357
......@@ -171,7 +171,7 @@ function MathRandom() {
// ECMA 262 - 15.8.2.15
function MathRound(x) {
if (!IS_NUMBER(x)) x = ToNumber(x);
return %Math_round(x);
return %RoundNumber(x);
}
// ECMA 262 - 15.8.2.16
......
......@@ -1121,6 +1121,17 @@ void HeapNumber::set_value(double value) {
}
int HeapNumber::get_exponent() {
return ((READ_INT_FIELD(this, kExponentOffset) & kExponentMask) >>
kExponentShift) - kExponentBias;
}
int HeapNumber::get_sign() {
return READ_INT_FIELD(this, kExponentOffset) & kSignMask;
}
ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
......
......@@ -1094,6 +1094,9 @@ class HeapNumber: public HeapObject {
void HeapNumberVerify();
#endif
inline int get_exponent();
inline int get_sign();
// Layout description.
static const int kValueOffset = HeapObject::kHeaderSize;
// IEEE doubles are two 32 bit words. The first is just mantissa, the second
......
......@@ -5350,16 +5350,38 @@ static Object* Runtime_Math_pow_cfunction(Arguments args) {
}
static Object* Runtime_Math_round(Arguments args) {
static Object* Runtime_RoundNumber(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
Counters::math_round.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]);
if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
double integer = ceil(x);
if (integer - x > 0.5) { integer -= 1.0; }
return Heap::NumberFromDouble(integer);
if (!args[0]->IsHeapNumber()) {
// Must be smi. Return the argument unchanged for all the other types
// to make fuzz-natives test happy.
return args[0];
}
HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
double value = number->value();
int exponent = number->get_exponent();
int sign = number->get_sign();
// We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
// should be rounded to 2^30, which is not smi.
if (!sign && exponent <= kSmiValueSize - 3) {
return Smi::FromInt(static_cast<int>(value + 0.5));
}
// If the magnitude is big enough, there's no place for fraction part. If we
// try to add 0.5 to this number, 1.0 will be added instead.
if (exponent >= 52) {
return number;
}
if (sign && value >= -0.5) return Heap::minus_zero_value();
return Heap::NumberFromDouble(floor(value + 0.5));
}
......
......@@ -145,7 +145,7 @@ namespace internal {
F(Math_log, 1, 1) \
F(Math_pow, 2, 1) \
F(Math_pow_cfunction, 2, 1) \
F(Math_round, 1, 1) \
F(RoundNumber, 1, 1) \
F(Math_sin, 1, 1) \
F(Math_sqrt, 1, 1) \
F(Math_tan, 1, 1) \
......
......@@ -50,3 +50,52 @@ assertEquals(-9007199254740990, Math.round(-9007199254740990));
assertEquals(-9007199254740991, Math.round(-9007199254740991));
assertEquals(Number.MAX_VALUE, Math.round(Number.MAX_VALUE));
assertEquals(-Number.MAX_VALUE, Math.round(-Number.MAX_VALUE));
assertEquals(536870911, Math.round(536870910.5));
assertEquals(536870911, Math.round(536870911));
assertEquals(536870911, Math.round(536870911.4));
assertEquals(536870912, Math.round(536870911.5));
assertEquals(536870912, Math.round(536870912));
assertEquals(536870912, Math.round(536870912.4));
assertEquals(536870913, Math.round(536870912.5));
assertEquals(536870913, Math.round(536870913));
assertEquals(536870913, Math.round(536870913.4));
assertEquals(1073741823, Math.round(1073741822.5));
assertEquals(1073741823, Math.round(1073741823));
assertEquals(1073741823, Math.round(1073741823.4));
assertEquals(1073741824, Math.round(1073741823.5));
assertEquals(1073741824, Math.round(1073741824));
assertEquals(1073741824, Math.round(1073741824.4));
assertEquals(1073741825, Math.round(1073741824.5));
assertEquals(2147483647, Math.round(2147483646.5));
assertEquals(2147483647, Math.round(2147483647));
assertEquals(2147483647, Math.round(2147483647.4));
assertEquals(2147483648, Math.round(2147483647.5));
assertEquals(2147483648, Math.round(2147483648));
assertEquals(2147483648, Math.round(2147483648.4));
assertEquals(2147483649, Math.round(2147483648.5));
// Tests based on WebKit LayoutTests
assertEquals(0, Math.round(0.4));
assertEquals(-0, Math.round(-0.4));
assertEquals(-0, Math.round(-0.5));
assertEquals(1, Math.round(0.6));
assertEquals(-1, Math.round(-0.6));
assertEquals(2, Math.round(1.5));
assertEquals(2, Math.round(1.6));
assertEquals(-2, Math.round(-1.6));
assertEquals(8640000000000000, Math.round(8640000000000000));
assertEquals(8640000000000001, Math.round(8640000000000001));
assertEquals(8640000000000002, Math.round(8640000000000002));
assertEquals(9007199254740990, Math.round(9007199254740990));
assertEquals(9007199254740991, Math.round(9007199254740991));
assertEquals(1.7976931348623157e+308, Math.round(1.7976931348623157e+308));
assertEquals(-8640000000000000, Math.round(-8640000000000000));
assertEquals(-8640000000000001, Math.round(-8640000000000001));
assertEquals(-8640000000000002, Math.round(-8640000000000002));
assertEquals(-9007199254740990, Math.round(-9007199254740990));
assertEquals(-9007199254740991, Math.round(-9007199254740991));
assertEquals(-1.7976931348623157e+308, Math.round(-1.7976931348623157e+308));
assertEquals(Infinity, Math.round(Infinity));
assertEquals(-Infinity, Math.round(-Infinity));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment