Compare commits

...

8 Commits

Author SHA1 Message Date
Tesselmax Opensource
0b4144db63
Merge 46cc281099bfad78ee697e700330314307235695 into 7fd7e2db152c12e5ada1c3e8222d55ecf8b983cb 2026-07-21 13:35:08 -07:00
Md Kaif
7fd7e2db15
fix(float): abs(-0.0) should return 0.0 (#534)
abs(-0.0) returns -0.0 instead of 0.0, and math.fabs(-0.0) does the
same. Both come from the idiom (x < 0) ? -x : x. Since -0.0 < 0 is
false, the negative zero is returned unchanged.

The idiom appears twice, once in dmath_fabs and once open-coded in
float__abs__. Fix dmath_fabs by clearing the sign bit, the same way
dmath_copysign just above it works, and make float__abs__ call the
shared helper instead of repeating the comparison.

abs(-0.0) == 0.0 is true even with the bug, because -0.0 == 0.0 under
IEEE 754, so the added tests compare str(...) to check the sign.
2026-07-21 19:36:08 +08:00
Md Kaif
005550e92a
fix(str): zfill should preserve a leading sign (#533)
zfill writes the padding zeros before the whole string, so a leading
+ or - ends up in the middle of the result instead of staying in front.
For example "-5".zfill(4) gave '00-5' where CPython gives '-005'.

CPython inserts the padding after the sign character, and the sign
counts toward the requested width. Write the sign first, then the
zeros, then the rest of the string. delta is still computed before
this, so the total length is unchanged.

The existing tests only covered unsigned strings, which is why this
went unnoticed. Added three asserts alongside them.
2026-07-21 19:09:11 +08:00
blueloveTH
f2b6d90a72 Update mpack1.h 2026-07-21 14:30:09 +08:00
blueloveTH
2ed21e8814 Update bindings.c 2026-07-21 14:27:31 +08:00
blueloveTH
08fce73bbb Update mpack1.h 2026-07-21 14:27:18 +08:00
blueloveTH
4fc4d665ec improve mpack 2026-07-21 14:09:27 +08:00
blueloveTH
4816c4471b Update bindings.c 2026-07-20 21:18:18 +08:00
8 changed files with 71 additions and 8 deletions

View File

@ -251,7 +251,7 @@
* types in @ref docs/protocol.md for more information.
*/
#ifndef MPACK_EXTENSIONS
#define MPACK_EXTENSIONS 0
#define MPACK_EXTENSIONS 1
#endif
/**

View File

@ -0,0 +1,20 @@
#pragma once
#include "mpack.h"
#include "pocketpy.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef bool (*is_mpack_ext_t)(py_Type type);
typedef bool (*py_to_mpack_ext_t)(py_Ref object, mpack_writer_t* writer);
typedef bool (*mpack_to_py_ext_t)(py_StackRef tmp, mpack_node_t node);
void mpack_config_exttype_callbacks(is_mpack_ext_t is_ext,
py_to_mpack_ext_t to_mpack,
mpack_to_py_ext_t to_py);
#ifdef __cplusplus
}
#endif

View File

@ -1,8 +1,22 @@
#include "pocketpy.h"
#include "mpack.h"
#include "mpack1.h"
#include <assert.h>
_Static_assert(MPACK_EXTENSIONS == 1, "You should change MPACK_EXTENSIONS in mpack.h to 1");
static is_mpack_ext_t is_mpack_ext;
static py_to_mpack_ext_t py_to_mpack_ext;
static mpack_to_py_ext_t mpack_to_py_ext;
void mpack_config_exttype_callbacks(is_mpack_ext_t is_ext,
py_to_mpack_ext_t to_mpack,
mpack_to_py_ext_t to_py) {
is_mpack_ext = is_ext;
py_to_mpack_ext = to_mpack;
mpack_to_py_ext = to_py;
}
static bool mpack_to_py(mpack_node_t node) {
py_StackRef tmp = py_pushtmp();
@ -69,6 +83,14 @@ static bool mpack_to_py(mpack_node_t node) {
}
break;
}
case mpack_type_ext: {
if(!mpack_to_py_ext) {
return RuntimeError("msgpack: mpack_to_py_ext is not set, cannot handle ext type");
}
if(!mpack_to_py_ext(tmp, node)) return false;
break;
}
default: return ValueError("msgpack: invalid node type");
}
return true;
@ -111,9 +133,7 @@ static bool mpack_write_dict_kv(py_Ref k, py_Ref v, void* ctx) {
} else {
return TypeError("msgpack: key must be string or integer");
}
bool ok = py_to_mpack(v, writer);
if(!ok) mpack_write_nil(writer);
return ok;
return py_to_mpack(v, writer);
}
static bool py_to_mpack(py_Ref object, mpack_writer_t* writer) {
@ -154,7 +174,15 @@ static bool py_to_mpack(py_Ref object, mpack_writer_t* writer) {
if(!ok) return false;
break;
}
default: return TypeError("msgpack: unsupported type '%t'", object->type);
default: {
if(is_mpack_ext && is_mpack_ext(object->type)) {
assert(py_to_mpack_ext != NULL);
return py_to_mpack_ext(object, writer);
break;
}
mpack_write_nil(writer);
return TypeError("msgpack: unsupported type '%t'", object->type);
}
}
return true;
}

View File

@ -384,7 +384,7 @@ static bool int__abs__(int argc, py_Ref argv) {
static bool float__abs__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_f64 val = py_tofloat(&argv[0]);
py_newfloat(py_retval(), val < 0 ? -val : val);
py_newfloat(py_retval(), dmath_fabs(val));
return true;
}

View File

@ -447,6 +447,12 @@ static bool str_zfill(int argc, py_Ref argv) {
}
c11_sbuf buf;
c11_sbuf__ctor(&buf);
// a leading sign is kept in front; the padding goes after it
if(self.size > 0 && (self.data[0] == '+' || self.data[0] == '-')) {
c11_sbuf__write_char(&buf, self.data[0]);
self.data++;
self.size--;
}
for(int i = 0; i < delta; i++) {
c11_sbuf__write_char(&buf, '0');
}

View File

@ -701,8 +701,11 @@ double dmath_copysign(double x, double y) {
return ux.f;
}
// https://github.com/kraj/musl/blob/kraj/master/src/math/fabs.c
double dmath_fabs(double x) {
return (x < 0) ? -x : x;
union Float64Bits u = { .f = x };
u.i &= -1ULL/2;
return u.f;
}
double dmath_ceil(double x) {

View File

@ -97,6 +97,9 @@ assert 3.4e+3 == 3400.0
assert abs(1.0) == 1.0
assert abs(-1.0) == 1.0
assert abs(0.0) == 0.0
# abs(-0.0) is 0.0, not -0.0. `==` cannot tell them apart, so check the sign.
assert str(abs(-0.0)) == '0.0'
assert str(abs(0.0)) == '0.0'
# import math
# assert math.isnan(0/0)

View File

@ -112,6 +112,9 @@ assert s2.join( seq ) == "runoob"
assert 'x'.zfill(5) == '0000x'
assert '568'.zfill(1) == '568'
assert '-5'.zfill(4) == '-005'
assert '+5'.zfill(4) == '+005'
assert '-'.zfill(3) == '-00'
num = 6
assert str(num) == '6'