Compare commits

..

17 Commits

Author SHA1 Message Date
BLUELOVETH
4b81a7af0e
Merge pull request #368 from PrimedErwin/determinism-math
add deterministic float test
2025-05-23 16:57:01 +08:00
PrimedErwin
3adf0509c0
Merge branch 'pocketpy:main' into determinism-math 2025-05-23 16:48:46 +08:00
blueloveTH
d528c4eb52 fix aarch64 2025-05-23 16:38:46 +08:00
PrimedErwin
0d40080d1f add random hard encoded test case 2025-05-23 16:24:30 +08:00
PrimedErwin
0f4acc1437
Merge branch 'pocketpy:main' into determinism-math 2025-05-23 15:20:33 +08:00
blueloveTH
6f4a5321a1 add pkpy.configmacros 2025-05-23 15:18:15 +08:00
PrimedErwin
205f11ebb1 add deterministic float test 2025-05-23 15:01:20 +08:00
blueloveTH
a0e721bd03 fix _DMATH_H 2025-05-23 13:46:31 +08:00
blueloveTH
b69b0787fa Update dmath 2025-05-23 13:41:02 +08:00
blueloveTH
0550f712f0 Update CMakeLists.txt 2025-05-23 13:39:35 +08:00
blueloveTH
1dabcd12db Update CMakeLists.txt 2025-05-23 13:37:56 +08:00
blueloveTH
1dc57b4c2d Update dmath 2025-05-23 13:34:55 +08:00
blueloveTH
cd08c4e022 Update CMakeLists.txt
Update CMakeLists.txt

Update CMakeLists.txt
2025-05-23 13:11:06 +08:00
blueloveTH
d28d86339d Revert "fix cmake"
This reverts commit 0a0d56770402b1e077c72c3fb76d0df52caf87d5.
2025-05-23 13:00:29 +08:00
blueloveTH
0a0d567704 fix cmake 2025-05-23 12:58:09 +08:00
blueloveTH
d424089e86 Update 70_math.py 2025-05-23 12:49:03 +08:00
blueloveTH
3c2d15abc2 add musl math library 2025-05-23 12:46:03 +08:00
12 changed files with 225 additions and 22 deletions

View File

