Skip to content

Commit

Permalink
Fix of ToUInt32 (ecma_number_to_uint32) and ToInt32 (ecma_number_to_i…
Browse files Browse the repository at this point in the history
…nt32) conversion routines.

Related issue: #160

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan [email protected]
  • Loading branch information
ruben-ayrapetyan committed Jun 23, 2015
1 parent 1a3940c commit 6b71cf3
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 14 deletions.
111 changes: 97 additions & 14 deletions jerry-core/ecma/base/ecma-helpers-conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,24 +823,80 @@ ecma_int32_to_number (int32_t value) /**< signed 32-bit integer value */
} /* ecma_int32_to_number */

/**
* ECMA-defined conversion of Number value to Uint32 value
* ECMA-defined conversion of Number value to UInt32 value
*
* See also:
* ECMA-262 v5, 9.6
*
* @return number - result of conversion.
* @return 32-bit unsigned integer - result of conversion.
*/
uint32_t
ecma_number_to_uint32 (ecma_number_t value) /**< unsigned 32-bit integer value */
ecma_number_to_uint32 (ecma_number_t num) /**< ecma-number */
{
if (ecma_number_is_nan (value)
|| ecma_number_is_zero (value)
|| ecma_number_is_infinity (value))
if (ecma_number_is_nan (num)
|| ecma_number_is_zero (num)
|| ecma_number_is_infinity (num))
{
return 0;
}

return (uint32_t) value;
bool sign = ecma_number_is_negative (num);
ecma_number_t abs_num;

if (sign)
{
abs_num = ecma_number_negate (num);
}
else
{
abs_num = num;
}

// 2 ^ 32
const uint64_t uint64_2_pow_32 = (1ull << 32);

const ecma_number_t num_2_pow_32 = (float) uint64_2_pow_32;

ecma_number_t num_in_uint32_range;

if (abs_num >= num_2_pow_32)
{
num_in_uint32_range = ecma_number_calc_remainder (abs_num,
num_2_pow_32);
}
else
{
num_in_uint32_range = abs_num;
}

// Check that the floating point value can be represented with uint32_t
JERRY_ASSERT (num_in_uint32_range < uint64_2_pow_32);
uint32_t uint32_num = (uint32_t) num_in_uint32_range;

uint32_t ret;

if (sign)
{
ret = -uint32_num;
}
else
{
ret = uint32_num;
}

#ifndef JERRY_NDEBUG
if (sign
&& uint32_num != 0)
{
JERRY_ASSERT (ret == uint64_2_pow_32 - uint32_num);
}
else
{
JERRY_ASSERT (ret == uint32_num);
}
#endif /* !JERRY_NDEBUG */

return ret;
} /* ecma_number_to_uint32 */

/**
Expand All @@ -849,19 +905,46 @@ ecma_number_to_uint32 (ecma_number_t value) /**< unsigned 32-bit integer value *
* See also:
* ECMA-262 v5, 9.5
*
* @return number - result of conversion.
* @return 32-bit signed integer - result of conversion.
*/
int32_t
ecma_number_to_int32 (ecma_number_t value) /**< unsigned 32-bit integer value */
ecma_number_to_int32 (ecma_number_t num) /**< ecma-number */
{
if (ecma_number_is_nan (value)
|| ecma_number_is_zero (value)
|| ecma_number_is_infinity (value))
uint32_t uint32_num = ecma_number_to_uint32 (num);

// 2 ^ 32
const int64_t int64_2_pow_32 = (1ll << 32);

// 2 ^ 31
const uint32_t uint32_2_pow_31 = (1ull << 31);

int32_t ret;

if (uint32_num >= uint32_2_pow_31)
{
return 0;
ret = (int32_t) (uint32_num - int64_2_pow_32);
}
else
{
ret = (int32_t) uint32_num;
}

#ifndef JERRY_NDEBUG
int64_t int64_num = uint32_num;

JERRY_ASSERT (int64_num >= 0);

if (int64_num >= uint32_2_pow_31)
{
JERRY_ASSERT (ret == int64_num - int64_2_pow_32);
}
else
{
JERRY_ASSERT (ret == int64_num);
}
#endif /* !JERRY_NDEBUG */

return (int32_t) (uint32_t) value;
return ret;
} /* ecma_number_to_int32 */

#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64
Expand Down
109 changes: 109 additions & 0 deletions tests/unit/test-number-to-integer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/

#include "ecma-globals.h"
#include "ecma-helpers.h"

#include "test-common.h"

typedef struct
{
ecma_number_t num;
uint32_t uint32_num;
} uint32_test_case_t;

typedef struct
{
ecma_number_t num;
int32_t int32_num;
} int32_test_case_t;

/**
* Unit test's main function.
*/
int
main (int __attr_unused___ argc,
char __attr_unused___ **argv)
{
TEST_INIT ();

const uint32_test_case_t test_cases_uint32[] =
{
#define TEST_CASE(num, uint32) { num, uint32 }
TEST_CASE (1.0, 1),
TEST_CASE (0.0, 0),
TEST_CASE (ecma_number_negate (0.0), 0),
TEST_CASE (NAN, 0),
TEST_CASE (-NAN, 0),
TEST_CASE (INFINITY, 0),
TEST_CASE (-INFINITY, 0),
TEST_CASE (0.1, 0),
TEST_CASE (-0.1, 0),
TEST_CASE (1.1, 1),
TEST_CASE (-1.1, 4294967295),
TEST_CASE (4294967295, 4294967295),
TEST_CASE (-4294967295, 1),
TEST_CASE (4294967296, 0),
TEST_CASE (-4294967296, 0),
TEST_CASE (4294967297, 1),
TEST_CASE (-4294967297, 4294967295)
#undef TEST_CASE
};

for (uint32_t i = 0;
i < sizeof (test_cases_uint32) / sizeof (test_cases_uint32[0]);
i++)
{
JERRY_ASSERT (ecma_number_to_uint32 (test_cases_uint32[i].num) == test_cases_uint32[i].uint32_num);
}

int32_test_case_t test_cases_int32[] =
{
#define TEST_CASE(num, int32) { num, int32 }
TEST_CASE (1.0, 1),
TEST_CASE (0.0, 0),
TEST_CASE (ecma_number_negate (0.0), 0),
TEST_CASE (NAN, 0),
TEST_CASE (-NAN, 0),
TEST_CASE (INFINITY, 0),
TEST_CASE (-INFINITY, 0),
TEST_CASE (0.1, 0),
TEST_CASE (-0.1, 0),
TEST_CASE (1.1, 1),
TEST_CASE (-1.1, -1),
TEST_CASE (4294967295, -1),
TEST_CASE (-4294967295, 1),
TEST_CASE (4294967296, 0),
TEST_CASE (-4294967296, 0),
TEST_CASE (4294967297, 1),
TEST_CASE (-4294967297, -1),
TEST_CASE (2147483648, -2147483648),
TEST_CASE (-2147483648, -2147483648),
TEST_CASE (2147483647, 2147483647),
TEST_CASE (-2147483647, -2147483647),
TEST_CASE (-2147483649, 2147483647),
TEST_CASE (2147483649, -2147483647)
#undef TEST_CASE
};

for (uint32_t i = 0;
i < sizeof (test_cases_int32) / sizeof (test_cases_int32[0]);
i++)
{
JERRY_ASSERT (ecma_number_to_int32 (test_cases_int32[i].num) == test_cases_int32[i].int32_num);
}

return 0;
} /* main */

0 comments on commit 6b71cf3

Please sign in to comment.