मैंने मॉड्यूल (this और this) को देखा और सिथॉन को कोड का अनुवाद किया और PyObject
भागों को हटा दिया। सिद्धांत रूप में यह काम करना चाहिए, लेकिन कुछ भागों (float
भागों की तरह) मैं कड़ाई से परीक्षण का कोई तरीका नहीं:
कुछ आयात:
from cpython.array cimport array, clone
from libc.string cimport memcmp, memcpy
from libc.math cimport frexp, ldexp
from libc.stdint cimport int32_t, int64_t
सहेजें एक जुड़े हुए प्रकार के साथ कुछ कोड। यह तकनीकी रूप से स्थिर सुविधा नहीं है, लेकिन यह मेरे लिए निर्दोष रूप से काम करता है:
ctypedef fused integer:
int32_t
int64_t
यह भाग मशीन की अंतहीनता का परीक्षण करता है। यह मेरे लिए काम करता है, लेकिन यह शायद ही एक पूरा सूट है। OTOH, इसके बारे में लग रहा है सही
cdef enum float_format_type:
unknown_format,
ieee_big_endian_format,
ieee_little_endian_format
# Set-up
cdef array stringtemplate = array('B')
cdef float_format_type double_format
cdef double x = 9006104071832581.0
if sizeof(double) == 8:
if memcmp(&x, b"\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0:
double_format = ieee_big_endian_format
elif memcmp(&x, b"\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0:
double_format = ieee_little_endian_format
else:
double_format = unknown_format
else:
double_format = unknown_format;
इस भाग सरल है (stringtemplate
bytes
वस्तुओं जल्दी से बनाने के लिए सक्षम होने के लिए प्रयोग किया जाता है):
cdef void _write_integer(integer x, char* output):
cdef int i
for i in range(sizeof(integer)-1, -1, -1):
output[i] = <char>x
x >>= 8
cpdef bytes write_int(int32_t i):
cdef array output = clone(stringtemplate, sizeof(int32_t), False)
_write_integer(i, output.data.as_chars)
return output.data.as_chars[:sizeof(int32_t)]
cpdef bytes write_long(int64_t i):
cdef array output = clone(stringtemplate, sizeof(int64_t), False)
_write_integer(i, output.data.as_chars)
return output.data.as_chars[:sizeof(int64_t)]
array
malloc
के समान है लेकिन यह है कचरा इकट्ठा :)।
इस भाग में मुझे अधिकतर कोई जानकारी नहीं है। मेरे "परीक्षण" पास हुए, लेकिन यह ज्यादातर उम्मीद है:
cdef void _write_double(double x, char* output):
cdef:
unsigned char sign
int e
double f
unsigned int fhi, flo, i
char *s
if double_format == unknown_format or True:
if x < 0:
sign = 1
x = -x
else:
sign = 0
f = frexp(x, &e)
# Normalize f to be in the range [1.0, 2.0)
if 0.5 <= f < 1.0:
f *= 2.0
e -= 1
elif f == 0.0:
e = 0
else:
raise SystemError("frexp() result out of range")
if e >= 1024:
raise OverflowError("float too large to pack with d format")
elif e < -1022:
# Gradual underflow
f = ldexp(f, 1022 + e)
e = 0;
elif not (e == 0 and f == 0.0):
e += 1023
f -= 1.0 # Get rid of leading 1
# fhi receives the high 28 bits; flo the low 24 bits (== 52 bits)
f *= 2.0 ** 28
fhi = <unsigned int>f # Truncate
assert fhi < 268435456
f -= <double>fhi
f *= 2.0 ** 24
flo = <unsigned int>(f + 0.5) # Round
assert(flo <= 16777216);
if flo >> 24:
# The carry propagated out of a string of 24 1 bits.
flo = 0
fhi += 1
if fhi >> 28:
# And it also progagated out of the next 28 bits.
fhi = 0
e += 1
if e >= 2047:
raise OverflowError("float too large to pack with d format")
output[0] = (sign << 7) | (e >> 4)
output[1] = <unsigned char> (((e & 0xF) << 4) | (fhi >> 24))
output[2] = 0xFF & (fhi >> 16)
output[3] = 0xFF & (fhi >> 8)
output[4] = 0xFF & fhi
output[5] = 0xFF & (flo >> 16)
output[6] = 0xFF & (flo >> 8)
output[7] = 0xFF & flo
else:
s = <char*>&x;
if double_format == ieee_little_endian_format:
for i in range(8):
output[i] = s[7-i]
else:
for i in range(8):
output[i] = s[i]
यदि आप समझ सकते हैं कि यह कैसे काम करता है, तो इसे स्वयं जांचें।
फिर हम यह पहले की तरह लपेट:
cdef bytes write_double(double x):
cdef array output = clone(stringtemplate, sizeof(double), False)
_write_double(x, output.data.as_chars)
return output.data.as_chars[:sizeof(double)]
स्ट्रिंग एक वास्तव में बहुत आसान है, और यही कारण है मैं इसे सेट अप के रूप में मैं ऊपर किया:
cdef bytes write_string(bytes val):
cdef:
int32_t int_length = sizeof(int32_t)
int32_t input_length = len(val)
array output = clone(stringtemplate, int_length + input_length, True)
_write_integer(input_length, output.data.as_chars)
memcpy(output.data.as_chars + int_length, <char*>val, input_length)
return output.data.as_chars[:int_length + input_length]
यदि यह पूर्णांकों मैं विशेष रूप से उन के लिए पूछ की सलाह देते हैं, यह भी शीर्षक में के बारे में ही है। – User
हाय मैंने अभी विस्तार से अधिक जानकारी प्रदान करने के लिए कोड अपडेट किया है। यह int/double/string के बारे में है। – lxyu