Compare commits

..

1 Commits

32 changed files with 206 additions and 5083 deletions

3
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "3rd/lz4/lz4"] [submodule "3rd/lz4/lz4"]
path = 3rd/lz4/lz4 path = 3rd/lz4/lz4
url = https://github.com/lz4/lz4 url = https://github.com/lz4/lz4
[submodule "3rd/dmath/dmath"]
path = 3rd/dmath/dmath
url = https://github.com/pocketpy/dmath
[submodule "3rd/periphery/c-periphery"] [submodule "3rd/periphery/c-periphery"]
path = 3rd/periphery/c-periphery path = 3rd/periphery/c-periphery
url = https://github.com/vsergeev/c-periphery.git url = https://github.com/vsergeev/c-periphery.git

1
3rd/dmath/dmath Submodule

@ -0,0 +1 @@
Subproject commit cc7cdccae657b0f81a1e234eb9d4ed4c458bda0f

View File

@ -62,6 +62,7 @@ else()
endif() endif()
if(PK_ENABLE_DETERMINISM) if(PK_ENABLE_DETERMINISM)
add_subdirectory(3rd/dmath/dmath)
add_definitions(-DPK_ENABLE_DETERMINISM=1) add_definitions(-DPK_ENABLE_DETERMINISM=1)
else() else()
add_definitions(-DPK_ENABLE_DETERMINISM=0) add_definitions(-DPK_ENABLE_DETERMINISM=0)
@ -148,12 +149,24 @@ target_include_directories(
${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/include
) )
if(PK_ENABLE_DETERMINISM)
target_link_libraries(${PROJECT_NAME} dmath)
if(MSVC)
target_link_options(${PROJECT_NAME} PRIVATE /FORCE:MULTIPLE)
endif()
endif()
if(PK_ENABLE_THREADS) if(PK_ENABLE_THREADS)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME} Threads::Threads) target_link_libraries(${PROJECT_NAME} Threads::Threads)
endif() endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
if(NOT PK_ENABLE_DETERMINISM)
# use platform libm
target_link_libraries(${PROJECT_NAME} m)
endif()
if(PK_ENABLE_OS) if(PK_ENABLE_OS)
target_link_libraries(${PROJECT_NAME} dl) target_link_libraries(${PROJECT_NAME} dl)
endif() endif()

View File

@ -8,7 +8,7 @@ endif()
# system features # system features
option(PK_ENABLE_OS "" ON) option(PK_ENABLE_OS "" ON)
option(PK_ENABLE_THREADS "" ON) option(PK_ENABLE_THREADS "" ON)
option(PK_ENABLE_DETERMINISM "" ON) option(PK_ENABLE_DETERMINISM "" OFF)
option(PK_ENABLE_WATCHDOG "" OFF) option(PK_ENABLE_WATCHDOG "" OFF)
option(PK_ENABLE_CUSTOM_SNAME "" OFF) option(PK_ENABLE_CUSTOM_SNAME "" OFF)
option(PK_ENABLE_MIMALLOC "" OFF) option(PK_ENABLE_MIMALLOC "" OFF)

View File

@ -16,6 +16,7 @@ cmake \
-DPK_BUILD_SHARED_LIB=ON \ -DPK_BUILD_SHARED_LIB=ON \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DPK_ENABLE_OS=OFF \ -DPK_ENABLE_OS=OFF \
-DPK_ENABLE_DETERMINISM=ON \
-DPK_BUILD_MODULE_LZ4=ON \ -DPK_BUILD_MODULE_LZ4=ON \
-DPK_BUILD_MODULE_CUTE_PNG=ON \ -DPK_BUILD_MODULE_CUTE_PNG=ON \
-DPK_BUILD_MODULE_MSGPACK=ON -DPK_BUILD_MODULE_MSGPACK=ON

View File

@ -8,6 +8,7 @@ cd build
FLAGS="-DPK_BUILD_STATIC_LIB=ON \ FLAGS="-DPK_BUILD_STATIC_LIB=ON \
-DPK_ENABLE_OS=OFF \ -DPK_ENABLE_OS=OFF \
-DPK_ENABLE_DETERMINISM=ON \
-DPK_BUILD_MODULE_LZ4=ON \ -DPK_BUILD_MODULE_LZ4=ON \
-DPK_BUILD_MODULE_CUTE_PNG=ON \ -DPK_BUILD_MODULE_CUTE_PNG=ON \
-DPK_BUILD_MODULE_MSGPACK=ON \ -DPK_BUILD_MODULE_MSGPACK=ON \

View File

@ -10,6 +10,7 @@ FLAGS="-DCMAKE_TOOLCHAIN_FILE=3rd/ios.toolchain.cmake \
-DDEPLOYMENT_TARGET=13.0 \ -DDEPLOYMENT_TARGET=13.0 \
-DPK_BUILD_STATIC_LIB=ON \ -DPK_BUILD_STATIC_LIB=ON \
-DPK_ENABLE_OS=OFF \ -DPK_ENABLE_OS=OFF \
-DPK_ENABLE_DETERMINISM=ON \
-DPK_BUILD_MODULE_LZ4=ON \ -DPK_BUILD_MODULE_LZ4=ON \
-DPK_BUILD_MODULE_CUTE_PNG=ON \ -DPK_BUILD_MODULE_CUTE_PNG=ON \
-DPK_BUILD_MODULE_MSGPACK=ON \ -DPK_BUILD_MODULE_MSGPACK=ON \

View File

@ -20,7 +20,7 @@ assert config in ['Debug', 'Release', 'RelWithDebInfo']
os.chdir("build") os.chdir("build")
code = os.system(f"cmake .. -DPK_ENABLE_MIMALLOC=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}") code = os.system(f"cmake .. -DPK_ENABLE_MIMALLOC=ON -DPK_ENABLE_DETERMINISM=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}")
assert code == 0 assert code == 0
code = os.system(f"cmake --build . --config {config} -j 4") code = os.system(f"cmake --build . --config {config} -j 4")
assert code == 0 assert code == 0

10
docs/modules/colorcvt.md Normal file
View File

@ -0,0 +1,10 @@
---
icon: package
label: colorcvt
---
Provide color conversion functions.
#### Source code
:::code source="../../include/typings/colorcvt.pyi" :::

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include "pocketpy/common/utils.h"
#define c11__less(a, b) ((a) < (b)) #define c11__less(a, b) ((a) < (b))

View File

@ -1,47 +0,0 @@
#pragma once
#define DMATH_INFINITY ((float)((1e+300 * 1e+300)))
#define DMATH_NAN ((float)(DMATH_INFINITY * 0.0F))
#define DMATH_PI 3.1415926535897932384
#define DMATH_E 2.7182818284590452354
#define DMATH_DEG2RAD 0.017453292519943295
#define DMATH_RAD2DEG 57.29577951308232
#define DMATH_EPSILON 1e-10
#define DMATH_LOG2_E 1.4426950408889634
double dmath_exp2(double x);
double dmath_log2(double x);
double dmath_exp(double x);
double dmath_exp10(double x);
double dmath_log(double x);
double dmath_log10(double x);
double dmath_pow(double base, double exp);
double dmath_sqrt(double x);
double dmath_cbrt(double x);
void dmath_sincos(double x, double* sin, double* cos);
double dmath_sin(double x);
double dmath_cos(double x);
double dmath_tan(double x);
double dmath_asin(double x);
double dmath_acos(double x);
double dmath_atan(double x);
double dmath_atan2(double y, double x);
int dmath_isinf(double x);
int dmath_isnan(double x);
int dmath_isnormal(double x);
int dmath_isfinite(double x);
double dmath_fmod(double x, double y);
double dmath_copysign(double x, double y);
double dmath_fabs(double x);
double dmath_ceil(double x);
double dmath_floor(double x);
double dmath_trunc(double x);
double dmath_modf(double x, double* intpart);
double dmath_fmin(double x, double y);
double dmath_fmax(double x, double y);

View File

@ -52,6 +52,12 @@
// This is the maximum character length of a module path // This is the maximum character length of a module path
#define PK_MAX_MODULE_PATH_LEN 63 #define PK_MAX_MODULE_PATH_LEN 63
// This is some math constants
#define PK_M_PI 3.1415926535897932384
#define PK_M_E 2.7182818284590452354
#define PK_M_DEG2RAD 0.017453292519943295
#define PK_M_RAD2DEG 57.29577951308232
// Hash table load factor (smaller ones mean less collision but more memory) // Hash table load factor (smaller ones mean less collision but more memory)
// For class instance // For class instance
#define PK_INST_ATTR_LOAD_FACTOR 0.67f #define PK_INST_ATTR_LOAD_FACTOR 0.67f

View File

@ -12,6 +12,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include(FetchContent) include(FetchContent)
set(PK_ENABLE_OS OFF CACHE BOOL "" FORCE) set(PK_ENABLE_OS OFF CACHE BOOL "" FORCE)
set(PK_ENABLE_DETERMINISM ON CACHE BOOL "" FORCE)
set(PK_BUILD_MODULE_LZ4 ON CACHE BOOL "" FORCE) set(PK_BUILD_MODULE_LZ4 ON CACHE BOOL "" FORCE)
set(PK_BUILD_MODULE_CUTE_PNG ON CACHE BOOL "" FORCE) set(PK_BUILD_MODULE_CUTE_PNG ON CACHE BOOL "" FORCE)
set(PK_BUILD_MODULE_MSGPACK ON CACHE BOOL "" FORCE) set(PK_BUILD_MODULE_MSGPACK ON CACHE BOOL "" FORCE)

View File

@ -57,5 +57,3 @@ assert_never = lambda x: x
TypedDict = dict TypedDict = dict
NotRequired = _PLACEHOLDER NotRequired = _PLACEHOLDER
cast = lambda _, val: val

View File

@ -1,25 +0,0 @@
import math
def generate_sin_table(num_points = 4096 + 1):
y_step = 1.0 / (num_points - 1)
sin_table = []
for i in range(num_points):
y = i * y_step
x = math.asin(y)
x = max(0, min(x, math.pi / 2))
sin_table.append(x)
return sin_table
if __name__ == "__main__":
sin_table = generate_sin_table()
print(len(sin_table))
# print(sin_table)
filepath = 'include/pocketpy/common/_sin_table.h'
with open(filepath, 'w') as f:
f.write('static const double _sin_table[] = {')
for i, val in enumerate(sin_table):
if i % 8 == 0:
f.write('\n ')
f.write(str(val) + ', ')
f.write('\n};\n')

View File

