From 8ebc73c8f1276f23161da067374fcb3a3b2e84f1 Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Tue, 14 Jul 2020 13:16:05 +0000 Subject: [PATCH] Fixed njs_number_to_int32() for big-endian platforms. This is related to #326 issue in Github. --- auto/clang | 17 ----------- src/njs_number.h | 73 ++++++++++++++++++++++++------------------------ 2 files changed, 37 insertions(+), 53 deletions(-) diff --git a/auto/clang b/auto/clang index 82130b2a..ae5dc095 100644 --- a/auto/clang +++ b/auto/clang @@ -162,23 +162,6 @@ njs_feature_test="#include . auto/feature -njs_feature="NAN to uint conversion" -njs_feature_name=NJS_NAN_TO_UINT_CONVERSION -njs_feature_run=value -njs_feature_incs= -njs_feature_libs=-lm -njs_feature_test="#include - #include - #include - - int main(void) { - int64_t i64 = acosh(0); - printf(\"%x\", (uint32_t) i64); - return 0; - }" -. auto/feature - - njs_feature="_mm_setcsr()" njs_feature_name=NJS_HAVE_DENORMALS_CONTROL njs_feature_run=no diff --git a/src/njs_number.h b/src/njs_number.h index 328f5844..6e8d8c42 100644 --- a/src/njs_number.h +++ b/src/njs_number.h @@ -51,38 +51,6 @@ njs_key_is_integer_index(double num, const njs_value_t *value) } -njs_inline int64_t -njs_number_to_int64(double num) -{ -#if (NJS_NAN_TO_UINT_CONVERSION != 0) - /* - * PPC32: NaN and Inf are converted to 0x8000000080000000 - * and become non-zero after truncation. - */ - - if (isnan(num) || isinf(num)) { - return 0; - } -#endif - - /* - * ES5.1: integer must be modulo 2^32. - * 2^53 is the largest integer number which can be stored safely - * in the IEEE-754 format and numbers less than 2^53 can be just - * converted to int64_t eliding more expensive fmod() operation. - * Then the int64 integer is truncated to uint32_t. The NaN is - * converted to 0x8000000000000000 and becomes 0 after truncation. - * fmod() of the Infinity returns NaN. - */ - - if (fabs(num) > 9007199254740992.0) { - return (int64_t) fmod(num, 4294967296.0); - } - - return (int64_t) num; -} - - njs_inline int64_t njs_number_to_integer(double num) { @@ -97,28 +65,61 @@ njs_number_to_integer(double num) return 0; } - return njs_number_to_int64(num); + return trunc(num) + 0.0; } njs_inline int32_t njs_number_to_int32(double num) { - return (int32_t) njs_number_to_int64(num); + int32_t r; + uint64_t v; + njs_int_t exp; + njs_diyfp_conv_t conv; + + conv.d = num; + + exp = (conv.u64 & NJS_DBL_EXPONENT_MASK) >> NJS_DBL_SIGNIFICAND_SIZE; + + if (njs_fast_path(exp < (NJS_DBL_EXPONENT_OFFSET + 30))) { + /* |num| < 2**31. */ + return num; + } + + if (exp < (NJS_DBL_EXPONENT_OFFSET + 30 + 53)) { + v = (conv.u64 & NJS_DBL_SIGNIFICAND_MASK) | NJS_DBL_HIDDEN_BIT; + v <<= (exp - NJS_DBL_EXPONENT_BIAS + 32); + r = v >> 32; + + if (conv.u64 & NJS_DBL_SIGN_MASK) { + r = -r; + } + + return r; + } + + /* + * ES5.1: integer must be modulo 2^32. + * The distance between larger doubles + * (exp >= NJS_DBL_EXPONENT_OFFSET + 30 + 53) is a multiple of 2**32 => 0. + * This also handles NaN and Inf. + */ + + return 0; } njs_inline uint32_t njs_number_to_uint32(double num) { - return (uint32_t) njs_number_to_int64(num); + return (uint32_t) njs_number_to_int32(num); } njs_inline uint16_t njs_number_to_uint16(double num) { - return (uint16_t) njs_number_to_int64(num); + return (uint16_t) njs_number_to_int32(num); } -- 2.47.3