Fix Math.Asinh function and Math.Atanh function for windows

Deal with Math.Asinh(+0.0) and Math.Atanh(-0.0) in particular. Use
signbit() to distinguish between "+0.0" and "-0.0". Change
namespace panda::ecmascript::base::math to class
panda::ecmascript::base::MathHelper in order to avoid
"[-Werror, -Wunused-function]". Add unit-tests for
BuiltinsMath::Asinh and BuiltinsMath::Atanh at
ecmascript/builtins/tests/builtins_math_test.cpp.

Issue:
    https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I5ML3O
Test:
    unit-test(BuiltinsMathTest::Asinh_9, BuiltinsMathTest::Asinh_10,
              BuiltinsMathTest::Atanh_9, BuiltinsMathTest::Atanh_10)
    262-tests on windows(asinh-specialVals.js, atanh-specialVals.js)
Signed-off-by: gongyuhang <gongyuhang7@huawei.com>
This commit is contained in:
gongyuhang 2022-08-24 22:12:20 +08:00
parent 1844ad8bff
commit ce64462802
5 changed files with 101 additions and 15 deletions

View File

@ -17,20 +17,46 @@
#define ECMASCRIPT_BASE_MATH_HELPER_H
#include <cstdint>
#include <cmath>
#define panda_bit_utils_ctz __builtin_ctz // NOLINT(cppcoreguidelines-macro-usage)
#define panda_bit_utils_ctzll __builtin_ctzll // NOLINT(cppcoreguidelines-macro-usage)
namespace panda::ecmascript::base::math {
static constexpr uint32_t GetIntLog2(const uint32_t X)
{
return static_cast<uint32_t>(panda_bit_utils_ctz(X));
}
namespace panda::ecmascript::base {
class MathHelper {
public:
static constexpr uint32_t GetIntLog2(const uint32_t X)
{
return static_cast<uint32_t>(panda_bit_utils_ctz(X));
}
static constexpr uint64_t GetIntLog2(const uint64_t X)
{
return static_cast<uint64_t>(panda_bit_utils_ctzll(X));
}
static constexpr uint64_t GetIntLog2(const uint64_t X)
{
return static_cast<uint64_t>(panda_bit_utils_ctzll(X));
}
static double Asinh(double input)
{
#if defined(PANDA_TARGET_WINDOWS)
if (input == 0 && !std::signbit(input)) {
// +0.0(double) is the special case for std::asinh() function compiled in linux for windows.
return +0.0;
}
#endif
return std::asinh(input);
}
static inline double Atanh(double input)
{
#if defined(PANDA_TARGET_WINDOWS)
if (input == 0 && std::signbit(input)) {
// -0.0(double) is the special case for std::atanh() function compiled in linux for windows.
return -0.0;
}
#endif
return std::atanh(input);
}
};
} // panda::ecmascript::base
#endif // ECMASCRIPT_BASE_MATH_HELPER_H

View File

@ -106,7 +106,7 @@ JSTaggedValue BuiltinsMath::Asinh(EcmaRuntimeCallInfo *argv)
double result = base::NAN_VALUE;
// value == -NaN, NaN, result is NaN
if (!std::isnan(std::abs(value))) {
result = std::asinh(value);
result = base::MathHelper::Asinh(value);
}
return GetTaggedDouble(result);
}
@ -141,7 +141,7 @@ JSTaggedValue BuiltinsMath::Atanh(EcmaRuntimeCallInfo *argv)
double value = numberValue.GetNumber();
double result = base::NAN_VALUE;
if (value >= -1 && value <= 1) {
result = std::atanh(value);
result = base::MathHelper::Atanh(value);
}
return GetTaggedDouble(result);
}

View File

