Skip to content

Commit 6b71cf3

Browse files
Fix of ToUInt32 (ecma_number_to_uint32) and ToInt32 (ecma_number_to_int32) conversion routines.
Related issue: #160 JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan [email protected]
1 parent 1a3940c commit 6b71cf3

File tree

2 files changed

+206
-14
lines changed

2 files changed

+206
-14
lines changed

jerry-core/ecma/base/ecma-helpers-conversion.cpp

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -823,24 +823,80 @@ ecma_int32_to_number (int32_t value) /**< signed 32-bit integer value */
823823
} /* ecma_int32_to_number */
824824

825825
/**
826-
* ECMA-defined conversion of Number value to Uint32 value
826+
* ECMA-defined conversion of Number value to UInt32 value
827827
*
828828
* See also:
829829
* ECMA-262 v5, 9.6
830830
*
831-
* @return number - result of conversion.
831+
* @return 32-bit unsigned integer - result of conversion.
832832
*/
833833
uint32_t
834-
ecma_number_to_uint32 (ecma_number_t value) /**< unsigned 32-bit integer value */
834+
ecma_number_to_uint32 (ecma_number_t num) /**< ecma-number */
835835
{
836-
if (ecma_number_is_nan (value)
837-
|| ecma_number_is_zero (value)
838-
|| ecma_number_is_infinity (value))
836+
if (ecma_number_is_nan (num)
837+
|| ecma_number_is_zero (num)
838+
|| ecma_number_is_infinity (num))
839839
{
840840
return 0;
841841
}
842842

843-
return (uint32_t) value;
843+
bool sign = ecma_number_is_negative (num);
844+
ecma_number_t abs_num;
845+
846+
if (sign)
847+
{
848+
abs_num = ecma_number_negate (num);
849+
}
850+
else
851+
{
852+
abs_num = num;
853+
}
854+
855+
// 2 ^ 32
856+
const uint64_t uint64_2_pow_32 = (1ull << 32);
857+
858+
const ecma_number_t num_2_pow_32 = (float) uint64_2_pow_32;
859+
860+
ecma_number_t num_in_uint32_range;
861+
862+
if (abs_num >= num_2_pow_32)
863+
{
864+
num_in_uint32_range = ecma_number_calc_remainder (abs_num,
865+
num_2_pow_32);
866+
}
867+
else
868+
{
869+
num_in_uint32_range = abs_num;
870+
}
871+
872+
// Check that the floating point value can be represented with uint32_t
873+
JERRY_ASSERT (num_in_uint32_range < uint64_2_pow_32);
874+
uint32_t uint32_num = (uint32_t) num_in_uint32_range;
875+
876+
uint32_t ret;
877+
878+
if (sign)
879+
{
880+
ret = -uint32_num;
881+
}
882+
else
883+
{
884+
ret = uint32_num;
885+
}
886+
887+
#ifndef JERRY_NDEBUG
888+
if (sign
889+
&& uint32_num != 0)
890+
{
891+
JERRY_ASSERT (ret == uint64_2_pow_32 - uint32_num);
892+
}
893+
else
894+
{
895+
JERRY_ASSERT (ret == uint32_num);
896+
}
897+
#endif /* !JERRY_NDEBUG */
898+
899+
return ret;
844900
} /* ecma_number_to_uint32 */
845901

846902
/**
@@ -849,19 +905,46 @@ ecma_number_to_uint32 (ecma_number_t value) /**< unsigned 32-bit integer value *
849905
* See also:
850906
* ECMA-262 v5, 9.5
851907
*
852-
* @return number - result of conversion.
908+
* @return 32-bit signed integer - result of conversion.
853909
*/
854910
int32_t
855-
ecma_number_to_int32 (ecma_number_t value) /**< unsigned 32-bit integer value */
911+
ecma_number_to_int32 (ecma_number_t num) /**< ecma-number */
856912
{
857-
if (ecma_number_is_nan (value)
858-
|| ecma_number_is_zero (value)
859-
|| ecma_number_is_infinity (value))
913+
uint32_t uint32_num = ecma_number_to_uint32 (num);
914+
915+
// 2 ^ 32
916+
const int64_t int64_2_pow_32 = (1ll << 32);
917+
918+
// 2 ^ 31
919+
const uint32_t uint32_2_pow_31 = (1ull << 31);
920+
921+
int32_t ret;
922+
923+
if (uint32_num >= uint32_2_pow_31)
860924
{
861-
return 0;
925+
ret = (int32_t) (uint32_num - int64_2_pow_32);
926+
}
927+
else
928+
{
929+
ret = (int32_t) uint32_num;
930+
}
931+
932+
#ifndef JERRY_NDEBUG
933+
int64_t int64_num = uint32_num;
934+
935+
JERRY_ASSERT (int64_num >= 0);
936+
937+
if (int64_num >= uint32_2_pow_31)
938+
{
939+
JERRY_ASSERT (ret == int64_num - int64_2_pow_32);
940+
}
941+
else
942+
{
943+
JERRY_ASSERT (ret == int64_num);
862944
}
945+
#endif /* !JERRY_NDEBUG */
863946

864-
return (int32_t) (uint32_t) value;
947+
return ret;
865948
} /* ecma_number_to_int32 */
866949