@ -1,8 +1,8 @@
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include <math.h>
static bool try_castfloat(py_Ref self, double* out) { static bool try_castfloat(py_Ref self, double* out) {
switch(self->type) { switch(self->type) {
@ -100,7 +100,7 @@ static bool number__pow__(int argc, py_Ref argv) {
if(lhs == 0) { if(lhs == 0) {
return ZeroDivisionError("0.0 cannot be raised to a negative power"); return ZeroDivisionError("0.0 cannot be raised to a negative power");
} else { } else {
py_newfloat(py_retval(), dmath_pow(lhs, rhs)); py_newfloat(py_retval(), pow(lhs, rhs));
} }
} else { } else {
// rhs >= 0 // rhs >= 0
@ -117,7 +117,7 @@ static bool number__pow__(int argc, py_Ref argv) {
py_f64 lhs, rhs; py_f64 lhs, rhs;
if(!py_castfloat(&argv[0], &lhs)) return false; if(!py_castfloat(&argv[0], &lhs)) return false;
if(try_castfloat(&argv[1], &rhs)) { if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), dmath_pow(lhs, rhs)); py_newfloat(py_retval(), pow(lhs, rhs));
} else { } else {
py_newnotimplemented(py_retval()); py_newnotimplemented(py_retval());
} }
@ -153,7 +153,7 @@ static py_i64 cpy11__fast_mod(py_i64 a, py_i64 b) {
static void cpy11__float_div_mod(double vx, double wx, double *floordiv, double *mod) static void cpy11__float_div_mod(double vx, double wx, double *floordiv, double *mod)
{ {
double div; double div;
*mod = dmath_fmod(vx, wx); *mod = fmod(vx, wx);
/* fmod is typically exact, so vx-mod is *mathematically* an /* fmod is typically exact, so vx-mod is *mathematically* an
exact multiple of wx. But this is fp arithmetic, and fp exact multiple of wx. But this is fp arithmetic, and fp
vx - mod is an approximation; the result is that div may vx - mod is an approximation; the result is that div may
@ -172,18 +172,18 @@ static void cpy11__float_div_mod(double vx, double wx, double *floordiv, double
/* the remainder is zero, and in the presence of signed zeroes /* the remainder is zero, and in the presence of signed zeroes
fmod returns different results across platforms; ensure fmod returns different results across platforms; ensure
it has the same sign as the denominator. */ it has the same sign as the denominator. */
*mod = dmath_copysign(0.0, wx); *mod = copysign(0.0, wx);
} }
/* snap quotient to nearest integral value */ /* snap quotient to nearest integral value */
if (div) { if (div) {
*floordiv = dmath_floor(div); *floordiv = floor(div);
if (div - *floordiv > 0.5) { if (div - *floordiv > 0.5) {
*floordiv += 1.0; *floordiv += 1.0;
} }
} }
else { else {
/* div is zero - get the same sign as the true quotient */ /* div is zero - get the same sign as the true quotient */
*floordiv = dmath_copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */ *floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */
} }
} }
@ -471,11 +471,11 @@ static bool float__new__(int argc, py_Ref argv) {
c11_sv sv = py_tosv(py_arg(1)); c11_sv sv = py_tosv(py_arg(1));
if(c11__sveq2(sv, "inf")) { if(c11__sveq2(sv, "inf")) {
py_newfloat(py_retval(), DMATH_INFINITY); py_newfloat(py_retval(), INFINITY);
return true; return true;
} }
if(c11__sveq2(sv, "-inf")) { if(c11__sveq2(sv, "-inf")) {
py_newfloat(py_retval(), -DMATH_INFINITY); py_newfloat(py_retval(), -INFINITY);
return true; return true;
} }

View File

@ -11,7 +11,7 @@ const char kPythonLibs_functools[] = "class cache:\n def __init__(self, f):\n
const char kPythonLibs_heapq[] = "# Heap queue algorithm (a.k.a. priority queue)\ndef heappush(heap, item):\n \"\"\"Push item onto heap, maintaining the heap invariant.\"\"\"\n heap.append(item)\n _siftdown(heap, 0, len(heap)-1)\n\ndef heappop(heap):\n \"\"\"Pop the smallest item off the heap, maintaining the heap invariant.\"\"\"\n lastelt = heap.pop() # raises appropriate IndexError if heap is empty\n if heap:\n returnitem = heap[0]\n heap[0] = lastelt\n _siftup(heap, 0)\n return returnitem\n return lastelt\n\ndef heapreplace(heap, item):\n \"\"\"Pop and return the current smallest value, and add the new item.\n\n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed-size heap. Note that the value\n returned may be larger than item! That constrains reasonable uses of\n this routine unless written as part of a conditional replacement:\n\n if item > heap[0]:\n item = heapreplace(heap, item)\n \"\"\"\n returnitem = heap[0] # raises appropriate IndexError if heap is empty\n heap[0] = item\n _siftup(heap, 0)\n return returnitem\n\ndef heappushpop(heap, item):\n \"\"\"Fast version of a heappush followed by a heappop.\"\"\"\n if heap and heap[0] < item:\n item, heap[0] = heap[0], item\n _siftup(heap, 0)\n return item\n\ndef heapify(x):\n \"\"\"Transform list into a heap, in-place, in O(len(x)) time.\"\"\"\n n = len(x)\n # Transform bottom-up. The largest index there's any point to looking at\n # is the largest with a child index in-range, so must have 2*i + 1 < n,\n # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so\n # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is\n # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.\n for i in reversed(range(n//2)):\n _siftup(x, i)\n\n# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos\n# is the index of a leaf with a possibly out-of-order value. Restore the\n# heap invariant.\ndef _siftdown(heap, startpos, pos):\n newitem = heap[pos]\n # Follow the path to the root, moving parents down until finding a place\n # newitem fits.\n while pos > startpos:\n parentpos = (pos - 1) >> 1\n parent = heap[parentpos]\n if newitem < parent:\n heap[pos] = parent\n pos = parentpos\n continue\n break\n heap[pos] = newitem\n\ndef _siftup(heap, pos):\n endpos = len(heap)\n startpos = pos\n newitem = heap[pos]\n # Bubble up the smaller child until hitting a leaf.\n childpos = 2*pos + 1 # leftmost child position\n while childpos < endpos:\n # Set childpos to index of smaller child.\n rightpos = childpos + 1\n if rightpos < endpos and not heap[childpos] < heap[rightpos]:\n childpos = rightpos\n # Move the smaller child up.\n heap[pos] = heap[childpos]\n pos = childpos\n childpos = 2*pos + 1\n # The leaf at pos is empty now. Put newitem there, and bubble it up\n # to its final resting place (by sifting its parents down).\n heap[pos] = newitem\n _siftdown(heap, startpos, pos)"; const char kPythonLibs_heapq[] = "# Heap queue algorithm (a.k.a. priority queue)\ndef heappush(heap, item):\n \"\"\"Push item onto heap, maintaining the heap invariant.\"\"\"\n heap.append(item)\n _siftdown(heap, 0, len(heap)-1)\n\ndef heappop(heap):\n \"\"\"Pop the smallest item off the heap, maintaining the heap invariant.\"\"\"\n lastelt = heap.pop() # raises appropriate IndexError if heap is empty\n if heap:\n returnitem = heap[0]\n heap[0] = lastelt\n _siftup(heap, 0)\n return returnitem\n return lastelt\n\ndef heapreplace(heap, item):\n \"\"\"Pop and return the current smallest value, and add the new item.\n\n This is more efficient than heappop() followed by heappush(), and can be\n more appropriate when using a fixed-size heap. Note that the value\n returned may be larger than item! That constrains reasonable uses of\n this routine unless written as part of a conditional replacement:\n\n if item > heap[0]:\n item = heapreplace(heap, item)\n \"\"\"\n returnitem = heap[0] # raises appropriate IndexError if heap is empty\n heap[0] = item\n _siftup(heap, 0)\n return returnitem\n\ndef heappushpop(heap, item):\n \"\"\"Fast version of a heappush followed by a heappop.\"\"\"\n if heap and heap[0] < item:\n item, heap[0] = heap[0], item\n _siftup(heap, 0)\n return item\n\ndef heapify(x):\n \"\"\"Transform list into a heap, in-place, in O(len(x)) time.\"\"\"\n n = len(x)\n # Transform bottom-up. The largest index there's any point to looking at\n # is the largest with a child index in-range, so must have 2*i + 1 < n,\n # or i < (n-1)/2. If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so\n # j-1 is the largest, which is n//2 - 1. If n is odd = 2*j+1, this is\n # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.\n for i in reversed(range(n//2)):\n _siftup(x, i)\n\n# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos\n# is the index of a leaf with a possibly out-of-order value. Restore the\n# heap invariant.\ndef _siftdown(heap, startpos, pos):\n newitem = heap[pos]\n # Follow the path to the root, moving parents down until finding a place\n # newitem fits.\n while pos > startpos:\n parentpos = (pos - 1) >> 1\n parent = heap[parentpos]\n if newitem < parent:\n heap[pos] = parent\n pos = parentpos\n continue\n break\n heap[pos] = newitem\n\ndef _siftup(heap, pos):\n endpos = len(heap)\n startpos = pos\n newitem = heap[pos]\n # Bubble up the smaller child until hitting a leaf.\n childpos = 2*pos + 1 # leftmost child position\n while childpos < endpos:\n # Set childpos to index of smaller child.\n rightpos = childpos + 1\n if rightpos < endpos and not heap[childpos] < heap[rightpos]:\n childpos = rightpos\n # Move the smaller child up.\n heap[pos] = heap[childpos]\n pos = childpos\n childpos = 2*pos + 1\n # The leaf at pos is empty now. Put newitem there, and bubble it up\n # to its final resting place (by sifting its parents down).\n heap[pos] = newitem\n _siftdown(heap, startpos, pos)";
const char kPythonLibs_linalg[] = "from vmath import *"; const char kPythonLibs_linalg[] = "from vmath import *";
const char kPythonLibs_operator[] = "# https://docs.python.org/3/library/operator.html#mapping-operators-to-functions\n\ndef le(a, b): return a <= b\ndef lt(a, b): return a < b\ndef ge(a, b): return a >= b\ndef gt(a, b): return a > b\ndef eq(a, b): return a == b\ndef ne(a, b): return a != b\n\ndef and_(a, b): return a & b\ndef or_(a, b): return a | b\ndef xor(a, b): return a ^ b\ndef invert(a): return ~a\ndef lshift(a, b): return a << b\ndef rshift(a, b): return a >> b\n\ndef is_(a, b): return a is b\ndef is_not(a, b): return a is not b\ndef not_(a): return not a\ndef truth(a): return bool(a)\ndef contains(a, b): return b in a\n\ndef add(a, b): return a + b\ndef sub(a, b): return a - b\ndef mul(a, b): return a * b\ndef truediv(a, b): return a / b\ndef floordiv(a, b): return a // b\ndef mod(a, b): return a % b\ndef pow(a, b): return a ** b\ndef neg(a): return -a\ndef matmul(a, b): return a @ b\n\ndef getitem(a, b): return a[b]\ndef setitem(a, b, c): a[b] = c\ndef delitem(a, b): del a[b]\n\ndef iadd(a, b): a += b; return a\ndef isub(a, b): a -= b; return a\ndef imul(a, b): a *= b; return a\ndef itruediv(a, b): a /= b; return a\ndef ifloordiv(a, b): a //= b; return a\ndef imod(a, b): a %= b; return a\n# def ipow(a, b): a **= b; return a\n# def imatmul(a, b): a @= b; return a\ndef iand(a, b): a &= b; return a\ndef ior(a, b): a |= b; return a\ndef ixor(a, b): a ^= b; return a\ndef ilshift(a, b): a <<= b; return a\ndef irshift(a, b): a >>= b; return a\n\nclass attrgetter:\n def __init__(self, attr):\n self.attr = attr\n def __call__(self, obj):\n return getattr(obj, self.attr)\n"; const char kPythonLibs_operator[] = "# https://docs.python.org/3/library/operator.html#mapping-operators-to-functions\n\ndef le(a, b): return a <= b\ndef lt(a, b): return a < b\ndef ge(a, b): return a >= b\ndef gt(a, b): return a > b\ndef eq(a, b): return a == b\ndef ne(a, b): return a != b\n\ndef and_(a, b): return a & b\ndef or_(a, b): return a | b\ndef xor(a, b): return a ^ b\ndef invert(a): return ~a\ndef lshift(a, b): return a << b\ndef rshift(a, b): return a >> b\n\ndef is_(a, b): return a is b\ndef is_not(a, b): return a is not b\ndef not_(a): return not a\ndef truth(a): return bool(a)\ndef contains(a, b): return b in a\n\ndef add(a, b): return a + b\ndef sub(a, b): return a - b\ndef mul(a, b): return a * b\ndef truediv(a, b): return a / b\ndef floordiv(a, b): return a // b\ndef mod(a, b): return a % b\ndef pow(a, b): return a ** b\ndef neg(a): return -a\ndef matmul(a, b): return a @ b\n\ndef getitem(a, b): return a[b]\ndef setitem(a, b, c): a[b] = c\ndef delitem(a, b): del a[b]\n\ndef iadd(a, b): a += b; return a\ndef isub(a, b): a -= b; return a\ndef imul(a, b): a *= b; return a\ndef itruediv(a, b): a /= b; return a\ndef ifloordiv(a, b): a //= b; return a\ndef imod(a, b): a %= b; return a\n# def ipow(a, b): a **= b; return a\n# def imatmul(a, b): a @= b; return a\ndef iand(a, b): a &= b; return a\ndef ior(a, b): a |= b; return a\ndef ixor(a, b): a ^= b; return a\ndef ilshift(a, b): a <<= b; return a\ndef irshift(a, b): a >>= b; return a\n\nclass attrgetter:\n def __init__(self, attr):\n self.attr = attr\n def __call__(self, obj):\n return getattr(obj, self.attr)\n";
const char kPythonLibs_typing[] = "class _Placeholder:\n def __init__(self, *args, **kwargs):\n pass\n def __getitem__(self, *args):\n return self\n def __call__(self, *args, **kwargs):\n return self\n def __and__(self, other):\n return self\n def __or__(self, other):\n return self\n def __xor__(self, other):\n return self\n\n\n_PLACEHOLDER = _Placeholder()\n\nSequence = _PLACEHOLDER\nList = _PLACEHOLDER\nDict = _PLACEHOLDER\nTuple = _PLACEHOLDER\nSet = _PLACEHOLDER\nAny = _PLACEHOLDER\nUnion = _PLACEHOLDER\nOptional = _PLACEHOLDER\nCallable = _PLACEHOLDER\nType = _PLACEHOLDER\nTypeAlias = _PLACEHOLDER\nNewType = _PLACEHOLDER\n\nClassVar = _PLACEHOLDER\n\nLiteral = _PLACEHOLDER\nLiteralString = _PLACEHOLDER\n\nIterable = _PLACEHOLDER\nGenerator = _PLACEHOLDER\nIterator = _PLACEHOLDER\n\nHashable = _PLACEHOLDER\n\nTypeVar = _PLACEHOLDER\nSelf = _PLACEHOLDER\n\nProtocol = object\nGeneric = object\nNever = object\n\nTYPE_CHECKING = False\n\n# decorators\noverload = lambda x: x\nfinal = lambda x: x\n\n# exhaustiveness checking\nassert_never = lambda x: x\n\nTypedDict = dict\nNotRequired = _PLACEHOLDER\n\ncast = lambda _, val: val\n"; const char kPythonLibs_typing[] = "class _Placeholder:\n def __init__(self, *args, **kwargs):\n pass\n def __getitem__(self, *args):\n return self\n def __call__(self, *args, **kwargs):\n return self\n def __and__(self, other):\n return self\n def __or__(self, other):\n return self\n def __xor__(self, other):\n return self\n\n\n_PLACEHOLDER = _Placeholder()\n\nSequence = _PLACEHOLDER\nList = _PLACEHOLDER\nDict = _PLACEHOLDER\nTuple = _PLACEHOLDER\nSet = _PLACEHOLDER\nAny = _PLACEHOLDER\nUnion = _PLACEHOLDER\nOptional = _PLACEHOLDER\nCallable = _PLACEHOLDER\nType = _PLACEHOLDER\nTypeAlias = _PLACEHOLDER\nNewType = _PLACEHOLDER\n\nClassVar = _PLACEHOLDER\n\nLiteral = _PLACEHOLDER\nLiteralString = _PLACEHOLDER\n\nIterable = _PLACEHOLDER\nGenerator = _PLACEHOLDER\nIterator = _PLACEHOLDER\n\nHashable = _PLACEHOLDER\n\nTypeVar = _PLACEHOLDER\nSelf = _PLACEHOLDER\n\nProtocol = object\nGeneric = object\nNever = object\n\nTYPE_CHECKING = False\n\n# decorators\noverload = lambda x: x\nfinal = lambda x: x\n\n# exhaustiveness checking\nassert_never = lambda x: x\n\nTypedDict = dict\nNotRequired = _PLACEHOLDER\n";
const char* load_kPythonLib(const char* name) { const char* load_kPythonLib(const char* name) {
if (strchr(name, '.') != NULL) return NULL; if (strchr(name, '.') != NULL) return NULL;

View File

@ -1,706 +0,0 @@
#include "pocketpy/common/dmath.h"
#include "pocketpy/common/algorithm.h"
#include "pocketpy/common/_log_spline_tbl.h"
#include <stdint.h>
union Float64Bits {
double f;
uint64_t i;
};
/* IEEE 754 double precision floating point data manipulation */
typedef union
{
double f;
uint64_t u;
struct {int32_t i0,i1;} s;
} udi_t;
// https://github.com/akohlmey/fastermath/blob/master/src/exp.c#L63
double dmath_exp2(double x) {
if (x > 1000) return DMATH_INFINITY;
if (x < -1000) return 0;
if (dmath_isnan(x)) return DMATH_NAN;
const int FM_DOUBLE_BIAS = 1023;
static const double fm_exp2_q[] = {
/* 1.00000000000000000000e0, */
2.33184211722314911771e2,
4.36821166879210612817e3
};
static const double fm_exp2_p[] = {
2.30933477057345225087e-2,
2.02020656693165307700e1,
1.51390680115615096133e3
};
double ipart, fpart, px, qx;
udi_t epart;
ipart = dmath_floor(x+0.5);
fpart = x - ipart;
// FM_DOUBLE_INIT_EXP(epart,ipart);
epart.s.i0 = 0;
epart.s.i1 = (((int) ipart) + FM_DOUBLE_BIAS) << 20;
x = fpart*fpart;
px = fm_exp2_p[0];
px = px*x + fm_exp2_p[1];
qx = x + fm_exp2_q[0];
px = px*x + fm_exp2_p[2];
qx = qx*x + fm_exp2_q[1];
px = px * fpart;
x = 1.0 + 2.0*(px/(qx-px));
return epart.f*x;
}
double dmath_log2(double x) {
if(x < 0) return DMATH_NAN;
if(x == 0) return -DMATH_INFINITY;
if(x == DMATH_INFINITY) return DMATH_INFINITY;
if(dmath_isnan(x)) return DMATH_NAN;
const double fm_log_dinv = 4.09600000000000000000e+03;
const double fm_log_dsq6 = 9.93410746256510361521e-09;
const int FM_DOUBLE_BIAS = 1023;
const int FM_DOUBLE_EMASK = 2146435072;
const int FM_DOUBLE_MBITS = 20;
const int FM_DOUBLE_MMASK = 1048575;
const int FM_DOUBLE_EZERO = 1072693248;
const int FM_SPLINE_SHIFT = 8;
udi_t val;
double a,b,y;
int32_t hx, ipart;
val.f = x;
hx = val.s.i1;
/* extract exponent and subtract bias */
ipart = (((hx & FM_DOUBLE_EMASK) >> FM_DOUBLE_MBITS) - FM_DOUBLE_BIAS);
/* mask out exponent to get the prefactor to 2**ipart */
hx &= FM_DOUBLE_MMASK;
val.s.i1 = hx | FM_DOUBLE_EZERO;
x = val.f;
/* table index */
hx >>= FM_SPLINE_SHIFT;
/* compute x value matching table index */
val.s.i0 = 0;
val.s.i1 = FM_DOUBLE_EZERO | (hx << FM_SPLINE_SHIFT);
b = (x - val.f) * fm_log_dinv;
a = 1.0 - b;
/* evaluate spline */
y = a * fm_log_q1[hx] + b * fm_log_q1[hx+1];
a = (a*a*a-a) * fm_log_q2[hx];
b = (b*b*b-b) * fm_log_q2[hx+1];
y += (a + b) * fm_log_dsq6;
return ((double) ipart) + (y * DMATH_LOG2_E);
}
double dmath_exp(double x) {
return dmath_exp2(x * DMATH_LOG2_E); // log2(e)
}
double dmath_exp10(double x) {
return dmath_exp2(x * 3.321928094887362); // log2(10)
}
double dmath_log(double x) {
return dmath_log2(x) / DMATH_LOG2_E; // log2(e)
}
double dmath_log10(double x) {
return dmath_log2(x) / 3.321928094887362; // log2(10)
}
double dmath_pow(double base, double exp) {
int exp_int = (int)exp;
if(exp_int == exp) {
if(exp_int == 0) return 1;
if(exp_int < 0) {
base = 1 / base;
exp_int = -exp_int;
}
double res = 1;
while(exp_int > 0) {
if(exp_int & 1) res *= base;
base *= base;
exp_int >>= 1;
}
return res;
}
if (base > 0) {
return dmath_exp(exp * dmath_log(base));
}
if (base == 0) {
if (exp > 0) return 0;
if (exp == 0) return 1;
}
return DMATH_NAN;
}
double dmath_sqrt(double x) {
return dmath_pow(x, 0.5);
}
double dmath_cbrt(double x) {
return dmath_pow(x, 1.0 / 3.0);
}
// https://github.com/kraj/musl/blob/kraj/master/src/math/sincos.c
static double __sin(double x, double y, int iy)
{
static const double
S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
double z,r,v,w;
z = x*x;
w = z*z;
r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6);
v = z*x;
if (iy == 0)
return x + v*(S1 + z*r);
else
return x - ((z*(0.5*y - v*r) - y) - v*S1);
}
static double __cos(double x, double y)
{
static const double
C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
double hz,z,r,w;
z = x*x;
w = z*z;
r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
hz = 0.5*z;
w = 1.0-hz;
return w + (((1.0-w)-hz) + (z*r-x*y));
}
int __rem_pio2(double x, double *y)
{
static const double
toint = 1.5/2.22044604925031308085e-16,
pio4 = 0x1.921fb54442d18p-1,
invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
union Float64Bits u = { .f = x };
double z,w,t,r,fn;
double tx[3],ty[2];
uint32_t ix;
int sign, n, ex, ey, i;
sign = u.i>>63;
ix = u.i>>32 & 0x7fffffff;
if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */
if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */
goto medium; /* cancellation -- use medium case */
if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */
if (!sign) {
z = x - pio2_1; /* one round good to 85 bits */
y[0] = z - pio2_1t;
y[1] = (z-y[0]) - pio2_1t;
return 1;
} else {
z = x + pio2_1;
y[0] = z + pio2_1t;
y[1] = (z-y[0]) + pio2_1t;
return -1;
}
} else {
if (!sign) {
z = x - 2*pio2_1;
y[0] = z - 2*pio2_1t;
y[1] = (z-y[0]) - 2*pio2_1t;
return 2;
} else {
z = x + 2*pio2_1;
y[0] = z + 2*pio2_1t;
y[1] = (z-y[0]) + 2*pio2_1t;
return -2;
}
}
}
if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */
if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */
if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */
goto medium;
if (!sign) {
z = x - 3*pio2_1;
y[0] = z - 3*pio2_1t;
y[1] = (z-y[0]) - 3*pio2_1t;
return 3;
} else {
z = x + 3*pio2_1;
y[0] = z + 3*pio2_1t;
y[1] = (z-y[0]) + 3*pio2_1t;
return -3;
}
} else {
if (ix == 0x401921fb) /* |x| ~= 4pi/2 */
goto medium;
if (!sign) {
z = x - 4*pio2_1;
y[0] = z - 4*pio2_1t;
y[1] = (z-y[0]) - 4*pio2_1t;
return 4;
} else {
z = x + 4*pio2_1;
y[0] = z + 4*pio2_1t;
y[1] = (z-y[0]) + 4*pio2_1t;
return -4;
}
}
}
if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */
medium:
/* rint(x/(pi/2)) */
fn = (double)x*invpio2 + toint - toint;
n = (int32_t)fn;
r = x - fn*pio2_1;
w = fn*pio2_1t; /* 1st round, good to 85 bits */
/* Matters with directed rounding. */
if ((r - w < -pio4)) {
n--;
fn--;
r = x - fn*pio2_1;
w = fn*pio2_1t;
} else if ((r - w > pio4)) {
n++;
fn++;
r = x - fn*pio2_1;
w = fn*pio2_1t;
}
y[0] = r - w;
u.f = y[0];
ey = u.i>>52 & 0x7ff;
ex = ix>>20;
if (ex - ey > 16) { /* 2nd round, good to 118 bits */
t = r;
w = fn*pio2_2;
r = t - w;
w = fn*pio2_2t - ((t-r)-w);
y[0] = r - w;
u.f = y[0];
ey = u.i>>52 & 0x7ff;
if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */
t = r;
w = fn*pio2_3;
r = t - w;
w = fn*pio2_3t - ((t-r)-w);
y[0] = r - w;
}
}
y[1] = (r - y[0]) - w;
return n;
}
(void)tx;
(void)ty;
(void)i;
return 0;
#if 0
/*
* all other (large) arguments
*/
if (ix >= 0x7ff00000) { /* x is inf or NaN */
y[0] = y[1] = x - x;
return 0;
}
/* set z = scalbn(|x|,-ilogb(x)+23) */
u.f = x;
u.i &= (uint64_t)-1>>12;
u.i |= (uint64_t)(0x3ff + 23)<<52;
z = u.f;
for (i=0; i < 2; i++) {
tx[i] = (double)(int32_t)z;
z = (z-tx[i])*0x1p24;
}
tx[i] = z;
/* skip zero terms, first term is non-zero */
while (tx[i] == 0.0)
i--;
n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1);
if (sign) {
y[0] = -ty[0];
y[1] = -ty[1];
return -n;
}
y[0] = ty[0];
y[1] = ty[1];
return n;
#endif
}
void dmath_sincos(double x, double *sin, double *cos) {
double y[2], s, c;
uint32_t ix;
unsigned n;
//GET_HIGH_WORD(ix, x);
union Float64Bits u = { .f = x };
ix = (uint32_t)(u.i >> 32);
ix &= 0x7fffffff;
/* |x| ~< pi/4 */
if (ix <= 0x3fe921fb) {
/* if |x| < 2**-27 * sqrt(2) */
if (ix < 0x3e46a09e) {
/* raise inexact if x!=0 and underflow if subnormal */
// FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
volatile double y_force_eval;
y_force_eval = ix < 0x00100000 ? x/0x1p120f : x+0x1p120f;
(void)y_force_eval;
*sin = x;
*cos = 1.0;
return;
}
*sin = __sin(x, 0.0, 0);
*cos = __cos(x, 0.0);
return;
}
/* sincos(Inf or NaN) is NaN */
if (ix >= 0x7ff00000) {
*sin = *cos = x - x;
return;
}
/* argument reduction needed */
n = __rem_pio2(x, y);
s = __sin(y[0], y[1], 1);
c = __cos(y[0], y[1]);
switch (n&3) {
case 0:
*sin = s;
*cos = c;
break;
case 1:
*sin = c;
*cos = -s;
break;
case 2:
*sin = -s;
*cos = -c;
break;
case 3:
default:
*sin = -c;
*cos = s;
break;
}
}
double dmath_sin(double x) {
double s, c;
dmath_sincos(x, &s, &c);
return s;
}
double dmath_cos(double x) {
double s, c;
dmath_sincos(x, &s, &c);
return c;
}
double dmath_tan(double x) {
double s, c;
dmath_sincos(x, &s, &c);
return s / c;
}
static double zig_r64(double z) {
const double pS0 = 1.66666666666666657415e-01;
const double pS1 = -3.25565818622400915405e-01;
const double pS2 = 2.01212532134862925881e-01;
const double pS3 = -4.00555345006794114027e-02;
const double pS4 = 7.91534994289814532176e-04;
const double pS5 = 3.47933107596021167570e-05;
const double qS1 = -2.40339491173441421878e+00;
const double qS2 = 2.02094576023350569471e+00;
const double qS3 = -6.88283971605453293030e-01;
const double qS4 = 7.70381505559019352791e-02;
double p = z * (pS0 + z * (pS1 + z * (pS2 + z * (pS3 + z * (pS4 + z * pS5)))));
double q = 1.0 + z * (qS1 + z * (qS2 + z * (qS3 + z * qS4)));
return p / q;
}
// https://github.com/ziglang/zig/blob/master/lib/std/math/asin.zig
double dmath_asin(double x) {
const double pio2_hi = 1.57079632679489655800e+00;
const double pio2_lo = 6.12323399573676603587e-17;
union Float64Bits ux_union;
ux_union.f = x;
uint64_t ux = ux_union.i;
uint32_t hx = (uint32_t)(ux >> 32);
uint32_t ix = hx & 0x7FFFFFFF;
/* |x| >= 1 or nan */
if (ix >= 0x3FF00000) {
uint32_t lx = (uint32_t)(ux & 0xFFFFFFFF);
/* asin(1) = +-pi/2 with inexact */
if (((ix - 0x3FF00000) | lx) == 0) {
return x * pio2_hi + 0x1.0p-120;
} else {
return DMATH_NAN;
}
}
/* |x| < 0.5 */
if (ix < 0x3FE00000) {
/* if 0x1p-1022 <= |x| < 0x1p-26 avoid raising overflow */
if (ix < 0x3E500000 && ix >= 0x00100000) {
return x;
} else {
return x + x * zig_r64(x * x);
}
}
/* 1 > |x| >= 0.5 */
double z = (1 - dmath_fabs(x)) * 0.5;
double s = dmath_sqrt(z);
double r = zig_r64(z);
double fx;
/* |x| > 0.975 */
if (ix >= 0x3FEF3333) {
fx = pio2_hi - 2 * (s + s * r);
} else {
union Float64Bits jx_union = { .f = s };
uint64_t jx = jx_union.i;
union Float64Bits df_union = { .i = jx & 0xFFFFFFFF00000000ULL };
double df = df_union.f;
double c = (z - df * df) / (s + df);
fx = 0.5 * pio2_hi - (2 * s * r - (pio2_lo - 2 * c) - (0.5 * pio2_hi - 2 * df));
}
if (hx >> 31 != 0) {
return -fx;
} else {
return fx;
}
}
double dmath_acos(double x) {
return DMATH_PI / 2 - dmath_asin(x);
}
double dmath_atan(double x) {
return dmath_asin(x / dmath_sqrt(1 + x * x));
}
double dmath_atan2(double y, double x) {
if (x > 0) {
return dmath_atan(y / x);
} else if (x < 0 && y >= 0) {
return dmath_atan(y / x) + DMATH_PI;
} else if (x < 0 && y < 0) {
return dmath_atan(y / x) - DMATH_PI;
} else if (x == 0 && y > 0) {
return DMATH_PI / 2;
} else if (x == 0 && y < 0) {
return -DMATH_PI / 2;
} else {
return DMATH_NAN;
}
}
////////////////////////////////////////////////////////////////////
int dmath_isinf(double x) {
union Float64Bits u = { .f = x };
return (u.i & -1ULL>>1) == 0x7ffULL<<52;
}
int dmath_isnan(double x) {
union Float64Bits u = { .f = x };
return (u.i & -1ULL>>1) > 0x7ffULL<<52;
}
int dmath_isnormal(double x) {
union Float64Bits u = { .f = x };
return ((u.i+(1ULL<<52)) & -1ULL>>1) >= 1ULL<<53;
}
int dmath_isfinite(double x) {
union Float64Bits u = { .f = x };
return (u.i & -1ULL>>1) < 0x7ffULL<<52;
}
// https://github.com/kraj/musl/blob/kraj/master/src/math/fmod.c
double dmath_fmod(double x, double y) {
union Float64Bits ux = { .f = x }, uy = { .f = y };
int ex = ux.i>>52 & 0x7ff;
int ey = uy.i>>52 & 0x7ff;
int sx = ux.i>>63;
uint64_t i;
/* in the followings uxi should be ux.i, but then gcc wrongly adds */
/* float load/store to inner loops ruining performance and code size */
uint64_t uxi = ux.i;
if (uy.i<<1 == 0 || dmath_isnan(y) || ex == 0x7ff)
return (x*y)/(x*y);
if (uxi<<1 <= uy.i<<1) {
if (uxi<<1 == uy.i<<1)
return 0*x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1ULL >> 12;
uxi |= 1ULL << 52;
}
if (!ey) {
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1ULL >> 12;
uy.i |= 1ULL << 52;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
for (; uxi>>52 == 0; uxi <<= 1, ex--);
/* scale result */
if (ex > 0) {
uxi -= 1ULL << 52;
uxi |= (uint64_t)ex << 52;
} else {
uxi >>= -ex + 1;
}
uxi |= (uint64_t)sx << 63;
ux.i = uxi;
return ux.f;
}
// https://github.com/kraj/musl/blob/kraj/master/src/math/copysign.c
double dmath_copysign(double x, double y) {
union Float64Bits ux = { .f = x }, uy = { .f = y };
ux.i &= -1ULL/2;
ux.i |= uy.i & 1ULL<<63;
return ux.f;
}
double dmath_fabs(double x) {
return (x < 0) ? -x : x;
}
double dmath_ceil(double x) {
if(!dmath_isfinite(x)) return x;
int int_part = (int)x;
if (x > 0 && x != (double)int_part) {
return (double)(int_part + 1);
}
return (double)int_part;
}
double dmath_floor(double x) {
if(!dmath_isfinite(x)) return x;
int int_part = (int)x;
if (x < 0 && x != (double)int_part) {
return (double)(int_part - 1);
}
return (double)int_part;
}
double dmath_trunc(double x) {
return (double)((int)x);
}
// https://github.com/kraj/musl/blob/kraj/master/src/math/modf.c
double dmath_modf(double x, double* iptr) {
union Float64Bits u = { .f = x };
uint64_t mask;
int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
/* no fractional part */
if (e >= 52) {
*iptr = x;
if (e == 0x400 && u.i<<12 != 0) /* nan */
return x;
u.i &= 1ULL<<63;
return u.f;
}
/* no integral part*/
if (e < 0) {
u.i &= 1ULL<<63;
*iptr = u.f;
return x;
}
mask = -1ULL>>12>>e;
if ((u.i & mask) == 0) {
*iptr = x;
u.i &= 1ULL<<63;
return u.f;
}
u.i &= ~mask;
*iptr = u.f;
return x - u.f;
}
double dmath_fmin(double x, double y) {
return (x < y) ? x : y;
}
double dmath_fmax(double x, double y) {
return (x > y) ? x : y;
}

View File

@ -1,13 +1,13 @@
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/common/str.h" #include "pocketpy/common/str.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <math.h>
void c11_sbuf__ctor(c11_sbuf* self) { void c11_sbuf__ctor(c11_sbuf* self) {
c11_vector__ctor(&self->data, sizeof(char)); c11_vector__ctor(&self->data, sizeof(char));
@ -42,11 +42,11 @@ void c11_sbuf__write_i64(c11_sbuf* self, int64_t val) {
} }
void c11_sbuf__write_f64(c11_sbuf* self, double val, int precision) { void c11_sbuf__write_f64(c11_sbuf* self, double val, int precision) {
if(dmath_isinf(val)) { if(isinf(val)) {
c11_sbuf__write_cstr(self, val > 0 ? "inf" : "-inf"); c11_sbuf__write_cstr(self, val > 0 ? "inf" : "-inf");
return; return;
} }
if(dmath_isnan(val)) { if(isnan(val)) {
c11_sbuf__write_cstr(self, "nan"); c11_sbuf__write_cstr(self, "nan");
return; return;
} }

View File

@ -242,7 +242,7 @@ void VM__ctor(VM* self) {
pk__add_module_stdc(); pk__add_module_stdc();
pk__add_module_vmath(); pk__add_module_vmath();
pk__add_module_array2d(); pk__add_module_array2d();
// pk__add_module_colorcvt(); pk__add_module_colorcvt();
// add modules // add modules
pk__add_module_os(); pk__add_module_os();

View File

@ -3,12 +3,13 @@
#include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/codeobject.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/_generated.h" #include "pocketpy/common/_generated.h"
#include <math.h>
static bool builtins_exit(int argc, py_Ref argv) { static bool builtins_exit(int argc, py_Ref argv) {
int code = 0; int code = 0;
@ -172,9 +173,7 @@ static bool builtins_round(int argc, py_Ref argv) {
py_newint(py_retval(), (py_i64)(x + offset)); py_newint(py_retval(), (py_i64)(x + offset));
return true; return true;
} }
// py_f64 factor = dmath_exp10(ndigits); py_f64 factor = pow(10, ndigits);
py_f64 factor = 1.0;
for(int i = 0; i < ndigits; i++) factor *= 10.0;
py_newfloat(py_retval(), (py_i64)(x * factor + offset) / factor); py_newfloat(py_retval(), (py_i64)(x * factor + offset) / factor);
return true; return true;
} }

View File

@ -1,40 +1,40 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include <math.h>
// https://bottosson.github.io/posts/gamutclipping/#oklab-to-linear-srgb-conversion // https://bottosson.github.io/posts/gamutclipping/#oklab-to-linear-srgb-conversion
// clang-format off // clang-format off
static c11_vec3 linear_srgb_to_oklab(c11_vec3 c) static c11_vec3 linear_srgb_to_oklab(c11_vec3 c)
{ {
double l = 0.4122214708 * c.x + 0.5363325363 * c.y + 0.0514459929 * c.z; float l = 0.4122214708f * c.x + 0.5363325363f * c.y + 0.0514459929f * c.z;
double m = 0.2119034982 * c.x + 0.6806995451 * c.y + 0.1073969566 * c.z; float m = 0.2119034982f * c.x + 0.6806995451f * c.y + 0.1073969566f * c.z;
double s = 0.0883024619 * c.x + 0.2817188376 * c.y + 0.6299787005 * c.z; float s = 0.0883024619f * c.x + 0.2817188376f * c.y + 0.6299787005f * c.z;
double l_ = dmath_cbrt(l); float l_ = cbrtf(l);
double m_ = dmath_cbrt(m); float m_ = cbrtf(m);
double s_ = dmath_cbrt(s); float s_ = cbrtf(s);
return (c11_vec3){{ return (c11_vec3){{
0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, 0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_,
1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, 1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_,
0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, 0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_,
}}; }};
} }
static c11_vec3 oklab_to_linear_srgb(c11_vec3 c) static c11_vec3 oklab_to_linear_srgb(c11_vec3 c)
{ {
double l_ = c.x + 0.3963377774 * c.y + 0.2158037573 * c.z; float l_ = c.x + 0.3963377774f * c.y + 0.2158037573f * c.z;
double m_ = c.x - 0.1055613458 * c.y - 0.0638541728 * c.z; float m_ = c.x - 0.1055613458f * c.y - 0.0638541728f * c.z;
double s_ = c.x - 0.0894841775 * c.y - 1.2914855480 * c.z; float s_ = c.x - 0.0894841775f * c.y - 1.2914855480f * c.z;
double l = l_ * l_ * l_; float l = l_ * l_ * l_;
double m = m_ * m_ * m_; float m = m_ * m_ * m_;
double s = s_ * s_ * s_; float s = s_ * s_ * s_;
return (c11_vec3){{ return (c11_vec3){{
+4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s, +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s,
@ -45,12 +45,12 @@ static c11_vec3 oklab_to_linear_srgb(c11_vec3 c)
// clang-format on // clang-format on
static double _gamma_correct_inv(double x) { static float _gamma_correct_inv(float x) {
return (x <= 0.04045) ? (x / 12.92) : dmath_pow((x + 0.055) / 1.055, 2.4); return (x <= 0.04045f) ? (x / 12.92f) : powf((x + 0.055f) / 1.055f, 2.4f);
} }
static double _gamma_correct(double x) { static float _gamma_correct(float x) {
return (x <= 0.0031308) ? (12.92 * x) : (1.055 * dmath_pow(x, 1.0 / 2.4) - 0.055); return (x <= 0.0031308f) ? (12.92f * x) : (1.055f * powf(x, 1.0f / 2.4f) - 0.055f);
} }
static c11_vec3 srgb_to_linear_srgb(c11_vec3 c) { static c11_vec3 srgb_to_linear_srgb(c11_vec3 c) {
@ -70,17 +70,17 @@ static c11_vec3 linear_srgb_to_srgb(c11_vec3 c) {
static c11_vec3 _oklab_to_oklch(c11_vec3 c) { static c11_vec3 _oklab_to_oklch(c11_vec3 c) {
c11_vec3 res; c11_vec3 res;
res.x = c.x; res.x = c.x;
res.y = dmath_sqrt(c.y * c.y + c.z * c.z); res.y = sqrtf(c.y * c.y + c.z * c.z);
res.z = dmath_fmod(dmath_atan2(c.z, c.y), 2 * DMATH_PI); res.z = fmodf(atan2f(c.z, c.y), 2 * (float)PK_M_PI);
res.z = res.z * DMATH_RAD2DEG; res.z = res.z * PK_M_RAD2DEG;
return res; return res;
} }
static c11_vec3 _oklch_to_oklab(c11_vec3 c) { static c11_vec3 _oklch_to_oklab(c11_vec3 c) {
c11_vec3 res; c11_vec3 res;
res.x = c.x; res.x = c.x;
res.y = c.y * dmath_cos(c.z * DMATH_DEG2RAD); res.y = c.y * cosf(c.z * PK_M_DEG2RAD);
res.z = c.y * dmath_sin(c.z * DMATH_DEG2RAD); res.z = c.y * sinf(c.z * PK_M_DEG2RAD);
return res; return res;
} }
@ -105,9 +105,9 @@ static c11_vec3 oklch_to_linear_srgb(c11_vec3 c) {
// fall back to RGB clamping // fall back to RGB clamping
candidate = oklab_to_linear_srgb(_oklch_to_oklab(clamped)); candidate = oklab_to_linear_srgb(_oklch_to_oklab(clamped));
if(!_is_valid_srgb(candidate)) { if(!_is_valid_srgb(candidate)) {
candidate.x = dmath_fmax(0.0, dmath_fmin(1.0, candidate.x)); candidate.x = fmaxf(0.0f, fminf(1.0f, candidate.x));
candidate.y = dmath_fmax(0.0, dmath_fmin(1.0, candidate.y)); candidate.y = fmaxf(0.0f, fminf(1.0f, candidate.y));
candidate.z = dmath_fmax(0.0, dmath_fmin(1.0, candidate.z)); candidate.z = fmaxf(0.0f, fminf(1.0f, candidate.z));
return candidate; return candidate;
} }
@ -116,7 +116,7 @@ static c11_vec3 oklch_to_linear_srgb(c11_vec3 c) {
float start = 0.0f; float start = 0.0f;
float end = c.y; float end = c.y;
float range[2] = {0.0f, 0.4f}; float range[2] = {0.0f, 0.4f};
float resolution = (range[1] - range[0]) / dmath_pow(2, 13); float resolution = (range[1] - range[0]) / powf(2, 13);
float _last_good_c = clamped.y; float _last_good_c = clamped.y;
while(end - start > resolution) { while(end - start > resolution) {
@ -142,8 +142,8 @@ static c11_vec3 srgb_to_hsv(c11_vec3 c) {
float g = c.y; float g = c.y;
float b = c.z; float b = c.z;
float maxc = dmath_fmax(r, dmath_fmax(g, b)); float maxc = fmaxf(r, fmaxf(g, b));
float minc = dmath_fmin(r, dmath_fmin(g, b)); float minc = fminf(r, fminf(g, b));
float v = maxc; float v = maxc;
if(minc == maxc) { if(minc == maxc) {
return (c11_vec3){ return (c11_vec3){
@ -163,7 +163,7 @@ static c11_vec3 srgb_to_hsv(c11_vec3 c) {
} else { } else {
h = 4.0f + gc - rc; h = 4.0f + gc - rc;
} }
h = dmath_fmod(h / 6.0, 1.0); h = fmodf(h / 6.0f, 1.0f);
return (c11_vec3){ return (c11_vec3){
{h, s, v} {h, s, v}
}; };

View File

@ -1,69 +1,71 @@
#include "pocketpy/common/dmath.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/interpreter/vm.h"
#include <math.h>
// https://easings.net/ // https://easings.net/
const double kPi = DMATH_PI; const double kPi = 3.1415926545;
static double easeLinear(double x) { return x; } static double easeLinear(double x) { return x; }
static double easeInSine(double x) { return 1.0 - dmath_cos(x * kPi / 2); } static double easeInSine(double x) { return 1.0 - cos(x * kPi / 2); }
static double easeOutSine(double x) { return dmath_sin(x * kPi / 2); } static double easeOutSine(double x) { return sin(x * kPi / 2); }
static double easeInOutSine(double x) { return -(dmath_cos(kPi * x) - 1) / 2; } static double easeInOutSine(double x) { return -(cos(kPi * x) - 1) / 2; }
static double easeInQuad(double x) { return x * x; } static double easeInQuad(double x) { return x * x; }
static double easeOutQuad(double x) { return 1 - dmath_pow(1 - x, 2); } static double easeOutQuad(double x) { return 1 - pow(1 - x, 2); }
static double easeInOutQuad(double x) { static double easeInOutQuad(double x) {
if(x < 0.5) { if(x < 0.5) {
return 2 * x * x; return 2 * x * x;
} else { } else {
return 1 - dmath_pow(-2 * x + 2, 2) / 2; return 1 - pow(-2 * x + 2, 2) / 2;
} }
} }
static double easeInCubic(double x) { return x * x * x; } static double easeInCubic(double x) { return x * x * x; }
static double easeOutCubic(double x) { return 1 - dmath_pow(1 - x, 3); } static double easeOutCubic(double x) { return 1 - pow(1 - x, 3); }
static double easeInOutCubic(double x) { static double easeInOutCubic(double x) {
if(x < 0.5) { if(x < 0.5) {
return 4 * x * x * x; return 4 * x * x * x;
} else { } else {
return 1 - dmath_pow(-2 * x + 2, 3) / 2; return 1 - pow(-2 * x + 2, 3) / 2;
} }
} }
static double easeInQuart(double x) { return dmath_pow(x, 4); } static double easeInQuart(double x) { return pow(x, 4); }
static double easeOutQuart(double x) { return 1 - dmath_pow(1 - x, 4); } static double easeOutQuart(double x) { return 1 - pow(1 - x, 4); }
static double easeInOutQuart(double x) { static double easeInOutQuart(double x) {
if(x < 0.5) { if(x < 0.5) {
return 8 * dmath_pow(x, 4); return 8 * pow(x, 4);
} else { } else {
return 1 - dmath_pow(-2 * x + 2, 4) / 2; return 1 - pow(-2 * x + 2, 4) / 2;
} }
} }
static double easeInQuint(double x) { return dmath_pow(x, 5); } static double easeInQuint(double x) { return pow(x, 5); }
static double easeOutQuint(double x) { return 1 - dmath_pow(1 - x, 5); } static double easeOutQuint(double x) { return 1 - pow(1 - x, 5); }
static double easeInOutQuint(double x) { static double easeInOutQuint(double x) {
if(x < 0.5) { if(x < 0.5) {
return 16 * dmath_pow(x, 5); return 16 * pow(x, 5);
} else { } else {
return 1 - dmath_pow(-2 * x + 2, 5) / 2; return 1 - pow(-2 * x + 2, 5) / 2;
} }
} }
static double easeInExpo(double x) { return x == 0 ? 0 : dmath_pow(2, 10 * x - 10); } static double easeInExpo(double x) { return x == 0 ? 0 : pow(2, 10 * x - 10); }
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - dmath_pow(2, -10 * x); } static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - pow(2, -10 * x); }
static double easeInOutExpo(double x) { static double easeInOutExpo(double x) {
if(x == 0) { if(x == 0) {
@ -71,21 +73,21 @@ static double easeInOutExpo(double x) {
} else if(x == 1) { } else if(x == 1) {
return 1; return 1;
} else if(x < 0.5) { } else if(x < 0.5) {
return dmath_pow(2, 20 * x - 10) / 2; return pow(2, 20 * x - 10) / 2;
} else { } else {
return (2 - dmath_pow(2, -20 * x + 10)) / 2; return (2 - pow(2, -20 * x + 10)) / 2;
} }
} }
static double easeInCirc(double x) { return 1 - dmath_sqrt(1 - dmath_pow(x, 2)); } static double easeInCirc(double x) { return 1 - sqrt(1 - pow(x, 2)); }
static double easeOutCirc(double x) { return dmath_sqrt(1 - dmath_pow(x - 1, 2)); } static double easeOutCirc(double x) { return sqrt(1 - pow(x - 1, 2)); }
static double easeInOutCirc(double x) { static double easeInOutCirc(double x) {
if(x < 0.5) { if(x < 0.5) {
return (1 - dmath_sqrt(1 - dmath_pow(2 * x, 2))) / 2; return (1 - sqrt(1 - pow(2 * x, 2))) / 2;
} else { } else {
return (dmath_sqrt(1 - dmath_pow(-2 * x + 2, 2)) + 1) / 2; return (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2;
} }
} }
@ -98,16 +100,16 @@ static double easeInBack(double x) {
static double easeOutBack(double x) { static double easeOutBack(double x) {
const double c1 = 1.70158; const double c1 = 1.70158;
const double c3 = c1 + 1; const double c3 = c1 + 1;
return 1 + c3 * dmath_pow(x - 1, 3) + c1 * dmath_pow(x - 1, 2); return 1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2);
} }
static double easeInOutBack(double x) { static double easeInOutBack(double x) {
const double c1 = 1.70158; const double c1 = 1.70158;
const double c2 = c1 * 1.525; const double c2 = c1 * 1.525;
if(x < 0.5) { if(x < 0.5) {
return (dmath_pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2; return (pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
} else { } else {
return (dmath_pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2; return (pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
} }
} }
@ -118,7 +120,7 @@ static double easeInElastic(double x) {
} else if(x == 1) { } else if(x == 1) {
return 1; return 1;
} else { } else {
return -dmath_pow(2, 10 * x - 10) * dmath_sin((x * 10 - 10.75) * c4); return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4);
} }
} }
@ -129,7 +131,7 @@ static double easeOutElastic(double x) {
} else if(x == 1) { } else if(x == 1) {
return 1; return 1;
} else { } else {
return dmath_pow(2, -10 * x) * dmath_sin((x * 10 - 0.75) * c4) + 1; return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1;
} }
} }
@ -140,9 +142,9 @@ static double easeInOutElastic(double x) {
} else if(x == 1) { } else if(x == 1) {
return 1; return 1;
} else if(x < 0.5) { } else if(x < 0.5) {
return -(dmath_pow(2, 20 * x - 10) * dmath_sin((20 * x - 11.125) * c5)) / 2; return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2;
} else { } else {
return (dmath_pow(2, -20 * x + 10) * dmath_sin((20 * x - 11.125) * c5)) / 2 + 1; return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c5)) / 2 + 1;
} }
} }

View File

@ -1,10 +1,10 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include <math.h>
static bool json_loads(int argc, py_Ref argv) { static bool json_loads(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
@ -27,9 +27,9 @@ void pk__add_module_json() {
py_setdict(mod, py_name("true"), py_True()); py_setdict(mod, py_name("true"), py_True());
py_setdict(mod, py_name("false"), py_False()); py_setdict(mod, py_name("false"), py_False());
py_TValue tmp; py_TValue tmp;
py_newfloat(&tmp, DMATH_NAN); py_newfloat(&tmp, NAN);
py_setdict(mod, py_name("NaN"), &tmp); py_setdict(mod, py_name("NaN"), &tmp);
py_newfloat(&tmp, DMATH_INFINITY); py_newfloat(&tmp, INFINITY);
py_setdict(mod, py_name("Infinity"), &tmp); py_setdict(mod, py_name("Infinity"), &tmp);
py_bindfunc(mod, "loads", json_loads); py_bindfunc(mod, "loads", json_loads);
@ -104,9 +104,9 @@ static bool json__write_object(c11_sbuf* buf, py_TValue* obj, int indent, int de
case tp_NoneType: c11_sbuf__write_cstr(buf, "null"); return true; case tp_NoneType: c11_sbuf__write_cstr(buf, "null"); return true;
case tp_int: c11_sbuf__write_int(buf, obj->_i64); return true; case tp_int: c11_sbuf__write_int(buf, obj->_i64); return true;
case tp_float: { case tp_float: {
if(dmath_isnan(obj->_f64)) { if(isnan(obj->_f64)) {
c11_sbuf__write_cstr(buf, "NaN"); c11_sbuf__write_cstr(buf, "NaN");
} else if(dmath_isinf(obj->_f64)) { } else if(isinf(obj->_f64)) {
c11_sbuf__write_cstr(buf, obj->_f64 < 0 ? "-Infinity" : "Infinity"); c11_sbuf__write_cstr(buf, obj->_f64 < 0 ? "-Infinity" : "Infinity");
} else { } else {
c11_sbuf__write_f64(buf, obj->_f64, -1); c11_sbuf__write_f64(buf, obj->_f64, -1);

View File

@ -1,7 +1,13 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include <math.h>
#if PK_ENABLE_DETERMINISM
#ifndef _DMATH_H
#error "_DMATH_H not defined"
#endif
#endif
#define ONE_ARG_FUNC(name, func) \ #define ONE_ARG_FUNC(name, func) \
static bool math_##name(int argc, py_Ref argv) { \ static bool math_##name(int argc, py_Ref argv) { \
@ -31,10 +37,10 @@
return true; \ return true; \
} }
ONE_ARG_FUNC(ceil, dmath_ceil) ONE_ARG_FUNC(ceil, ceil)
ONE_ARG_FUNC(fabs, dmath_fabs) ONE_ARG_FUNC(fabs, fabs)
ONE_ARG_FUNC(floor, dmath_floor) ONE_ARG_FUNC(floor, floor)
ONE_ARG_FUNC(trunc, dmath_trunc) ONE_ARG_FUNC(trunc, trunc)
static bool math_fsum(int argc, py_Ref argv) { static bool math_fsum(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
@ -72,58 +78,58 @@ static bool math_gcd(int argc, py_Ref argv) {
return true; return true;
} }
ONE_ARG_BOOL_FUNC(isfinite, dmath_isfinite) ONE_ARG_BOOL_FUNC(isfinite, isfinite)
ONE_ARG_BOOL_FUNC(isinf, dmath_isinf) ONE_ARG_BOOL_FUNC(isinf, isinf)
ONE_ARG_BOOL_FUNC(isnan, dmath_isnan) ONE_ARG_BOOL_FUNC(isnan, isnan)
static bool math_isclose(int argc, py_Ref argv) { static bool math_isclose(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
double a, b; double a, b;
if(!py_castfloat(py_arg(0), &a)) return false; if(!py_castfloat(py_arg(0), &a)) return false;
if(!py_castfloat(py_arg(1), &b)) return false; if(!py_castfloat(py_arg(1), &b)) return false;
py_newbool(py_retval(), dmath_fabs(a - b) < 1e-9); py_newbool(py_retval(), fabs(a - b) < 1e-9);
return true; return true;
} }
ONE_ARG_FUNC(exp, dmath_exp) ONE_ARG_FUNC(exp, exp)
static bool math_log(int argc, py_Ref argv) { static bool math_log(int argc, py_Ref argv) {
double x; double x;
if(!py_castfloat(py_arg(0), &x)) return false; if(!py_castfloat(py_arg(0), &x)) return false;
if(argc == 1) { if(argc == 1) {
py_newfloat(py_retval(), dmath_log(x)); py_newfloat(py_retval(), log(x));
} else if(argc == 2) { } else if(argc == 2) {
double base; double base;
if(!py_castfloat(py_arg(1), &base)) return false; if(!py_castfloat(py_arg(1), &base)) return false;
py_newfloat(py_retval(), dmath_log2(x) / dmath_log2(base)); py_newfloat(py_retval(), log(x) / log(base));
} else { } else {
return TypeError("log() takes 1 or 2 arguments"); return TypeError("log() takes 1 or 2 arguments");
} }
return true; return true;
} }
ONE_ARG_FUNC(log2, dmath_log2) ONE_ARG_FUNC(log2, log2)
ONE_ARG_FUNC(log10, dmath_log10) ONE_ARG_FUNC(log10, log10)
TWO_ARG_FUNC(pow, dmath_pow) TWO_ARG_FUNC(pow, pow)
ONE_ARG_FUNC(sqrt, dmath_sqrt) ONE_ARG_FUNC(sqrt, sqrt)
ONE_ARG_FUNC(acos, dmath_acos) ONE_ARG_FUNC(acos, acos)
ONE_ARG_FUNC(asin, dmath_asin) ONE_ARG_FUNC(asin, asin)
ONE_ARG_FUNC(atan, dmath_atan) ONE_ARG_FUNC(atan, atan)
ONE_ARG_FUNC(cos, dmath_cos) ONE_ARG_FUNC(cos, cos)
ONE_ARG_FUNC(sin, dmath_sin) ONE_ARG_FUNC(sin, sin)
ONE_ARG_FUNC(tan, dmath_tan) ONE_ARG_FUNC(tan, tan)
TWO_ARG_FUNC(atan2, dmath_atan2) TWO_ARG_FUNC(atan2, atan2)
static bool math_degrees(int argc, py_Ref argv) { static bool math_degrees(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
double x; double x;
if(!py_castfloat(py_arg(0), &x)) return false; if(!py_castfloat(py_arg(0), &x)) return false;
py_newfloat(py_retval(), x * DMATH_RAD2DEG); py_newfloat(py_retval(), x * PK_M_RAD2DEG);
return true; return true;
} }
@ -131,17 +137,17 @@ static bool math_radians(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
double x; double x;
if(!py_castfloat(py_arg(0), &x)) return false; if(!py_castfloat(py_arg(0), &x)) return false;
py_newfloat(py_retval(), x * DMATH_DEG2RAD); py_newfloat(py_retval(), x * PK_M_DEG2RAD);
return true; return true;
} }
TWO_ARG_FUNC(fmod, dmath_fmod) TWO_ARG_FUNC(fmod, fmod)
TWO_ARG_FUNC(copysign, dmath_copysign) TWO_ARG_FUNC(copysign, copysign)
static bool math_modf(int argc, py_Ref argv) { static bool math_modf(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
double i; double i;
double f = dmath_modf(py_tofloat(py_arg(0)), &i); double f = modf(py_tofloat(py_arg(0)), &i);
py_Ref p = py_newtuple(py_retval(), 2); py_Ref p = py_newtuple(py_retval(), 2);
py_newfloat(&p[0], f); py_newfloat(&p[0], f);
py_newfloat(&p[1], i); py_newfloat(&p[1], i);
@ -163,10 +169,10 @@ static bool math_factorial(int argc, py_Ref argv) {
void pk__add_module_math() { void pk__add_module_math() {
py_Ref mod = py_newmodule("math"); py_Ref mod = py_newmodule("math");
py_newfloat(py_emplacedict(mod, py_name("pi")), DMATH_PI); py_newfloat(py_emplacedict(mod, py_name("pi")), PK_M_PI);
py_newfloat(py_emplacedict(mod, py_name("e")), DMATH_E); py_newfloat(py_emplacedict(mod, py_name("e")), PK_M_E);
py_newfloat(py_emplacedict(mod, py_name("inf")), DMATH_INFINITY); py_newfloat(py_emplacedict(mod, py_name("inf")), INFINITY);
py_newfloat(py_emplacedict(mod, py_name("nan")), DMATH_NAN); py_newfloat(py_emplacedict(mod, py_name("nan")), NAN);
py_bindfunc(mod, "ceil", math_ceil); py_bindfunc(mod, "ceil", math_ceil);
py_bindfunc(mod, "fabs", math_fabs); py_bindfunc(mod, "fabs", math_fabs);

View File

@ -3,10 +3,10 @@
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/common/dmath.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include <math.h>
static bool isclose(float a, float b) { return dmath_fabs(a - b) < 1e-4; } static bool isclose(float a, float b) { return fabs(a - b) < 1e-4; }
#define DEFINE_VEC_FIELD(name, T, Tc, field) \ #define DEFINE_VEC_FIELD(name, T, Tc, field) \
static bool name##__##field(int argc, py_Ref argv) { \ static bool name##__##field(int argc, py_Ref argv) { \
@ -193,7 +193,7 @@ static py_Ref _const(py_Type type, const char* name) {
float sum = 0; \ float sum = 0; \
for(int i = 0; i < D; i++) \ for(int i = 0; i < D; i++) \
sum += v.data[i] * v.data[i]; \ sum += v.data[i] * v.data[i]; \
py_newfloat(py_retval(), dmath_sqrt(sum)); \ py_newfloat(py_retval(), sqrtf(sum)); \
return true; \ return true; \
} \ } \
static bool vec##D##_length_squared(int argc, py_Ref argv) { \ static bool vec##D##_length_squared(int argc, py_Ref argv) { \
@ -223,7 +223,7 @@ static py_Ref _const(py_Type type, const char* name) {
for(int i = 0; i < D; i++) \ for(int i = 0; i < D; i++) \
len += self.data[i] * self.data[i]; \ len += self.data[i] * self.data[i]; \
if(isclose(len, 0)) return ZeroDivisionError("cannot normalize zero vector"); \ if(isclose(len, 0)) return ZeroDivisionError("cannot normalize zero vector"); \
len = dmath_sqrt(len); \ len = sqrtf(len); \
c11_vec##D res; \ c11_vec##D res; \
for(int i = 0; i < D; i++) \ for(int i = 0; i < D; i++) \
res.data[i] = self.data[i] / len; \ res.data[i] = self.data[i] / len; \
@ -344,8 +344,8 @@ static bool vec2_rotate(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
py_f64 radians; py_f64 radians;
if(!py_castfloat(&argv[1], &radians)) return false; if(!py_castfloat(&argv[1], &radians)) return false;
double sr, cr; float cr = cosf(radians);
dmath_sincos(radians, &sr, &cr); float sr = sinf(radians);
c11_vec2 res; c11_vec2 res;
res.x = argv[0]._vec2.x * cr - argv[0]._vec2.y * sr; res.x = argv[0]._vec2.x * cr - argv[0]._vec2.y * sr;
res.y = argv[0]._vec2.x * sr + argv[0]._vec2.y * cr; res.y = argv[0]._vec2.x * sr + argv[0]._vec2.y * cr;
@ -357,9 +357,9 @@ static bool vec2_angle_STATIC(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(0, tp_vec2); PY_CHECK_ARG_TYPE(0, tp_vec2);
PY_CHECK_ARG_TYPE(1, tp_vec2); PY_CHECK_ARG_TYPE(1, tp_vec2);
float val = dmath_atan2(argv[1]._vec2.y, argv[1]._vec2.x) - dmath_atan2(argv[0]._vec2.y, argv[0]._vec2.x); float val = atan2f(argv[1]._vec2.y, argv[1]._vec2.x) - atan2f(argv[0]._vec2.y, argv[0]._vec2.x);
if(val > DMATH_PI) val -= 2 * (float)DMATH_PI; if(val > PK_M_PI) val -= 2 * (float)PK_M_PI;
if(val < -DMATH_PI) val += 2 * (float)DMATH_PI; if(val < -PK_M_PI) val += 2 * (float)PK_M_PI;
py_newfloat(py_retval(), val); py_newfloat(py_retval(), val);
return true; return true;
} }
@ -398,7 +398,7 @@ static bool vec2_smoothdamp_STATIC(int argc, py_Ref argv) {
float maxChangeSq = maxChange * maxChange; float maxChangeSq = maxChange * maxChange;
float sqDist = change_x * change_x + change_y * change_y; float sqDist = change_x * change_x + change_y * change_y;
if(sqDist > maxChangeSq) { if(sqDist > maxChangeSq) {
float mag = dmath_sqrt(sqDist); float mag = sqrtf(sqDist);
change_x = change_x / mag * maxChange; change_x = change_x / mag * maxChange;
change_y = change_y / mag * maxChange; change_y = change_y / mag * maxChange;
} }
@ -576,8 +576,8 @@ static bool inverse(const c11_mat3x3* m, c11_mat3x3* restrict out) {
} }
static void trs(c11_vec2 t, float r, c11_vec2 s, c11_mat3x3* restrict out) { static void trs(c11_vec2 t, float r, c11_vec2 s, c11_mat3x3* restrict out) {
double sr, cr; float cr = cosf(r);
dmath_sincos(r, &sr, &cr); float sr = sinf(r);
// clang-format off // clang-format off
*out = (c11_mat3x3){ *out = (c11_mat3x3){
._11 = s.x * cr, ._12 = -s.y * sr, ._13 = t.x, ._11 = s.x * cr, ._12 = -s.y * sr, ._13 = t.x,
@ -733,7 +733,7 @@ static bool mat3x3_t(int argc, py_Ref argv) {
static bool mat3x3_r(int argc, py_Ref argv) { static bool mat3x3_r(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
c11_mat3x3* ud = py_tomat3x3(argv); c11_mat3x3* ud = py_tomat3x3(argv);
float r = dmath_atan2(ud->_21, ud->_11); float r = atan2f(ud->_21, ud->_11);
py_newfloat(py_retval(), r); py_newfloat(py_retval(), r);
return true; return true;
} }
@ -742,8 +742,8 @@ static bool mat3x3_s(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
c11_mat3x3* ud = py_tomat3x3(argv); c11_mat3x3* ud = py_tomat3x3(argv);
c11_vec2 res; c11_vec2 res;
res.x = dmath_sqrt(ud->_11 * ud->_11 + ud->_21 * ud->_21); res.x = sqrtf(ud->_11 * ud->_11 + ud->_21 * ud->_21);
res.y = dmath_sqrt(ud->_12 * ud->_12 + ud->_22 * ud->_22); res.y = sqrtf(ud->_12 * ud->_12 + ud->_22 * ud->_22);
py_newvec2(py_retval(), res); py_newvec2(py_retval(), res);
return true; return true;
} }

View File

@ -124,7 +124,6 @@ assert isclose(math.sin(0), 0.0)
assert isclose(math.sin(math.pi / 2), 1.0) assert isclose(math.sin(math.pi / 2), 1.0)
assert isclose(math.sin(math.pi), 0.0) assert isclose(math.sin(math.pi), 0.0)
assert isclose(math.sin(-math.pi / 2), -1.0) assert isclose(math.sin(-math.pi / 2), -1.0)
assert isclose(math.sin(-math.pi / 4), -0.7071067811865476)
# cos - cosine # cos - cosine
assert isclose(math.cos(0), 1.0) assert isclose(math.cos(0), 1.0)

View File

@ -10,7 +10,7 @@ assert isclose(c1 - c2, complex(1, -0.5))
assert isclose(c1*4, complex(12, 16)) assert isclose(c1*4, complex(12, 16))
assert isclose(c1*c2, complex(-12, 21.5)) assert isclose(c1*c2, complex(-12, 21.5))
assert isclose(c2/c1, complex(0.96, 0.22)) assert isclose(c2/c1, complex(0.96, 0.22))
assert isclose(c2**2, complex(-16.25, 18)) assert isclose(c2**2, complex(-16.25, 17.99999999999999))
assert 1+2j == complex(1, 2) == 2j+1 assert 1+2j == complex(1, 2) == 2j+1

View File

@ -1,13 +1,12 @@
import easing import easing
def validate(k, f, x): def validate(val):
val = f(x) assert -2 <= val <= 2.0
assert (-2 <= val <= 2.0), (k, x, val) assert isinstance(val, float)
assert isinstance(val, float), (k, x, val)
for k, f in easing.__dict__.items(): for k, f in easing.__dict__.items():
if callable(f): if callable(f):
validate(k, f, 0.2) validate(f(0.2))
validate(k, f, 0.5) validate(f(0.5))
validate(k, f, 0.8) validate(f(0.8))
validate(k, f, 1.0) validate(f(1.0))

View File

@ -1,5 +1,3 @@
exit()
import colorcvt import colorcvt
from vmath import vec3 from vmath import vec3

View File

@ -8,7 +8,7 @@ if config["PK_ENABLE_DETERMINISM"] == 0:
def assertEqual(a, b): def assertEqual(a, b):
if a == b: if a == b:
return return
print(f'{a} != {b} ({a-b})') print(f'{a} != {b}')
raise AssertionError raise AssertionError
# test constants # test constants
@ -54,18 +54,18 @@ assertEqual(math.isnan(math.nan), True)
# test exp # test exp
assertEqual(math.exp(0), 1.0) assertEqual(math.exp(0), 1.0)
assertEqual(math.exp(1), math.e) assertEqual(math.exp(1), math.e)
assertEqual(math.exp(1.5), 4.48168907033806362960604019463) #4.481689070338065 - 8.881784197001252e-16) assertEqual(math.exp(1.5), 4.481689070338065 - 8.881784197001252e-16)
assertEqual(math.exp(3), 20.0855369231876608182574273087) #20.08553692318767 - 3.552713678800501e-15) assertEqual(math.exp(3), 20.08553692318767 - 3.552713678800501e-15)
assertEqual(math.exp(-3), 0.04978706836786396527916309651) #0.04978706836786394 + 6.938893903907228e-18) assertEqual(math.exp(-3), 0.04978706836786394 + 6.938893903907228e-18)
assertEqual(math.exp(-2.253647), 0.1050155336754953 - 1.387778780781446e-17) assertEqual(math.exp(-2.253647), 0.1050155336754953 - 1.387778780781446e-17)
assertEqual(math.exp(4.729036), 113.186398052200445363268954679) #113.1863980522005 - 4.263256414560601e-14) assertEqual(math.exp(4.729036), 113.1863980522005 - 4.263256414560601e-14)
# test log series # test log series
assertEqual(math.log(0), -math.inf) assertEqual(math.log(0), -math.inf)
assertEqual(math.log(1), 0.0) assertEqual(math.log(1), 0.0)
assertEqual(math.log(2), 0.69314718055994530942) assertEqual(math.log(2), 0.69314718055994530942)
assertEqual(math.log(math.e), 1.0) assertEqual(math.log(math.e), 1.0)
assertEqual(math.log(10), 2.30258509299404545700440394284) #2.30258509299404568402) assertEqual(math.log(10), 2.30258509299404568402)
assertEqual(math.log(28.897124), 3.363742074595449) assertEqual(math.log(28.897124), 3.363742074595449)
assertEqual(math.log2(math.e), 1.4426950408889634074) assertEqual(math.log2(math.e), 1.4426950408889634074)
assertEqual(math.log2(78.781291), 6.299781153677818) assertEqual(math.log2(78.781291), 6.299781153677818)
@ -77,13 +77,13 @@ assertEqual(math.pow(2,2), 4.0)
assertEqual(math.pow(1.41421356237309504880, 2), 2.0 + 4.440892098500626e-16) assertEqual(math.pow(1.41421356237309504880, 2), 2.0 + 4.440892098500626e-16)
assertEqual(math.pow(0.70710678118654752440, 2), 0.5000000000000001) assertEqual(math.pow(0.70710678118654752440, 2), 0.5000000000000001)
assertEqual(math.pow(-1.255782,-3), -0.5049603042167915) assertEqual(math.pow(-1.255782,-3), -0.5049603042167915)
assertEqual(math.pow(6.127042, 4.071529), 1604.40754645674428502388764172) #1604.407546456745 + 2.273736754432321e-13) assertEqual(math.pow(6.127042, 4.071529), 1604.407546456745 + 2.273736754432321e-13)
# test sqrt # test sqrt
assertEqual(math.sqrt(2), 1.41421356237309492343001693370) #1.41421356237309504880) assertEqual(math.sqrt(2), 1.41421356237309504880)
assertEqual(math.sqrt(math.pi), 1.772453850905516 - 2.220446049250313e-16) assertEqual(math.sqrt(math.pi), 1.772453850905516 - 2.220446049250313e-16)
assertEqual(math.sqrt(125.872509), 11.21929182257062) assertEqual(math.sqrt(125.872509), 11.21929182257062)
assertEqual(math.sqrt(1225.296280), 35.0042323155358019448613049462) #35.00423231553579) assertEqual(math.sqrt(1225.296280), 35.00423231553579)
# test cos, sin, tan # test cos, sin, tan
assertEqual(math.cos(0), 1.0) assertEqual(math.cos(0), 1.0)
@ -112,19 +112,19 @@ assertEqual(math.asin(1), 1.570796326794897 - 4.440892098500626e-16)
assertEqual(math.asin(-0.225895), -0.2278616865773913 + 2.775557561562891e-17) assertEqual(math.asin(-0.225895), -0.2278616865773913 + 2.775557561562891e-17)
assertEqual(math.asin(0.955658), 1.271886195819423 + 4.440892098500626e-16) assertEqual(math.asin(0.955658), 1.271886195819423 + 4.440892098500626e-16)
assertEqual(math.atan(0), 0.0) assertEqual(math.atan(0), 0.0)
assertEqual(math.atan(1), 0.78539816339744839002179332965) #0.7853981633974483) assertEqual(math.atan(1), 0.7853981633974483)
assertEqual(math.atan(-3.758927), -1.3107852846106160527028805518) #-1.310785284610617 - 4.440892098500626e-16) assertEqual(math.atan(-3.758927), -1.310785284610617 - 4.440892098500626e-16)
assertEqual(math.atan(35.789293), 1.54286227728011748894232368911) #1.542862277280122) assertEqual(math.atan(35.789293), 1.542862277280122)
# test atan2 # test atan2
assertEqual(math.atan2(math.pi/4, math.pi/4), 0.78539816339744839002179332965) #0.7853981633974483) assertEqual(math.atan2(math.pi/4, math.pi/4), 0.7853981633974483)
assertEqual(math.atan2(-math.pi/4, math.pi/4), -0.7853981633974483900217933296) #-0.7853981633974483) assertEqual(math.atan2(-math.pi/4, math.pi/4), -0.7853981633974483)
assertEqual(math.atan2(-math.pi/4, -math.pi/4), -2.356194490192345) assertEqual(math.atan2(-math.pi/4, -math.pi/4), -2.356194490192345)
assertEqual(math.atan2(math.pi/4, -math.pi/4), 2.356194490192345) assertEqual(math.atan2(math.pi/4, -math.pi/4), 2.356194490192345)
assertEqual(math.atan2(1.573823, 0.685329), 1.16010368292465315676054160576) #1.160103682924653) assertEqual(math.atan2(1.573823, 0.685329), 1.160103682924653)
assertEqual(math.atan2(-0.899663, 0.668972), -0.9314162757114096136135117376) #-0.9314162757114095) assertEqual(math.atan2(-0.899663, 0.668972), -0.9314162757114095)
assertEqual(math.atan2(-0.762894, -0.126497), -1.7351133471732969049128314509) #-1.735113347173296 - 4.440892098500626e-16) assertEqual(math.atan2(-0.762894, -0.126497), -1.735113347173296 - 4.440892098500626e-16)
assertEqual(math.atan2(0.468463, -0.992734), 2.70068341069237316531825854326) #2.700683410692374 - 4.440892098500626e-16) assertEqual(math.atan2(0.468463, -0.992734), 2.700683410692374 - 4.440892098500626e-16)
# test fsum, sum # test fsum, sum
fsum_sin = math.fsum([math.sin(i) for i in range(5000)]) fsum_sin = math.fsum([math.sin(i) for i in range(5000)])