mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
reimpl float
This commit is contained in:
parent
e86e7feafd
commit
7254c5a491
@ -76,10 +76,6 @@ struct NumberTraits<4> {
|
||||
|
||||
template<typename... Args>
|
||||
static float_t stof(Args&&... args) { return std::stof(std::forward<Args>(args)...); }
|
||||
|
||||
static constexpr int_t c0 = 0b00000000011111111111111111111100;
|
||||
static constexpr int_t c1 = 0b11111111111111111111111111111100;
|
||||
static constexpr int_t c2 = 0b00000000000000000000000000000011;
|
||||
};
|
||||
|
||||
template <>
|
||||
@ -89,18 +85,59 @@ struct NumberTraits<8> {
|
||||
|
||||
template<typename... Args>
|
||||
static float_t stof(Args&&... args) { return std::stod(std::forward<Args>(args)...); }
|
||||
|
||||
static constexpr int_t c0 = 0b0000000000001111111111111111111111111111111111111111111111111100;
|
||||
static constexpr int_t c1 = 0b1111111111111111111111111111111111111111111111111111111111111100;
|
||||
static constexpr int_t c2 = 0b0000000000000000000000000000000000000000000000000000000000000011;
|
||||
};
|
||||
|
||||
using Number = NumberTraits<sizeof(void*)>;
|
||||
using i64 = int64_t;
|
||||
using i64 = int64_t; // always 64-bit
|
||||
using f64 = Number::float_t;
|
||||
|
||||
template<size_t T>
|
||||
union BitsCvtImpl;
|
||||
|
||||
template<>
|
||||
union BitsCvtImpl<4>{
|
||||
NumberTraits<4>::int_t _int;
|
||||
NumberTraits<4>::float_t _float;
|
||||
|
||||
struct{
|
||||
unsigned int sign: 1;
|
||||
unsigned int exp: 8;
|
||||
uint64_t mantissa: 23;
|
||||
} _float_bits;
|
||||
|
||||
static constexpr int C0 = 127; // 2^7 - 1
|
||||
static constexpr int C1 = -62; // 2 - 2^6
|
||||
static constexpr int C2 = 63; // 2^6 - 1
|
||||
|
||||
BitsCvtImpl(NumberTraits<4>::float_t val): _float(val) {}
|
||||
BitsCvtImpl(NumberTraits<4>::int_t val): _int(val) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
union BitsCvtImpl<8>{
|
||||
NumberTraits<8>::int_t _int;
|
||||
NumberTraits<8>::float_t _float;
|
||||
|
||||
struct{
|
||||
unsigned int sign: 1;
|
||||
unsigned int exp: 11;
|
||||
uint64_t mantissa: 52;
|
||||
} _float_bits;
|
||||
|
||||
static constexpr int C0 = 1023; // 2^10 - 1
|
||||
static constexpr int C1 = -510; // 2 - 2^9
|
||||
static constexpr int C2 = 511; // 2^9 - 1
|
||||
|
||||
BitsCvtImpl(NumberTraits<8>::float_t val): _float(val) {}
|
||||
BitsCvtImpl(NumberTraits<8>::int_t val): _int(val) {}
|
||||
};
|
||||
|
||||
using BitsCvt = BitsCvtImpl<sizeof(void*)>;
|
||||
|
||||
static_assert(sizeof(i64) == 8);
|
||||
static_assert(sizeof(f64) == sizeof(void*));
|
||||
static_assert(sizeof(Number::float_t) == sizeof(void*));
|
||||
static_assert(sizeof(Number::int_t) == sizeof(void*));
|
||||
static_assert(sizeof(BitsCvt) == sizeof(void*));
|
||||
static_assert(std::numeric_limits<f64>::is_iec559);
|
||||
|
||||
struct Dummy { };
|
||||
@ -133,10 +170,33 @@ struct Type {
|
||||
struct PyObject;
|
||||
#define PK_BITS(p) (reinterpret_cast<Number::int_t>(p))
|
||||
|
||||
// special singals, is_tagged() for them is true
|
||||
inline PyObject* const PY_NULL = (PyObject*)0b000011; // tagged null
|
||||
inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
|
||||
inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
|
||||
inline PyObject* tag_float(f64 val){
|
||||
BitsCvt decomposed(val);
|
||||
unsigned int exp_7b = decomposed._float_bits.exp;
|
||||
if(exp_7b - BitsCvt::C0 < BitsCvt::C1){
|
||||
exp_7b = 0;
|
||||
decomposed._float_bits.mantissa = 0;
|
||||
}else if(exp_7b - BitsCvt::C0 > BitsCvt::C2){
|
||||
exp_7b = BitsCvt::C0;
|
||||
if(!std::isnan(val)) decomposed._float_bits.mantissa = 0;
|
||||
}
|
||||
decomposed._float_bits.exp = exp_7b - BitsCvt::C0 + BitsCvt::C2;
|
||||
decomposed._int = (decomposed._int << 1) | 0b01;
|
||||
return reinterpret_cast<PyObject*>(decomposed._int);
|
||||
}
|
||||
|
||||
inline f64 untag_float(PyObject* val){
|
||||
BitsCvt decomposed(reinterpret_cast<Number::int_t>(val));
|
||||
decomposed._int >>= 1;
|
||||
unsigned int exp_7b = decomposed._float_bits.exp;
|
||||
if(exp_7b == 0) return 0.0f;
|
||||
if(exp_7b == BitsCvt::C0){
|
||||
decomposed._float_bits.exp = -1;
|
||||
return decomposed._float;
|
||||
}
|
||||
decomposed._float_bits.exp = exp_7b - BitsCvt::C2 + BitsCvt::C0;
|
||||
return decomposed._float;
|
||||
}
|
||||
|
||||
// is_pod<> for c++17 and c++20
|
||||
template<typename T>
|
||||
|
@ -123,20 +123,29 @@ struct PyObject{
|
||||
}
|
||||
};
|
||||
|
||||
struct PySignalObject: PyObject {
|
||||
PySignalObject() : PyObject(0) {
|
||||
gc.enabled = false;
|
||||
}
|
||||
void _obj_gc_mark() override {}
|
||||
};
|
||||
|
||||
inline PyObject* const PY_NULL = new PySignalObject();
|
||||
inline PyObject* const PY_OP_CALL = new PySignalObject();
|
||||
inline PyObject* const PY_OP_YIELD = new PySignalObject();
|
||||
|
||||
const int kTpIntIndex = 2;
|
||||
const int kTpFloatIndex = 3;
|
||||
|
||||
inline bool is_tagged(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
|
||||
inline bool is_small_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b01; }
|
||||
inline bool is_small_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
|
||||
inline bool is_heap_int(PyObject* p) noexcept { return !is_tagged(p) && p->type.index == kTpIntIndex; }
|
||||
inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
|
||||
inline bool is_special(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b11; }
|
||||
inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 1) == 1; } // 01 or 11
|
||||
inline bool is_int(PyObject* p) noexcept { return is_small_int(p) || is_heap_int(p); }
|
||||
|
||||
inline bool is_type(PyObject* obj, Type type) {
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr");
|
||||
if(is_special(obj)) throw std::runtime_error("is_type() called with special object");
|
||||
#endif
|
||||
switch(type.index){
|
||||
case kTpIntIndex: return is_int(obj);
|
||||
@ -148,7 +157,6 @@ inline bool is_type(PyObject* obj, Type type) {
|
||||
inline bool is_non_tagged_type(PyObject* obj, Type type) {
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
if(obj == nullptr) throw std::runtime_error("is_non_tagged_type() called with nullptr");
|
||||
if(is_special(obj)) throw std::runtime_error("is_non_tagged_type() called with special object");
|
||||
#endif
|
||||
return !is_tagged(obj) && obj->type == type;
|
||||
}
|
||||
@ -200,13 +208,6 @@ Str obj_type_name(VM* vm, Type type);
|
||||
#define OBJ_NAME(obj) PK_OBJ_GET(Str, vm->getattr(obj, __name__))
|
||||
#endif
|
||||
|
||||
union BitsCvt {
|
||||
Number::int_t _int;
|
||||
f64 _float;
|
||||
BitsCvt(Number::int_t val) : _int(val) {}
|
||||
BitsCvt(f64 val) : _float(val) {}
|
||||
};
|
||||
|
||||
template <typename, typename=void> struct is_py_class : std::false_type {};
|
||||
template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
|
||||
|
||||
|
@ -505,7 +505,7 @@ PY_CAST_INT(unsigned long)
|
||||
PY_CAST_INT(unsigned long long)
|
||||
|
||||
template<> inline float py_cast<float>(VM* vm, PyObject* obj){
|
||||
if(is_float(obj)) return BitsCvt(PK_BITS(obj) & Number::c1)._float;
|
||||
if(is_float(obj)) return untag_float(obj);
|
||||
i64 bits;
|
||||
if(try_cast_int(obj, &bits)) return (float)bits;
|
||||
vm->TypeError("expected 'int' or 'float', got " + OBJ_NAME(vm->_t(obj)).escape());
|
||||
@ -515,7 +515,7 @@ template<> inline float _py_cast<float>(VM* vm, PyObject* obj){
|
||||
return py_cast<float>(vm, obj);
|
||||
}
|
||||
template<> inline double py_cast<double>(VM* vm, PyObject* obj){
|
||||
if(is_float(obj)) return BitsCvt(PK_BITS(obj) & Number::c1)._float;
|
||||
if(is_float(obj)) return untag_float(obj);
|
||||
i64 bits;
|
||||
if(try_cast_int(obj, &bits)) return (float)bits;
|
||||
vm->TypeError("expected 'int' or 'float', got " + OBJ_NAME(vm->_t(obj)).escape());
|
||||
@ -532,7 +532,7 @@ const i64 kMinSmallInt = -(1ll << 28);
|
||||
inline PyObject* py_var(VM* vm, T _val){ \
|
||||
i64 val = static_cast<i64>(_val); \
|
||||
if(val >= kMinSmallInt && val <= kMaxSmallInt){ \
|
||||
val = (val << 2) | 0b01; \
|
||||
val = (val << 2) | 0b10; \
|
||||
return reinterpret_cast<PyObject*>(val); \
|
||||
}else{ \
|
||||
return vm->heap.gcnew<i64>(vm->tp_int, val); \
|
||||
@ -554,16 +554,7 @@ PY_VAR_INT(unsigned long long)
|
||||
#define PY_VAR_FLOAT(T) \
|
||||
inline PyObject* py_var(VM* vm, T _val){ \
|
||||
PK_UNUSED(vm); \
|
||||
BitsCvt val(static_cast<f64>(_val)); \
|
||||
i64 bits = val._int & Number::c1; \
|
||||
i64 tail = val._int & Number::c2; \
|
||||
if(tail == 0b10){ \
|
||||
if(bits&0b100) bits += 0b100; \
|
||||
}else if(tail == 0b11){ \
|
||||
bits += 0b100; \
|
||||
} \
|
||||
bits |= 0b10; \
|
||||
return reinterpret_cast<PyObject*>(bits); \
|
||||
return tag_float(static_cast<f64>(_val)); \
|
||||
}
|
||||
|
||||
PY_VAR_FLOAT(float)
|
||||
|
Loading…
x
Reference in New Issue
Block a user