867950
#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64

tests/unit/test-number-to-integer.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* Copyright 2015 Samsung Electronics Co., Ltd.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
#include "ecma-globals.h"
17+
#include "ecma-helpers.h"
18+
19+
#include "test-common.h"
20+
21+
typedef struct
22+
{
23+
ecma_number_t num;
24+
uint32_t uint32_num;
25+
} uint32_test_case_t;
26+
27+
typedef struct
28+
{
29+
ecma_number_t num;
30+
int32_t int32_num;
31+
} int32_test_case_t;
32+
33+
/**
34+
* Unit test's main function.
35+
*/
36+
int
37+
main (int __attr_unused___ argc,
38+
char __attr_unused___ **argv)
39+
{
40+
TEST_INIT ();
41+
42+
const uint32_test_case_t test_cases_uint32[] =
43+
{
44+
#define TEST_CASE(num, uint32) { num, uint32 }
45+
TEST_CASE (1.0, 1),
46+
TEST_CASE (0.0, 0),
47+
TEST_CASE (ecma_number_negate (0.0), 0),
48+
TEST_CASE (NAN, 0),
49+
TEST_CASE (-NAN, 0),
50+
TEST_CASE (INFINITY, 0),
51+
TEST_CASE (-INFINITY, 0),
52+
TEST_CASE (0.1, 0),
53+
TEST_CASE (-0.1, 0),
54+
TEST_CASE (1.1, 1),
55+
TEST_CASE (-1.1, 4294967295),
56+
TEST_CASE (4294967295, 4294967295),
57+
TEST_CASE (-4294967295, 1),
58+
TEST_CASE (4294967296, 0),
59+
TEST_CASE (-4294967296, 0),
60+
TEST_CASE (4294967297, 1),
61+
TEST_CASE (-4294967297, 4294967295)
62+
#undef TEST_CASE
63+
};
64+
65+
for (uint32_t i = 0;
66+
i < sizeof (test_cases_uint32) / sizeof (test_cases_uint32[0]);
67+
i++)
68+
{
69+
JERRY_ASSERT (ecma_number_to_uint32 (test_cases_uint32[i].num) == test_cases_uint32[i].uint32_num);
70+
}
71+
72+
int32_test_case_t test_cases_int32[] =
73+
{
74+
#define TEST_CASE(num, int32) { num, int32 }
75+
TEST_CASE (1.0, 1),
76+
TEST_CASE (0.0, 0),
77+
TEST_CASE (ecma_number_negate (0.0), 0),
78+
TEST_CASE (NAN, 0),
79+
TEST_CASE (-NAN, 0),
80+
TEST_CASE (INFINITY, 0),
81+
TEST_CASE (-INFINITY, 0),
82+
TEST_CASE (0.1, 0),
83+
TEST_CASE (-0.1, 0),
84+
TEST_CASE (1.1, 1),
85+
TEST_CASE (-1.1, -1),
86+
TEST_CASE (4294967295, -1),
87+
TEST_CASE (-4294967295, 1),
88+
TEST_CASE (4294967296, 0),
89+
TEST_CASE (-4294967296, 0),
90+
TEST_CASE (4294967297, 1),
91+
TEST_CASE (-4294967297, -1),
92+
TEST_CASE (2147483648, -2147483648),
93+
TEST_CASE (-2147483648, -2147483648),
94+
TEST_CASE (2147483647, 2147483647),
95+
TEST_CASE (-2147483647, -2147483647),
96+
TEST_CASE (-2147483649, 2147483647),
97+
TEST_CASE (2147483649, -2147483647)
98+
#undef TEST_CASE
99+
};
100+
101+
for (uint32_t i = 0;
102+
i < sizeof (test_cases_int32) / sizeof (test_cases_int32[0]);
103+
i++)
104+
{
105+
JERRY_ASSERT (ecma_number_to_int32 (test_cases_int32[i].num) == test_cases_int32[i].int32_num);
106+
}
107+
108+
return 0;
109+
} /* main */

0 commit comments

Comments
 (0)