summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/dragon4.c264
-rw-r--r--numpy/core/src/multiarray/dragon4.h68
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c161
3 files changed, 432 insertions, 61 deletions
diff --git a/numpy/core/src/multiarray/dragon4.c b/numpy/core/src/multiarray/dragon4.c
index 3f2749d82..07e250b10 100644
--- a/numpy/core/src/multiarray/dragon4.c
+++ b/numpy/core/src/multiarray/dragon4.c
@@ -1509,10 +1509,15 @@ npy_uint64 GetMantissa_F64(FloatUnion64 *v) { return v->integer & 0xFFFFFFFFFFFF
* intbit 1 bit, first u64
* mantissa: 63 bits, first u64
*/
-typedef union FloatUnion128 {
- npy_float128 floatingPoint;
+
+/*
+ * Since systems have different types of long doubles, and may not necessarily
+ * have a 128-byte format we can use to pass values around, here we create
+ * our own 128-bit storage type for convenience.
+ */
+typedef struct FloatVal128 {
npy_uint64 integer[2];
-} FloatUnion128;
+} FloatVal128;
npy_bool IsNegative_F128(FloatVal128 *v) {
return ((v->integer[1] >> 15) & 0x1) != 0;
}
@@ -1522,6 +1527,44 @@ npy_uint64 GetMantissa_F128(FloatVal128 *v) {
}
/*
+ * then for each different definition of long double, we create a union to
+ * unpack the float data safely. We can then copy these integers to a
+ * FloatVal128.
+ */
+#ifdef NPY_FLOAT128
+typedef union FloatUnion128
+{
+ npy_float128 floatingPoint;
+ struct {
+ npy_uint64 a;
+ npy_uint16 b;
+ } integer;
+} FloatUnion128;
+#endif
+
+#ifdef NPY_FLOAT96
+typedef union FloatUnion96
+{
+ npy_float96 floatingPoint;
+ struct {
+ npy_uint64 a;
+ npy_uint32 b;
+ } integer;
+} FloatUnion96;
+#endif
+
+#ifdef NPY_FLOAT80
+typedef union FloatUnion80
+{
+ npy_float80 floatingPoint;
+ struct {
+ npy_uint64 a;
+ npy_uint16 b;
+ } integer;
+} FloatUnion80;
+#endif
+
+/*
* The main changes above this point, relative to Ryan Juckett's code, are:
* 1. fixed overflow problems when mantissa was 64 bits (in float128 types),
* by replacing multiplication by 2 or 4 by BigInt_ShiftLeft calls.
@@ -1532,7 +1575,7 @@ npy_uint64 GetMantissa_F128(FloatVal128 *v) {
* Below this point, the FormatPositional and FormatScientific functions have
* been more significantly rewritten. The Dragon4_PrintFloat16 and
* Dragon4_PrintFloat128 functions are new, and were adapted from the 64 and 32
- * bit versions.
+ * bit versions. The python interfacing functions (in the header) are new.
*/
@@ -2102,7 +2145,7 @@ PrintInfNan(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
* exponent with 0s until there are this many digits. If
* negative, only use sufficient digits.
*/
-npy_uint32
+static npy_uint32
Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value,
npy_bool scientific, npy_bool unique, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
@@ -2198,7 +2241,7 @@ Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value,
}
}
-npy_uint32
+static npy_uint32
Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value,
npy_bool scientific, npy_bool unique, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
@@ -2294,7 +2337,7 @@ Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value,
}
}
-npy_uint32
+static npy_uint32
Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value,
npy_bool scientific, npy_bool unique, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
@@ -2391,7 +2434,7 @@ Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value,
}
}
-npy_uint32
+static npy_uint32
Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value,
npy_bool scientific, npy_bool unique, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
@@ -2485,4 +2528,209 @@ Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value,
digits_left, digits_right);
}
}
+
+PyObject *
+Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
+ int precision, int sign, TrimMode trim,
+ int pad_left, int pad_right)
+{
+ /*
+ * Use a very large buffer in case anyone tries to output a large numberG.
+ * 16384 should be enough to uniquely print any float128, which goes up
+ * to about 10^4932 */
+ static char repr[16384];
+ FloatVal128 val128;
+#ifdef NPY_FLOAT80
+ FloatUnion80 buf80;;
+#endif
+#ifdef NPY_FLOAT96
+ FloatUnion96 buf96;
+#endif
+#ifdef NPY_FLOAT128
+ FloatUnion128 buf128;
+#endif
+
+ switch (size) {
+ case 2:
+ Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+ case 4:
+ Dragon4_PrintFloat32(repr, sizeof(repr), *(npy_float32*)val,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+ case 8:
+ Dragon4_PrintFloat64(repr, sizeof(repr), *(npy_float64*)val,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+#ifdef NPY_FLOAT80
+ case 10:
+ buf80.floatingPoint = *(npy_float80*)val;
+ val128.integer[0] = buf80.integer.a;
+ val128.integer[1] = buf80.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+#endif
+#ifdef NPY_FLOAT96
+ case 12:
+ buf96.floatingPoint = *(npy_float96*)val;
+ val128.integer[0] = buf96.integer.a;
+ val128.integer[1] = buf96.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+#endif
+#ifdef NPY_FLOAT128
+ case 16:
+ buf128.floatingPoint = *(npy_float128*)val;
+ val128.integer[0] = buf128.integer.a;
+ val128.integer[1] = buf128.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ break;
+#endif
+ default:
+ PyErr_Format(PyExc_ValueError, "unexpected itemsize %zu", size);
+ return NULL;
+ }
+
+ return PyUString_FromString(repr);
+}
+
+PyObject *
+Dragon4_Positional(PyObject *obj, npy_bool unique, int precision, int sign,
+ TrimMode trim, int pad_left, int pad_right)
+{
+ double val;
+
+ if (PyArray_IsScalar(obj, Half)) {
+ npy_half x = ((PyHalfScalarObject *)obj)->obval;
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_half), unique,
+ precision, sign, trim, pad_left, pad_right);
+ }
+ else if (PyArray_IsScalar(obj, Float)) {
+ npy_float x = ((PyFloatScalarObject *)obj)->obval;
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_float), unique,
+ precision, sign, trim, pad_left, pad_right);
+ }
+ else if (PyArray_IsScalar(obj, Double)) {
+ npy_double x = ((PyDoubleScalarObject *)obj)->obval;
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_double), unique,
+ precision, sign, trim, pad_left, pad_right);
+ }
+ else if (PyArray_IsScalar(obj, LongDouble)) {
+ npy_longdouble x = ((PyLongDoubleScalarObject *)obj)->obval;
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_longdouble), unique,
+ precision, sign, trim, pad_left, pad_right);
+ }
+
+ val = PyFloat_AsDouble(obj);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ return Dragon4_Positional_AnySize(&val, sizeof(double), unique,
+ precision, sign, trim, pad_left, pad_right);
+}
+
+PyObject *
+Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
+ int precision, int sign, TrimMode trim,
+ int pad_left, int exp_digits)
+{
+ /* use a very large buffer in case anyone tries to output a large precision */
+ static char repr[4096];
+ FloatVal128 val128;
+#ifdef NPY_FLOAT80
+ FloatUnion80 buf80;;
+#endif
+#ifdef NPY_FLOAT96
+ FloatUnion96 buf96;
+#endif
+#ifdef NPY_FLOAT128
+ FloatUnion128 buf128;
#endif
+
+
+ switch (size) {
+ case 2:
+ Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+ case 4:
+ Dragon4_PrintFloat32(repr, sizeof(repr), *(npy_float32*)val,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+ case 8:
+ Dragon4_PrintFloat64(repr, sizeof(repr), *(npy_float64*)val,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+#ifdef NPY_FLOAT80
+ case 10:
+ buf80.floatingPoint = *(npy_float80*)val;
+ val128.integer[0] = buf80.integer.a;
+ val128.integer[1] = buf80.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+#endif
+#ifdef NPY_FLOAT96
+ case 12:
+ buf96.floatingPoint = *(npy_float96*)val;
+ val128.integer[0] = buf96.integer.a;
+ val128.integer[1] = buf96.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+#endif
+#ifdef NPY_FLOAT128
+ case 16:
+ buf128.floatingPoint = *(npy_float128*)val;
+ val128.integer[0] = buf128.integer.a;
+ val128.integer[1] = buf128.integer.b;
+ Dragon4_PrintFloat128(repr, sizeof(repr), val128,
+ 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ break;
+#endif
+ default:
+ PyErr_Format(PyExc_ValueError, "unexpected itemsize %zu", size);
+ return NULL;
+ }
+
+ return PyUString_FromString(repr);
+}
+
+PyObject *
+Dragon4_Scientific(PyObject *obj, npy_bool unique, int precision, int sign,
+ TrimMode trim, int pad_left, int exp_digits)
+{
+ double val;
+
+ if (PyArray_IsScalar(obj, Half)) {
+ npy_half x = ((PyHalfScalarObject *)obj)->obval;
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_half), unique,
+ precision, sign, trim, pad_left, exp_digits);
+ }
+ else if (PyArray_IsScalar(obj, Float)) {
+ npy_float x = ((PyFloatScalarObject *)obj)->obval;
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_float), unique,
+ precision, sign, trim, pad_left, exp_digits);
+ }
+ else if (PyArray_IsScalar(obj, Double)) {
+ npy_double x = ((PyDoubleScalarObject *)obj)->obval;
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_double), unique,
+ precision, sign, trim, pad_left, exp_digits);
+ }
+ else if (PyArray_IsScalar(obj, LongDouble)) {
+ npy_longdouble x = ((PyLongDoubleScalarObject *)obj)->obval;
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_longdouble), unique,
+ precision, sign, trim, pad_left, exp_digits);
+ }
+
+ val = PyFloat_AsDouble(obj);
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+ return Dragon4_Scientific_AnySize(&val, sizeof(double), unique,
+ precision, sign, trim, pad_left, exp_digits);
+}
diff --git a/numpy/core/src/multiarray/dragon4.h b/numpy/core/src/multiarray/dragon4.h
index 9ace4fd58..814c84a2f 100644
--- a/numpy/core/src/multiarray/dragon4.h
+++ b/numpy/core/src/multiarray/dragon4.h
@@ -30,7 +30,15 @@
#ifndef _NPY_DRAGON4_H_
#define _NPY_DRAGON4_H_
-#include "numpy/npy_common.h"
+
+#include "Python.h"
+#include "structmember.h"
+#define NPY_NO_DEPRECATED_API NPY_API_VERSION
+#define _MULTIARRAYMODULE
+#include "numpy/arrayobject.h"
+#include "npy_config.h"
+#include "npy_pycompat.h"
+#include "numpy/arrayscalars.h"
typedef enum TrimMode
{
@@ -40,53 +48,23 @@ typedef enum TrimMode
TrimMode_DptZeros, /* trim trailing zeros & trailing decimal point */
} TrimMode;
+PyObject *
+Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
+ int precision, int sign, TrimMode trim,
+ int pad_left, int pad_right);
-//******************************************************************************
-// These functions frint a floating-point number as a decimal string.
-// The output string is always NUL terminated and the string length (not
-// including the NUL) is returned.
-//******************************************************************************
-//
-// Arguments are:
-// * buffer - buffer to output into
-// * bufferSize - maximum characters that can be printed to buffer
-// * value - value significand
-// * scientific - boolean controlling whether scientific notation is used
-// * precision - If positive, specifies the number of decimals to show after
-// decimal point. If negative, sufficient digits to uniquely
-// specify the float will be output.
-// * trim_mode - how to treat trailing zeros and decimal point. See TrimMode.
-// * digits_right - pad the result with '' on the right past the decimal point
-// * digits_left - pad the result with '' on the right past the decimal point
-// * exp_digits - Only affects scientific output. If positive, pads the
-// exponent with 0s until there are this many digits. If
-// negative, only use sufficient digits.
-
-npy_uint32
-Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
- npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
- npy_int32 digits_right, npy_int32 exp_digits);
+PyObject *
+Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
+ int precision, int sign, TrimMode trim,
+ int pad_left, int exp_digits);
-npy_uint32
-Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
- npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
- npy_int32 digits_right, npy_int32 exp_digits);
+PyObject *
+Dragon4_Positional(PyObject *obj, npy_bool unique, int precision, int sign,
+ TrimMode trim, int pad_left, int pad_right);
-npy_uint32
-Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
- npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
- npy_int32 digits_right, npy_int32 exp_digits);
-
-#ifdef NPY_FLOAT128
-npy_uint32
-Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
- npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
- npy_int32 digits_right, npy_int32 exp_digits);
-#endif
+PyObject *
+Dragon4_Scientific(PyObject *obj, npy_bool unique, int precision, int sign,
+ TrimMode trim, int pad_left, int exp_digits);
#endif
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index 499ec343c..9ee53362e 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -37,6 +37,7 @@ NPY_NO_EXPORT int NPY_NUMUSERTYPES = 0;
#include "arrayobject.h"
#include "hashdescr.h"
#include "descriptor.h"
+#include "dragon4.h"
#include "calculation.h"
#include "number.h"
#include "scalartypes.h"
@@ -3583,14 +3584,156 @@ as_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
#undef _test_code
+
+/*
+ * Prints floating-point scalars usign the Dragon4 algorithm, scientific mode.
+ * Arguments:
+ * x - a numpy scalar of Floating type
+ * precision - number of fractional digits to show. In unique mode, can be
+ * ommited and the unique repr will be returned, otherwise the
+ * unique value will be truncated to this number of digits
+ * (breaking the uniqueness guarantee). In fixed mode, is
+ * required, and specifies the number of fractional digits to
+ * print.
+ * unique - whether to use unique (default) or fixed mode.
+ * sign - whether to show the sign for positive values. Default False
+ * trim - one of 'k', '.', '0', '-' to control trailing digits, as follows:
+ * k : don't trim zeros, always leave a decimal point
+ * . : trim all but the zero before the decimal point
+ * 0 : trim all trailing zeros, leave decimal point
+ * - : trim trailing zeros and a trailing decimal point
+ * Default is k.
+ * pad_left - pads left side of string with whitespace until at least
+ * this many characters are to the left of the decimal point. If
+ * -1, don't add any padding. Default -1.
+ * exp_digits - exponent will contain at least this many digits, padding
+ * with 0 if necessary. -1 means pad to 2. Maximum of 5.
+ */
+static PyObject *
+dragon4_scientific(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+ static char *kwlist[] = {"x", "precision", "unique", "sign", "trim",
+ "pad_left", "exp_digits", NULL};
+ int precision=-1, pad_left=-1, exp_digits=-1;
+ char *trimstr=NULL;
+ TrimMode trim = TrimMode_None;
+ int sign=0, unique=1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiisii", kwlist,
+ &obj, &precision, &unique, &sign, &trimstr, &pad_left,
+ &exp_digits)) {
+ return NULL;
+ }
+
+ if (trimstr != NULL) {
+ if (strcmp(trimstr, "k") == 0) {
+ trim = TrimMode_None;
+ }
+ else if (strcmp(trimstr, ".") == 0) {
+ trim = TrimMode_Zeros;
+ }
+ else if (strcmp(trimstr, "0") == 0) {
+ trim = TrimMode_LeaveOneZero;
+ }
+ else if (strcmp(trimstr, "-") == 0) {
+ trim = TrimMode_DptZeros;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "if supplied, trim must be 'k', '.', '0' or '-'");
+ return NULL;
+ }
+ }
+
+ if (unique == 0 && precision < 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "in non-unique mode `precision` must be supplied");
+ return NULL;
+ }
+
+ return Dragon4_Scientific(obj, unique, precision, sign,
+ trim, pad_left, exp_digits);
+}
+
+/*
+ * Prints floating-point scalars usign the Dragon4 algorithm, positional mode.
+ * Arguments:
+ * x - a numpy scalar of Floating type
+ * precision - number of fractional digits to show. In unique mode, can be
+ * ommited and the unique repr will be returned, otherwise the
+ * unique value will be truncated to this number of digits
+ * (breaking the uniqueness guarantee). In fixed mode, is
+ * required, and specifies the number of fractional digits to
+ * print.
+ * unique - whether to use unique (default) or fixed mode.
+ * sign - whether to show the sign for positive values. Default False
+ * trim - one of 'k', '.', '0', '-' to control trailing digits, as follows:
+ * k : don't trim zeros, always leave a decimal point
+ * . : trim all but the zero before the decimal point
+ * 0 : trim all trailing zeros, leave decimal point
+ * - : trim trailing zeros and a trailing decimal point
+ * Default is k.
+ * pad_left - pads left side of string with whitespace until at least
+ * this many characters are to the left of the decimal point. If
+ * -1, don't add any padding. Default -1.
+ * pad_right - pads right side of string with whitespace until at least
+ * this many characters are to the right of the decimal point. If
+ * -1, don't add any padding. Default -1.
+ */
+static PyObject *
+dragon4_positional(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+ static char *kwlist[] = {"x", "precision", "unique", "sign", "trim",
+ "pad_left", "pad_right", NULL};
+ int precision=-1, pad_left=-1, pad_right=-1;
+ char *trimstr=NULL;
+ TrimMode trim = TrimMode_None;
+ int sign=0, unique=1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiisii", kwlist,
+ &obj, &precision, &unique, &sign, &trimstr, &pad_left,
+ &pad_right)) {
+ return NULL;
+ }
+
+ if (trimstr != NULL) {
+ if (strcmp(trimstr, "k") == 0) {
+ trim = TrimMode_None;
+ }
+ else if (strcmp(trimstr, ".") == 0) {
+ trim = TrimMode_Zeros;
+ }
+ else if (strcmp(trimstr, "0") == 0) {
+ trim = TrimMode_LeaveOneZero;
+ }
+ else if (strcmp(trimstr, "-") == 0) {
+ trim = TrimMode_DptZeros;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "if supplied, trim must be 'k', '.', '0' or '-'");
+ return NULL;
+ }
+ }
+
+ if (unique == 0 && precision < 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "in non-unique mode `precision` must be supplied");
+ return NULL;
+ }
+
+ return Dragon4_Positional(obj, unique, precision, sign,
+ trim, pad_left, pad_right);
+}
+
static PyObject *
format_longfloat(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
{
PyObject *obj;
unsigned int precision;
- npy_longdouble x;
static char *kwlist[] = {"x", "precision", NULL};
- static char repr[100];
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OI:format_longfloat", kwlist,
&obj, &precision)) {
@@ -3601,12 +3744,8 @@ format_longfloat(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
"not a longfloat");
return NULL;
}
- x = ((PyLongDoubleScalarObject *)obj)->obval;
- if (precision > 70) {
- precision = 70;
- }
- format_longdouble(repr, 100, x, precision);
- return PyUString_FromString(repr);
+ return Dragon4_Scientific(obj, precision, 0, 1, TrimMode_LeaveOneZero,
+ -1, -1);
}
static PyObject *
@@ -4289,6 +4428,12 @@ static struct PyMethodDef array_module_methods[] = {
{"format_longfloat",
(PyCFunction)format_longfloat,
METH_VARARGS | METH_KEYWORDS, NULL},
+ {"dragon4_positional",
+ (PyCFunction)dragon4_positional,
+ METH_VARARGS | METH_KEYWORDS, NULL},
+ {"dragon4_scientific",
+ (PyCFunction)dragon4_scientific,
+ METH_VARARGS | METH_KEYWORDS, NULL},
{"compare_chararrays",
(PyCFunction)compare_chararrays,
METH_VARARGS | METH_KEYWORDS, NULL},