diff --git a/docs/modules/math.md b/docs/modules/math.md index c6c09c37..421edbef 100644 --- a/docs/modules/math.md +++ b/docs/modules/math.md @@ -59,6 +59,10 @@ Return `True` if `x` is a positive or negative infinity, and `False` otherwise. Return `True` if `x` is a NaN (not a number), and `False` otherwise. +### `math.isclose(a, b)` + +Return `True` if the values `a` and `b` are close to each other and `False` otherwise. + ### `math.exp(x)` Return `e` raised to the power of `x`. diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 1459cbf7..7ccec844 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -78,6 +78,7 @@ struct NumberTraits<4> { static constexpr int_t kMaxSmallInt = (1 << 28) - 1; static constexpr int_t kMinSmallInt = - (1 << 28); + static constexpr float_t kEpsilon = 1e-4; }; template <> @@ -87,6 +88,7 @@ struct NumberTraits<8> { static constexpr int_t kMaxSmallInt = (1ll << 60) - 1; static constexpr int_t kMinSmallInt = - (1ll << 60); + static constexpr float_t kEpsilon = 1e-8; }; using Number = NumberTraits; diff --git a/include/pocketpy/linalg.h b/include/pocketpy/linalg.h index ed6bf4d9..8df06071 100644 --- a/include/pocketpy/linalg.h +++ b/include/pocketpy/linalg.h @@ -4,7 +4,7 @@ namespace pkpy{ -inline bool isclose(float a, float b){ return fabsf(a - b) < 1e-4f; } +inline bool isclose(float a, float b){ return std::fabsf(a - b) <= NumberTraits<4>::kEpsilon; } struct Vec2{ float x, y; diff --git a/python/cmath.py b/python/cmath.py index 5cbb7987..60ec66c4 100644 --- a/python/cmath.py +++ b/python/cmath.py @@ -13,14 +13,17 @@ class complex: def imag(self): return self._imag + def conjugate(self): + return complex(self.real, -self.imag) + def __repr__(self): return f"({self.real}+{self.imag}j)" def __eq__(self, other): if type(other) is complex: - return self.real == other.real and self.imag == other.imag + return math.isclose(self.real, other.real) and math.isclose(self.imag, other.imag) if type(other) in (int, float): - return self.real == other and self.imag == 0 + return math.isclose(self.real, other) and self.imag == 0 return NotImplemented def __add__(self, other): @@ -144,9 +147,6 @@ def isinf(z: complex): def isnan(z: complex): return math.isnan(z.real) or math.isnan(z.imag) -def isclose(*args, **kwargs): - raise NotImplementedError - # Constants pi = math.pi diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index f333c212..acf26843 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -1488,6 +1488,12 @@ void add_module_math(VM* vm){ vm->bind_func<1>(mod, "isinf", PK_LAMBDA(VAR(std::isinf(CAST_F(args[0]))))); vm->bind_func<1>(mod, "isnan", PK_LAMBDA(VAR(std::isnan(CAST_F(args[0]))))); + vm->bind_func<2>(mod, "isclose", [](VM* vm, ArgsView args) { + f64 a = CAST_F(args[0]); + f64 b = CAST_F(args[1]); + return VAR(std::fabs(a - b) <= Number::kEpsilon); + }); + vm->bind_func<1>(mod, "exp", PK_LAMBDA(VAR(std::exp(CAST_F(args[0]))))); vm->bind_func<1>(mod, "log", PK_LAMBDA(VAR(std::log(CAST_F(args[0]))))); vm->bind_func<1>(mod, "log2", PK_LAMBDA(VAR(std::log2(CAST_F(args[0]))))); diff --git a/tests/10_cmath.py b/tests/10_cmath.py index 7b86e7ff..eb443bc0 100644 --- a/tests/10_cmath.py +++ b/tests/10_cmath.py @@ -12,6 +12,9 @@ assert (1+2j)*3 == 3+6j import cmath +assert (1+2j)**2 == -3+4j + +assert (1+2j).conjugate() == 1-2j + res = cmath.sqrt(1+2j) -assert round(res.real, 3) == 1.272, res.real -assert round(res.imag, 3) == 0.786, res.imag +assert res == 1.272019649514069+0.7861513777574233j