return NULL; } s = PyString_AS_STRING(arg); if (strcmp(s, "double") == 0) { r = double_format; } else if (strcmp(s, "float") == 0) { r = float_format; } else { PyErr_SetString(PyExc_ValueError, "__getformat__() argument 1 must be " "'double' or 'float'"); return NULL; } switch (r) { case unknown_format: return PyString_FromString("unknown"); case ieee_little_endian_format: return PyString_FromString("IEEE, little-endian"); case ieee_big_endian_format: return PyString_FromString("IEEE, big-endian"); default: Py_FatalError("insane float_format or double_format"); return NULL; }} PyDoc_STRVAR(float_getformat_doc,"float.__getformat__(tstr) -> string\n""\n""You probably don't want to use this function. It exists mainly to be\n""used in Python's test suite.\n""\n""tstr must be 'double' or 'float'. This function returns whichever of\n""'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n""format of floating point numbers used by the C type named by tstr."); static PyObject *float_setformat(PyTypeObject *v, PyObject* args){ char* tstr; char* format; float_format_type f; float_format_type detected; float_format_type *p; if (!PyArg_ParseTuple(args, "ss:__setformat__", &tstr, &format)) return NULL; if (strcmp(tstr, "double") == 0) { p = &double_format; detected = detected_double_format; } else if (strcmp(tstr, "float") == 0) { p = &float_format; detected = detected_float_format; } else { PyErr_SetString(PyExc_ValueError, "__setformat__() argument 1 must " "be 'double' or 'float'"); return NULL; } if (strcmp(format, "unknown") == 0) { f = unknown_format; } else if (strcmp(format, "IEEE, little-endian") == 0) { f = ieee_little_endian_format; } else if (strcmp(format, "IEEE, big-endian") == 0) { f = ieee_big_endian_format; } else { PyErr_SetString(PyExc_ValueError, "__setformat__() argument 2 must be " "'unknown', 'IEEE, little-endian' or " "'IEEE, big-endian'"); return NULL; } if (f != unknown_format && f != detected) { PyErr_Format(PyExc_ValueError, "can only set %s format to 'unknown' or the " "detected platform value", tstr); return NULL; } *p = f; Py_RETURN_NONE;} PyDoc_STRVAR(float_setformat_doc,"float.__setformat__(tstr, fmt) -> None\n""\n""You probably don't want to use this function. It exists mainly to be\n""used in Python's test suite.\n""\n""tstr must be 'double' or 'float'. fmt must be one of 'unknown',\n""'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n""one of the latter two if it appears to match the underlying C reality.\n""\n""Overrides the automatic determination of C-level floating point type.\n""This affects how floats are converted to and from binary strings."); static PyMethodDef float_methods[] = { {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, {"__getformat__", (PyCFunction)float_getformat, METH_O|METH_CLASS, float_getformat_doc}, {"__setformat__", (PyCFunction)float_setformat, METH_VARARGS|METH_CLASS, float_setformat_doc}, {NULL, NULL} /* sentinel */}; PyDoc_STRVAR(float_doc,"float(x) -> floating point number\n\\n\Convert a string or number to a floating point number, if possible."); static PyNumberMethods float_as_number = { float_add, /*nb_add*/ float_sub, /*nb_subtract*/ float_mul, /*nb_multiply*/ float_classic_div, /*nb_divide*/ float_rem, /*nb_remainder*/ float_divmod, /*nb_divmod*/ float_pow, /*nb_power*/ (unaryfunc)float_neg, /*nb_negative*/ (unaryfunc)float_pos, /*nb_positive*/ (unaryfunc)float_abs, /*nb_absolute*/ (inquiry)float_nonzero, /*nb_nonzero*/ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ float_coerce, /*nb_coerce*/ float_int, /*nb_int*/ float_long, /*nb_long*/ float_float, /*nb_float*/ 0, /* nb_oct */ 0, /* nb_hex */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ 0, /* nb_inplace_divide */ 0, /* nb_inplace_remainder */ 0, /* nb_inplace_power */ 0, /* nb_inplace_lshift */ 0, /* nb_inplace_rshift */ 0, /* nb_inplace_and */ 0, /* nb_inplace_xor */ 0, /* nb_inplace_or */ float_floor_div, /* nb_floor_divide */ float_div, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */}; PyTypeObject PyFloat_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "float", sizeof(PyFloatObject), 0, (destructor)float_dealloc, /* tp_dealloc */ (printfunc)float_print, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)float_repr, /* tp_repr */ &float_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc)float_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)float_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_BASETYPE, /* tp_flags */ float_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ float_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ float_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ float_new, /* tp_new */}; void_PyFloat_Init(void){ /* We attempt to determine if this machine is using IEEE floating point formats by peering at the bits of some carefully chosen values. If it looks like we are on an IEEE platform, the float packing/unpacking routines can just copy bits, if not they resort to arithmetic & shifts and masks. The shifts & masks approach works on all finite values, but what happens to infinities, NaNs and signed zeroes on packing is an accident, and attempting to unpack a NaN or an infinity will raise an exception. Note that if we're on some whacked-out platform which uses IEEE formats but isn't strictly little-endian or big- endian, we will fall back to the portable shifts & masks method. */ #if SIZEOF_DOUBLE == 8 { double x = 9006104071832581.0; if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0) detected_double_format = ieee_big_endian_format; else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) detected_double_format = ieee_little_endian_format; else detected_double_format = unknown_format; }#else detected_double_format = unknown_format;#endif #if SIZEOF_FLOAT == 4 { float y = 16711938.0; if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) detected_float_format = ieee_big_endian_format; else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) detected_float_format = ieee_little_endian_format; else detected_float_format = unknown_format; }#else detected_float_format = unknown_format;#endif double_format = detected_double_format; float_format = detected_float_format;} voidPyFloat_Fini(void){ PyFloatObject *p; PyFloatBlock *list, *next; unsigned i; int bc, bf; /* block count, number of freed blocks */ int frem, fsum; /* remaining unfreed floats per block, total */ bc = 0; bf = 0; fsum = 0; list = block_list; block_list = NULL; free_list = NULL; while (list != NULL) { bc++; frem = 0; for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) frem++; } next = list->next; if (frem) { list->next = block_list; block_list = list; for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (!PyFloat_CheckExact(p) || p->ob_refcnt == 0) { p->ob_type = (struct _typeobject *) free_list; free_list = p; } } } else { PyMem_FREE(list); /* XXX PyObject_FREE ??? */ bf++; } fsum += frem; list = next; } if (!Py_VerboseFlag) return; fprintf(stderr, "# cleanup floats"); if (!fsum) { fprintf(stderr, "\n"); } else { fprintf(stderr, ": %d unfreed float%s in %d out of %d block%s\n", fsum, fsum == 1 ? "" : "s", bc - bf, bc, bc == 1 ? "" : "s"); } if (Py_VerboseFlag > 1) { list = block_list; while (list != NULL) { for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) { char buf[100]; PyFloat_AsString(buf, p); /* XXX(twouters) cast refcount to long until %zd is universally available */ fprintf(stderr, "# <float at %p, refcnt=%ld, val=%s>\n", p, (long)p->ob_refcnt, buf); } } list = list->next; } }} /*---------------------------------------------------------------------------- * _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h. * * TODO: On platforms that use the standard IEEE-754 single and double * formats natively, these routines could simply copy the bytes. */int_PyFloat_Pack4(double x, unsigned char *p, int le){ if (float_format == unknown_format) { unsigned char sign; int e; double f; unsigned int fbits; int incr = 1; if (le) { p += 3; incr = -1; } 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 && f < 1.0) { f *= 2.0; e--; } else if (f == 0.0) e = 0; else { PyErr_SetString(PyExc_SystemError, "frexp() result out of range"); return -1; } if (e >= 128) goto Overflow; else if (e < -126) { /* Gradual underflow */ f = ldexp(f, 126 + e); e = 0; } else if (!(e == 0 && f == 0.0)) { e += 127; f -= 1.0; /* Get rid of leading 1 */ } f *= 8388608.0; /* 2**23 */ fbits = (unsigned int)(f + 0.5); /* Round */ assert(fbits <= 8388608); if (fbits >> 23) { /* The carry propagated out of a string of 23 1 bits. */ fbits = 0; ++e; if (e >= 255) goto Overflow; } /* First byte */ *p = (sign << 7) | (e >> 1); p += incr; /* Second byte */ *p = (char) (((e & 1) << 7) | (fbits >> 16)); p += incr; /* Third byte */ *p = (fbits >> 8) & 0xFF; p += incr; /* Fourth byte */ *p = fbits & 0xFF; /* Done */ return 0; Overflow: PyErr_SetString(PyExc_OverflowError, "float too large to pack with f format"); return -1; } else { float y = (float)x; const char *s = (char*)&y; int i, incr = 1; if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) { p += 3; incr = -1; } for (i = 0; i < 4; i++) { *p = *s++; p += incr; } return 0; }} int_PyFloat_Pack8(double x, unsigned char *p, int le){ if (double_format == unknown_format) { unsigned char sign; int e; double f; unsigned int fhi, flo; int incr = 1; if (le) { p += 7; incr = -1; } 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 && f < 1.0) { f *= 2.0; e--; } else if (f == 0.0) e = 0; else { PyErr_SetString(PyExc_SystemError, "frexp() result out of range"); return -1; } if (e >= 1024) goto Overflow; else if (e < -1022) { /* Gradual underflow */ f = ldexp(f, 1022 + e); e = 0; } else if (!(e == 0 && 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 *= 268435456.0; /* 2**28 */ fhi = (unsigned int)f; /* Truncate */ assert(fhi < 268435456);Lines 1001–1500 of 1748. Previous lines Load more
return NULL; } s = PyString_AS_STRING(arg); if (strcmp(s, "double") == 0) { r = double_format; } else if (strcmp(s, "float") == 0) { r = float_format; } else { PyErr_SetString(PyExc_ValueError, "__getformat__() argument 1 must be " "'double' or 'float'"); return NULL; } switch (r) { case unknown_format: return PyString_FromString("unknown"); case ieee_little_endian_format: return PyString_FromString("IEEE, little-endian"); case ieee_big_endian_format: return PyString_FromString("IEEE, big-endian"); default: Py_FatalError("insane float_format or double_format"); return NULL; } } PyDoc_STRVAR(float_getformat_doc, "float.__getformat__(tstr) -> string\n" "\n" "You probably don't want to use this function. It exists mainly to be\n" "used in Python's test suite.\n" "\n" "tstr must be 'double' or 'float'. This function returns whichever of\n" "'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n" "format of floating point numbers used by the C type named by tstr."); static PyObject * float_setformat(PyTypeObject *v, PyObject* args) { char* tstr; char* format; float_format_type f; float_format_type detected; float_format_type *p; if (!PyArg_ParseTuple(args, "ss:__setformat__", &tstr, &format)) return NULL; if (strcmp(tstr, "double") == 0) { p = &double_format; detected = detected_double_format; } else if (strcmp(tstr, "float") == 0) { p = &float_format; detected = detected_float_format; } else { PyErr_SetString(PyExc_ValueError, "__setformat__() argument 1 must " "be 'double' or 'float'"); return NULL; } if (strcmp(format, "unknown") == 0) { f = unknown_format; } else if (strcmp(format, "IEEE, little-endian") == 0) { f = ieee_little_endian_format; } else if (strcmp(format, "IEEE, big-endian") == 0) { f = ieee_big_endian_format; } else { PyErr_SetString(PyExc_ValueError, "__setformat__() argument 2 must be " "'unknown', 'IEEE, little-endian' or " "'IEEE, big-endian'"); return NULL; } if (f != unknown_format && f != detected) { PyErr_Format(PyExc_ValueError, "can only set %s format to 'unknown' or the " "detected platform value", tstr); return NULL; } *p = f; Py_RETURN_NONE; } PyDoc_STRVAR(float_setformat_doc, "float.__setformat__(tstr, fmt) -> None\n" "\n" "You probably don't want to use this function. It exists mainly to be\n" "used in Python's test suite.\n" "\n" "tstr must be 'double' or 'float'. fmt must be one of 'unknown',\n" "'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n" "one of the latter two if it appears to match the underlying C reality.\n" "\n" "Overrides the automatic determination of C-level floating point type.\n" "This affects how floats are converted to and from binary strings."); static PyMethodDef float_methods[] = { {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, {"__getformat__", (PyCFunction)float_getformat, METH_O|METH_CLASS, float_getformat_doc}, {"__setformat__", (PyCFunction)float_setformat, METH_VARARGS|METH_CLASS, float_setformat_doc}, {NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(float_doc, "float(x) -> floating point number\n\ \n\ Convert a string or number to a floating point number, if possible."); static PyNumberMethods float_as_number = { float_add, /*nb_add*/ float_sub, /*nb_subtract*/ float_mul, /*nb_multiply*/ float_classic_div, /*nb_divide*/ float_rem, /*nb_remainder*/ float_divmod, /*nb_divmod*/ float_pow, /*nb_power*/ (unaryfunc)float_neg, /*nb_negative*/ (unaryfunc)float_pos, /*nb_positive*/ (unaryfunc)float_abs, /*nb_absolute*/ (inquiry)float_nonzero, /*nb_nonzero*/ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ 0, /*nb_and*/ 0, /*nb_xor*/ 0, /*nb_or*/ float_coerce, /*nb_coerce*/ float_int, /*nb_int*/ float_long, /*nb_long*/ float_float, /*nb_float*/ 0, /* nb_oct */ 0, /* nb_hex */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply */ 0, /* nb_inplace_divide */ 0, /* nb_inplace_remainder */ 0, /* nb_inplace_power */ 0, /* nb_inplace_lshift */ 0, /* nb_inplace_rshift */ 0, /* nb_inplace_and */ 0, /* nb_inplace_xor */ 0, /* nb_inplace_or */ float_floor_div, /* nb_floor_divide */ float_div, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ }; PyTypeObject PyFloat_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "float", sizeof(PyFloatObject), 0, (destructor)float_dealloc, /* tp_dealloc */ (printfunc)float_print, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)float_repr, /* tp_repr */ &float_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ (hashfunc)float_hash, /* tp_hash */ 0, /* tp_call */ (reprfunc)float_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_BASETYPE, /* tp_flags */ float_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ float_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ float_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ float_new, /* tp_new */ }; void _PyFloat_Init(void) { /* We attempt to determine if this machine is using IEEE floating point formats by peering at the bits of some carefully chosen values. If it looks like we are on an IEEE platform, the float packing/unpacking routines can just copy bits, if not they resort to arithmetic & shifts and masks. The shifts & masks approach works on all finite values, but what happens to infinities, NaNs and signed zeroes on packing is an accident, and attempting to unpack a NaN or an infinity will raise an exception. Note that if we're on some whacked-out platform which uses IEEE formats but isn't strictly little-endian or big- endian, we will fall back to the portable shifts & masks method. */ #if SIZEOF_DOUBLE == 8 { double x = 9006104071832581.0; if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0) detected_double_format = ieee_big_endian_format; else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) detected_double_format = ieee_little_endian_format; else detected_double_format = unknown_format; } #else detected_double_format = unknown_format; #endif #if SIZEOF_FLOAT == 4 { float y = 16711938.0; if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) detected_float_format = ieee_big_endian_format; else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) detected_float_format = ieee_little_endian_format; else detected_float_format = unknown_format; } #else detected_float_format = unknown_format; #endif double_format = detected_double_format; float_format = detected_float_format; } void PyFloat_Fini(void) { PyFloatObject *p; PyFloatBlock *list, *next; unsigned i; int bc, bf; /* block count, number of freed blocks */ int frem, fsum; /* remaining unfreed floats per block, total */ bc = 0; bf = 0; fsum = 0; list = block_list; block_list = NULL; free_list = NULL; while (list != NULL) { bc++; frem = 0; for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) frem++; } next = list->next; if (frem) { list->next = block_list; block_list = list; for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (!PyFloat_CheckExact(p) || p->ob_refcnt == 0) { p->ob_type = (struct _typeobject *) free_list; free_list = p; } } } else { PyMem_FREE(list); /* XXX PyObject_FREE ??? */ bf++; } fsum += frem; list = next; } if (!Py_VerboseFlag) return; fprintf(stderr, "# cleanup floats"); if (!fsum) { fprintf(stderr, "\n"); } else { fprintf(stderr, ": %d unfreed float%s in %d out of %d block%s\n", fsum, fsum == 1 ? "" : "s", bc - bf, bc, bc == 1 ? "" : "s"); } if (Py_VerboseFlag > 1) { list = block_list; while (list != NULL) { for (i = 0, p = &list->objects[0]; i < N_FLOATOBJECTS; i++, p++) { if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) { char buf[100]; PyFloat_AsString(buf, p); /* XXX(twouters) cast refcount to long until %zd is universally available */ fprintf(stderr, "# <float at %p, refcnt=%ld, val=%s>\n", p, (long)p->ob_refcnt, buf); } } list = list->next; } } } /*---------------------------------------------------------------------------- * _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h. * * TODO: On platforms that use the standard IEEE-754 single and double * formats natively, these routines could simply copy the bytes. */ int _PyFloat_Pack4(double x, unsigned char *p, int le) { if (float_format == unknown_format) { unsigned char sign; int e; double f; unsigned int fbits; int incr = 1; if (le) { p += 3; incr = -1; } 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 && f < 1.0) { f *= 2.0; e--; } else if (f == 0.0) e = 0; else { PyErr_SetString(PyExc_SystemError, "frexp() result out of range"); return -1; } if (e >= 128) goto Overflow; else if (e < -126) { /* Gradual underflow */ f = ldexp(f, 126 + e); e = 0; } else if (!(e == 0 && f == 0.0)) { e += 127; f -= 1.0; /* Get rid of leading 1 */ } f *= 8388608.0; /* 2**23 */ fbits = (unsigned int)(f + 0.5); /* Round */ assert(fbits <= 8388608); if (fbits >> 23) { /* The carry propagated out of a string of 23 1 bits. */ fbits = 0; ++e; if (e >= 255) goto Overflow; } /* First byte */ *p = (sign << 7) | (e >> 1); p += incr; /* Second byte */ *p = (char) (((e & 1) << 7) | (fbits >> 16)); p += incr; /* Third byte */ *p = (fbits >> 8) & 0xFF; p += incr; /* Fourth byte */ *p = fbits & 0xFF; /* Done */ return 0; Overflow: PyErr_SetString(PyExc_OverflowError, "float too large to pack with f format"); return -1; } else { float y = (float)x; const char *s = (char*)&y; int i, incr = 1; if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) { p += 3; incr = -1; } for (i = 0; i < 4; i++) { *p = *s++; p += incr; } return 0; } } int _PyFloat_Pack8(double x, unsigned char *p, int le) { if (double_format == unknown_format) { unsigned char sign; int e; double f; unsigned int fhi, flo; int incr = 1; if (le) { p += 7; incr = -1; } 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 && f < 1.0) { f *= 2.0; e--; } else if (f == 0.0) e = 0; else { PyErr_SetString(PyExc_SystemError, "frexp() result out of range"); return -1; } if (e >= 1024) goto Overflow; else if (e < -1022) { /* Gradual underflow */ f = ldexp(f, 1022 + e); e = 0; } else if (!(e == 0 && 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 *= 268435456.0; /* 2**28 */ fhi = (unsigned int)f; /* Truncate */ assert(fhi < 268435456);