@ -878,6 +878,36 @@ HWTEST_F_L0(BuiltinsMathTest, Asinh_8)
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.asinh(-0.0)
HWTEST_F_L0(BuiltinsMathTest, Asinh_9)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(-0.0));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo);
JSTaggedValue result = BuiltinsMath::Asinh(ecmaRuntimeCallInfo);
TestHelper::TearDownFrame(thread_, prev);
JSTaggedValue expect = BuiltinsBase::GetTaggedDouble(-0.0);
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.asinh(+0.0)
HWTEST_F_L0(BuiltinsMathTest, Asinh_10)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(+0.0));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo);
JSTaggedValue result = BuiltinsMath::Asinh(ecmaRuntimeCallInfo);
TestHelper::TearDownFrame(thread_, prev);
JSTaggedValue expect = BuiltinsBase::GetTaggedDouble(+0.0);
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.atan(-1)
HWTEST_F_L0(BuiltinsMathTest, Atan)
{
@ -1152,6 +1182,36 @@ HWTEST_F_L0(BuiltinsMathTest, Atanh_8)
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.atanh(-0.0)
HWTEST_F_L0(BuiltinsMathTest, Atanh_9)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(-0.0));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo);
JSTaggedValue result = BuiltinsMath::Atanh(ecmaRuntimeCallInfo);
TestHelper::TearDownFrame(thread_, prev);
JSTaggedValue expect = BuiltinsBase::GetTaggedDouble(-0.0);
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.atanh(+0.0)
HWTEST_F_L0(BuiltinsMathTest, Atanh_10)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(+0.0));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread_, ecmaRuntimeCallInfo);
JSTaggedValue result = BuiltinsMath::Atanh(ecmaRuntimeCallInfo);
TestHelper::TearDownFrame(thread_, prev);
JSTaggedValue expect = BuiltinsBase::GetTaggedDouble(+0.0);
ASSERT_EQ(result.GetRawData(), expect.GetRawData());
}
// Math.atan2(NaN, 1.5)
HWTEST_F_L0(BuiltinsMathTest, Atan2)
{

View File

@ -31,11 +31,11 @@ class GCBitset {
public:
using GCBitsetWord = uint32_t;
static constexpr uint32_t BYTE_PER_WORD = sizeof(GCBitsetWord);
static constexpr uint32_t BYTE_PER_WORD_LOG2 = base::math::GetIntLog2(BYTE_PER_WORD);
static constexpr uint32_t BYTE_PER_WORD_LOG2 = base::MathHelper::GetIntLog2(BYTE_PER_WORD);
static constexpr uint32_t BIT_PER_BYTE = 8;
static constexpr uint32_t BIT_PER_BYTE_LOG2 = base::math::GetIntLog2(BIT_PER_BYTE);
static constexpr uint32_t BIT_PER_BYTE_LOG2 = base::MathHelper::GetIntLog2(BIT_PER_BYTE);
static constexpr uint32_t BIT_PER_WORD = BYTE_PER_WORD * BIT_PER_BYTE;
static constexpr uint32_t BIT_PER_WORD_LOG2 = base::math::GetIntLog2(BIT_PER_WORD);
static constexpr uint32_t BIT_PER_WORD_LOG2 = base::MathHelper::GetIntLog2(BIT_PER_WORD);
static constexpr uint32_t BIT_PER_WORD_MASK = BIT_PER_WORD - 1;
GCBitset() = default;

View File

@ -77,7 +77,7 @@ static constexpr size_t MAX_CHUNK_AREA_SIZE = 1_MB;
using TaggedType = uint64_t;
static constexpr uint32_t TAGGED_TYPE_SIZE = sizeof(TaggedType);
static constexpr uint32_t TAGGED_TYPE_SIZE_LOG = base::math::GetIntLog2(TAGGED_TYPE_SIZE);
static constexpr uint32_t TAGGED_TYPE_SIZE_LOG = base::MathHelper::GetIntLog2(TAGGED_TYPE_SIZE);
template<typename T>
constexpr inline bool IsAligned(T value, size_t alignment)