@ -17,7 +17,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- uses: ilammy/msvc-dev-cmd@v1 - uses: ilammy/msvc-dev-cmd@v1
- name: Compile - name: Compile
shell: powershell shell: powershell
@ -30,7 +30,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- uses: ilammy/msvc-dev-cmd@v1 - uses: ilammy/msvc-dev-cmd@v1
- name: Compile - name: Compile
shell: bash shell: bash
@ -52,7 +52,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- name: Setup Clang - name: Setup Clang
uses: egor-tensin/setup-clang@v1 uses: egor-tensin/setup-clang@v1
with: with:
@ -87,7 +87,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- name: Compile and Test - name: Compile and Test
run: | run: |
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON
@ -101,7 +101,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- uses: nttld/setup-ndk@v1 - uses: nttld/setup-ndk@v1
id: setup-ndk id: setup-ndk
with: with:
@ -132,7 +132,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- name: Compile Frameworks - name: Compile Frameworks
run: | run: |
git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
@ -151,7 +151,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: recursive
- name: Setup Alpine Linux for ${{ matrix.arch }} - name: Setup Alpine Linux for ${{ matrix.arch }}
uses: jirutka/setup-alpine@v1 uses: jirutka/setup-alpine@v1
with: with:

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[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

1
3rd/dmath/dmath Submodule

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

View File

@ -20,10 +20,6 @@ if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
add_definitions(-DNDEBUG) add_definitions(-DNDEBUG)
endif() endif()
if(PK_ENABLE_DETERMINISM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Oi-")
endif()
else() else()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
@ -36,7 +32,7 @@ else()
endif() endif()
if(PK_ENABLE_DETERMINISM) if(PK_ENABLE_DETERMINISM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexcess-precision=standard -ffp-contract=off") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffp-contract=off")
endif() endif()
endif() endif()
@ -48,6 +44,12 @@ if(PK_ENABLE_OS)
add_definitions(-DPK_ENABLE_OS=1) add_definitions(-DPK_ENABLE_OS=1)
endif() endif()
if(PK_ENABLE_DETERMINISM)
add_subdirectory(3rd/dmath/dmath)
include_directories(BEFORE 3rd/dmath/dmath/include/public)
add_definitions(-DPK_ENABLE_DETERMINISM=1)
endif()
if(PK_ENABLE_WATCHDOG) if(PK_ENABLE_WATCHDOG)
add_definitions(-DPK_ENABLE_WATCHDOG=1) add_definitions(-DPK_ENABLE_WATCHDOG=1)
endif() endif()
@ -82,6 +84,14 @@ else()
target_link_libraries(main ${PROJECT_NAME}) target_link_libraries(main ${PROJECT_NAME})
endif() endif()
if(PK_ENABLE_DETERMINISM)
target_link_libraries(${PROJECT_NAME} dmath)
if(MSVC)
target_link_options(${PROJECT_NAME} PRIVATE /FORCE:MULTIPLE)
endif()
endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
if(NOT PK_ENABLE_DETERMINISM) if(NOT PK_ENABLE_DETERMINISM)
# use platform libm # use platform libm

View File

@ -7,7 +7,7 @@ endif()
# system features # system features
option(PK_ENABLE_OS "" OFF) option(PK_ENABLE_OS "" OFF)
option(PK_ENABLE_DETERMINISM "" FALSE) option(PK_ENABLE_DETERMINISM "" OFF)
option(PK_ENABLE_WATCHDOG "" OFF) option(PK_ENABLE_WATCHDOG "" OFF)
# modules # modules

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_OS=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}") code = os.system(f"cmake .. -DPK_ENABLE_OS=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

View File

@ -12,6 +12,10 @@
#define PK_ENABLE_OS 1 #define PK_ENABLE_OS 1
#endif #endif
#ifndef PK_ENABLE_DETERMINISM // must be enabled from cmake
#define PK_ENABLE_DETERMINISM 0
#endif
#ifndef PK_ENABLE_WATCHDOG // can be overridden by cmake #ifndef PK_ENABLE_WATCHDOG // can be overridden by cmake
#define PK_ENABLE_WATCHDOG 0 #define PK_ENABLE_WATCHDOG 0
#endif #endif

View File

@ -11,6 +11,8 @@ class TValue[T]:
# TValue_float = TValue[float] # TValue_float = TValue[float]
# TValue_vec2i = TValue[vec2i] # TValue_vec2i = TValue[vec2i]
# TValue_vec2 = TValue[vec2] # TValue_vec2 = TValue[vec2]
configmacros: dict[str, int]
def memory_usage() -> str: def memory_usage() -> str:
"""Return a summary of the memory usage.""" """Return a summary of the memory usage."""

View File

@ -7,6 +7,12 @@
#include <math.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) { \
PY_CHECK_ARGC(1); \ PY_CHECK_ARGC(1); \

View File

@ -454,6 +454,13 @@ static void pk_ComputeThread__register(py_Ref mod) {
py_bindmethod(type, "eval", ComputeThread_eval); py_bindmethod(type, "eval", ComputeThread_eval);
} }
static void pkpy_configmacros_add(py_Ref dict, const char* key, int val){
assert(dict->type == tp_dict);
py_TValue tmp;
py_newint(&tmp, val);
py_dict_setitem_by_str(dict, key, &tmp);
}
void pk__add_module_pkpy() { void pk__add_module_pkpy() {
py_Ref mod = py_newmodule("pkpy"); py_Ref mod = py_newmodule("pkpy");
@ -500,6 +507,14 @@ void pk__add_module_pkpy() {
#endif #endif
pk_ComputeThread__register(mod); pk_ComputeThread__register(mod);
py_Ref configmacros = py_emplacedict(mod, py_name("configmacros"));
py_newdict(configmacros);
pkpy_configmacros_add(configmacros, "PK_ENABLE_OS", PK_ENABLE_OS);
pkpy_configmacros_add(configmacros, "PK_ENABLE_DETERMINISM", PK_ENABLE_DETERMINISM);
pkpy_configmacros_add(configmacros, "PK_ENABLE_WATCHDOG", PK_ENABLE_WATCHDOG);
pkpy_configmacros_add(configmacros, "PK_GC_MIN_THRESHOLD", PK_GC_MIN_THRESHOLD);
pkpy_configmacros_add(configmacros, "PK_VM_STACK_SIZE", PK_VM_STACK_SIZE);
} }
#undef DEF_TVALUE_METHODS #undef DEF_TVALUE_METHODS

View File

@ -3,14 +3,14 @@ from math import log, log10, log2, sin, cos, tan, e, pi, isnan, isinf, fabs, flo
def isclose(a, b): def isclose(a, b):
return abs(a-b) < 0.000001 return abs(a-b) < 0.000001
assert isclose(e, 2.718281828459045) assert isclose(e, 2.718281828459045), e
assert isclose(pi, 3.141592653589793) assert isclose(pi, 3.141592653589793), pi
assert isclose(log(10), 2.302585092994046) assert isclose(log(10), 2.302585092994046), log(10)
assert isclose(log10(10), 1.0) assert isclose(log10(10), 1.0), log10(10)
assert isclose(log2(10), 3.321928094887362) assert isclose(log2(10), 3.321928094887362), log2(10)
assert isclose(sin(0), 0.0) assert isclose(sin(0), 0.0), sin(0)
assert isclose(cos(0), 1.0) assert isclose(cos(0), 1.0), cos(0)
assert isclose(tan(0), 0.0) assert isclose(tan(0), 0.0), tan(0)
a = -0.1 a = -0.1
a = a**a a = a**a

View File

@ -0,0 +1,162 @@
import math
import pkpy
config = pkpy.configmacros
if config["PK_ENABLE_DETERMINISM"] == 0:
exit(0)
def assertEqual(a, b):
if a == b:
return
print(f'{a} != {b}')
raise AssertionError
# test constants
assertEqual(math.pi, 3.14159265358979323846)
assertEqual(math.e, 2.7182818284590452354)
assert math.inf, math.inf
assert math.nan != math.nan
# test ceil
assertEqual(math.ceil(math.pi), 4.0)
assertEqual(math.ceil(-math.e), -2.0)
assertEqual(math.ceil(math.inf), math.inf)
# test floor
assertEqual(math.floor(math.pi), 3.0)
assertEqual(math.floor(-math.e), -3.0)
# test trunc
assertEqual(math.trunc(math.pi), 3.0)
# test fabs
assertEqual(math.fabs(math.pi), 3.14159265358979323846)
assertEqual(math.fabs(-math.pi), 3.14159265358979323846)
# test gcd
assertEqual(math.gcd(10, 5), 5)
assertEqual(math.gcd(10, 6), 2)
assertEqual(math.gcd(10, 7), 1)
assertEqual(math.gcd(10, 10), 10)
assertEqual(math.gcd(-10, 10), 10)
# test isfinite, isinf, isnan
assertEqual(math.isfinite(math.pi), 1)
assertEqual(math.isfinite(math.inf), 0)
assertEqual(math.isfinite(math.nan), 0)
assertEqual(math.isinf(math.pi), 0)
assertEqual(math.isinf(math.inf), 1)
assertEqual(math.isinf(math.nan), 0)
assertEqual(math.isnan(math.pi), 0)
assertEqual(math.isnan(math.inf), 0)
assertEqual(math.isnan(math.nan), 1)
# test exp
assertEqual(math.exp(0), 1.0)
assertEqual(math.exp(1), math.e)
assertEqual(math.exp(1.5), 4.481689070338065 - 8.881784197001252e-16)
assertEqual(math.exp(3), 20.08553692318767 - 3.552713678800501e-15)
assertEqual(math.exp(-3), 0.04978706836786394 + 6.938893903907228e-18)
assertEqual(math.exp(-2.253647), 0.1050155336754953 - 1.387778780781446e-17)
assertEqual(math.exp(4.729036), 113.1863980522005 - 4.263256414560601e-14)
# test log series
assertEqual(math.log(0), -math.inf)
assertEqual(math.log(1), 0.0)
assertEqual(math.log(2), 0.69314718055994530942)
assertEqual(math.log(math.e), 1.0)
assertEqual(math.log(10), 2.30258509299404568402)
assertEqual(math.log(28.897124), 3.363742074595449)
assertEqual(math.log2(math.e), 1.4426950408889634074)
assertEqual(math.log2(78.781291), 6.299781153677818)
assertEqual(math.log10(math.e), 0.43429448190325182765)
assertEqual(math.log10(56.907822), 1.755171964426069 + 4.440892098500626e-16)
# test pow
assertEqual(math.pow(2,2), 4.0)
assertEqual(math.pow(1.41421356237309504880, 2), 2.0 + 4.440892098500626e-16)
assertEqual(math.pow(0.70710678118654752440, 2), 0.5000000000000001)
assertEqual(math.pow(-1.255782,-3), -0.5049603042167915)
assertEqual(math.pow(6.127042, 4.071529), 1604.407546456745 + 2.273736754432321e-13)
# test sqrt
assertEqual(math.sqrt(2), 1.41421356237309504880)
assertEqual(math.sqrt(math.pi), 1.772453850905516 - 2.220446049250313e-16)
assertEqual(math.sqrt(125.872509), 11.21929182257062)
assertEqual(math.sqrt(1225.296280), 35.00423231553579)
# test cos, sin, tan
assertEqual(math.cos(0), 1.0)
assertEqual(math.cos(math.pi/2), 6.123233995736766e-17)
assertEqual(math.cos(math.pi), -1.0)
assertEqual(math.cos(-11.352808), 0.3496839289707818 - 5.551115123125783e-17)
assertEqual(math.cos(7.294708), 0.530570640518482)
assertEqual(math.sin(0), 0.0)
assertEqual(math.sin(math.pi/2), 1.0)
assertEqual(math.sin(math.pi), 1.224646799147353e-16 + 2.465190328815662e-32)
assertEqual(math.sin(-2.837592), -0.2993398018896187)
assertEqual(math.sin(9.294782), 0.1296301374714747)
assertEqual(math.tan(0), 0.0)
assertEqual(math.tan(math.pi/2), 1.633123935319537e+16)
assertEqual(math.tan(math.pi), -1.224646799147353e-16 - 2.465190328815662e-32)
assertEqual(math.tan(-4.812975), 9.908188146466314)
assertEqual(math.tan(1.875814), -3.176189742032396 - 4.440892098500626e-16)
# test acos, asin, atan
assertEqual(math.acos(0), 1.570796326794897 - 4.440892098500626e-16)
assertEqual(math.acos(1), 0.0)
assertEqual(math.acos(-0.758293), 2.431486995121896 + 4.440892098500626e-16)
assertEqual(math.acos(0.024758), 1.546035796825635)
assertEqual(math.asin(0), 0.0)
assertEqual(math.asin(1), 1.570796326794897 - 4.440892098500626e-16)
assertEqual(math.asin(-0.225895), -0.2278616865773913 + 2.775557561562891e-17)
assertEqual(math.asin(0.955658), 1.271886195819423 + 4.440892098500626e-16)
assertEqual(math.atan(0), 0.0)
assertEqual(math.atan(1), 0.7853981633974483)
assertEqual(math.atan(-3.758927), -1.310785284610617 - 4.440892098500626e-16)
assertEqual(math.atan(35.789293), 1.542862277280122)
# test atan2
assertEqual(math.atan2(math.pi/4, math.pi/4), 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(1.573823, 0.685329), 1.160103682924653)
assertEqual(math.atan2(-0.899663, 0.668972), -0.9314162757114095)
assertEqual(math.atan2(-0.762894, -0.126497), -1.735113347173296 - 4.440892098500626e-16)
assertEqual(math.atan2(0.468463, -0.992734), 2.700683410692374 - 4.440892098500626e-16)
# test fsum, sum
fsum_sin = math.fsum([math.sin(i) for i in range(5000)])
fsum_cos = math.fsum([math.cos(i) for i in range(5000, 9999)])
assertEqual(fsum_sin, 1.267667771014267 + 2.220446049250313e-16)
assertEqual(fsum_cos, 1.949547793618193 - 4.440892098500626e-16)
assertEqual(fsum_sin + fsum_cos, 3.21721556463246)
sum_sin = sum([math.sin(i) for i in range(5000)])
sum_cos = sum([math.cos(i) for i in range(5000, 9999)])
assertEqual(sum_sin, 1.267667771014264 - 2.220446049250313e-16)
assertEqual(sum_cos, 1.949547793618197 - 4.440892098500626e-16)
assertEqual(sum_sin + sum_cos, 3.21721556463246 + 4.440892098500626e-16)
# test fmod
assertEqual(math.fmod(-2.0, 3.0), -2.0)
assertEqual(math.fmod(2.0, 3.0), 2.0)
assertEqual(math.fmod(4.0, 3.0), 1.0)
assertEqual(math.fmod(-4.0, 3.0), -1.0)
# test modf
x, y = math.modf(math.pi)
assertEqual(x, 0.14159265358979323846 - 1.110223024625157e-16)
assertEqual(y, 3.0)
x, y = math.modf(-math.e)
assertEqual(x, -0.7182818284590451)
assertEqual(y, -2.0)
# test factorial
assertEqual(math.factorial(0), 1)
assertEqual(math.factorial(1), 1)
assertEqual(math.factorial(2), 2)
assertEqual(math.factorial(3), 6)
assertEqual(math.factorial(4), 24)
assertEqual(math.factorial(5), 120)