summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/arrayprint.py67
-rw-r--r--numpy/core/src/multiarray/dragon4.c252
-rw-r--r--numpy/core/src/multiarray/dragon4.h35
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c80
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src19
-rw-r--r--numpy/core/tests/test_getlimits.py2
6 files changed, 223 insertions, 232 deletions
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py
index 8253713be..bceb5db27 100644
--- a/numpy/core/arrayprint.py
+++ b/numpy/core/arrayprint.py
@@ -718,6 +718,7 @@ class FloatingFormat(object):
if self.floatmode == 'fixed':
trim, unique = 'k', False
strs = (dragon4_positional(x, precision=self.precision,
+ fractional=True,
unique=unique, trim=trim,
sign=self.sign == '+')
for x in non_zero)
@@ -757,15 +758,20 @@ class FloatingFormat(object):
return ' '*(self.pad_left + self.pad_right + 1 - len(ret)) + ret
if self.exp_format:
- return dragon4_scientific(x, precision=self.precision,
+ return dragon4_scientific(x,
+ precision=self.precision,
unique=self.unique,
- trim=self.trim, sign=self.sign == '+',
+ trim=self.trim,
+ sign=self.sign == '+',
pad_left=self.pad_left,
exp_digits=self.exp_size)
else:
- return dragon4_positional(x, precision=self.precision,
+ return dragon4_positional(x,
+ precision=self.precision,
unique=self.unique,
- trim=self.trim, sign=self.sign == '+',
+ fractional=True,
+ trim=self.trim,
+ sign=self.sign == '+',
pad_left=self.pad_left,
pad_right=self.pad_right)
@@ -773,7 +779,7 @@ class FloatingFormat(object):
def format_float_scientific(x, precision=None, unique=True, trim='k',
sign=False, pad_left=None, exp_digits=None):
"""
- Format a floating-point scalar as a string in fractional notation.
+ Format a floating-point scalar as a string in scientific notation.
Provides control over rounding, trimming and padding. Uses and assumes
IEEE unbiased rounding. Uses the "Dragon4" algorithm.
@@ -783,18 +789,17 @@ def format_float_scientific(x, precision=None, unique=True, trim='k',
x : python float or numpy floating scalar
Value to format.
precision : non-negative integer, optional
- Maximum number of fractional digits to print. May be ommited
- if `unique` is `True`, but is required if unique is `False`.
+ Maximum number of fractional digits to print. May be omitted if
+ `unique` is `True`, but is required if unique is `False`.
unique : boolean, optional
- If `False`, output exactly `precision` fractional digits and round the
- remaining value. Digits are generated as if printing an
- infinite-precision value and stopping after `precision` digits.
If `True`, use a digit-generation strategy which gives the shortest
representation which uniquely identifies the floating-point number from
other values of the same type, by judicious rounding. If `precision`
- was omitted, print out the full unique representation, otherwise digit
- generation is cut off after `precision` digits and the remaining value
- is rounded.
+ was omitted, print all necessary digits, otherwise digit generation is
+ cut off after `precision` digits and the remaining value is rounded.
+ If `False`, digits are generated as if printing an infinite-precision
+ value and stopping after `precision` digits, rounding the remaining
+ value.
trim : one of 'k', '.', '0', '-', optional
Controls post-processing trimming of trailing digits, as follows:
k : keep trailing zeros, keep decimal point (no trimming)
@@ -833,16 +838,17 @@ def format_float_scientific(x, precision=None, unique=True, trim='k',
precision = -1 if precision is None else precision
pad_left = -1 if pad_left is None else pad_left
exp_digits = -1 if exp_digits is None else exp_digits
- return dragon4_scientific(x, precision=precision, unique=unique, trim=trim,
- sign=sign, pad_left=pad_left,
+ return dragon4_scientific(x, precision=precision, unique=unique,
+ trim=trim, sign=sign, pad_left=pad_left,
exp_digits=exp_digits)
-def format_float_positional(x, precision=None, unique=True, trim='k',
- sign=False, pad_left=None, pad_right=None):
+def format_float_positional(x, precision=None, unique=True,
+ fractional=True, trim='k', sign=False,
+ pad_left=None, pad_right=None):
"""
- Format a floating-point scalar as a string in scientific notation.
+ Format a floating-point scalar as a string in positional notation.
- Provides control over rounding, trimming and padding. Uses and assumes
+ Provides control over rounding, trimming and padding. Uses and assumes
IEEE unbiased rounding. Uses the "Dragon4" algorithm.
Parameters
@@ -850,18 +856,22 @@ def format_float_positional(x, precision=None, unique=True, trim='k',
x : python float or numpy floating scalar
Value to format.
precision : non-negative integer, optional
- Maximum number of fractional digits to print. May be ommited
- if `unique` is `True`, but is required if unique is `False`.
+ Maximum number of digits to print. May be omitted if `unique` is
+ `True`, but is required if unique is `False`.
unique : boolean, optional
- If `False`, output exactly `precision` fractional digits and round the
- remaining value. Digits are generated as if printing an
- infinite-precision value and stopping after `precision` digits.
If `True`, use a digit-generation strategy which gives the shortest
representation which uniquely identifies the floating-point number from
other values of the same type, by judicious rounding. If `precision`
- was omitted, print out the full unique representation, otherwise digit
- generation is cut off after `precision` digits and the remaining value
- is rounded.
+ was omitted, print out all necessary digits, otherwise digit generation
+ is cut off after `precision` digits and the remaining value is rounded.
+ If `False`, digits are generated as if printing an infinite-precision
+ value and stopping after `precision` digits, rounding the remaining
+ value.
+ fractional : boolean, optional
+ If `True`, the cutoff of `precision` digits refers to the total number
+ of digits after the decimal point, including leading zeros.
+ If `False`, `precision` refers to the total number of significant
+ digits, before or after the decimal point, ignoring leading zeros.
trim : one of 'k', '.', '0', '-', optional
Controls post-processing trimming of trailing digits, as follows:
k : keep trailing zeros, keep decimal point (no trimming)
@@ -901,7 +911,8 @@ def format_float_positional(x, precision=None, unique=True, trim='k',
precision = -1 if precision is None else precision
pad_left = -1 if pad_left is None else pad_left
pad_right = -1 if pad_right is None else pad_right
- return dragon4_positional(x, precision=precision, unique=unique, trim=trim,
+ return dragon4_positional(x, precision=precision, unique=unique,
+ fractional=fractional, trim=trim,
sign=sign, pad_left=pad_left,
pad_right=pad_right)
diff --git a/numpy/core/src/multiarray/dragon4.c b/numpy/core/src/multiarray/dragon4.c
index ab0741932..4bd055817 100644
--- a/numpy/core/src/multiarray/dragon4.c
+++ b/numpy/core/src/multiarray/dragon4.c
@@ -35,8 +35,12 @@
#include <string.h>
#include <assert.h>
-/* #define DEBUG_ASSERT(stmnt) assert(stmnt) */
+
+#if 0
+#define DEBUG_ASSERT(stmnt) assert(stmnt)
+#else
#define DEBUG_ASSERT(stmnt) {}
+#endif
/*
* Get the log base 2 of a 32-bit unsigned integer.
@@ -951,28 +955,6 @@ BigInt_ShiftLeft(BigInt *result, npy_uint32 shift)
}
}
-typedef enum CutoffMode
-{
- /*
- * As many digits as necessary to print a uniquely identifiable number.
- * cutoffNumber should be -1.
- */
- CutoffMode_Unique,
- /* up to cutoffNumber significant digits */
- CutoffMode_TotalLength,
- /* up to cutoffNumber significant digits past the decimal point */
- CutoffMode_FractionLength,
- /*
- * up to cutoffNumber digits, or fewer if the number can be uniquely
- * identified with fewer
- */
- CutoffMode_MaxTotalUnique,
- /*
- * up to cutoffNumber digits pas decimal point, or fewer if the number can
- * be uniquely identified with fewer
- */
- CutoffMode_MaxFractionUnique,
-} CutoffMode;
/*
* This is an implementation the Dragon4 algorithm to convert a binary number in
@@ -1029,7 +1011,8 @@ typedef enum CutoffMode
static npy_uint32
Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
const npy_uint32 mantissaBit, const npy_bool hasUnequalMargins,
- const CutoffMode cutoffMode, npy_int32 cutoffNumber, char *pOutBuffer,
+ const DigitMode digitMode, const CutoffMode cutoffMode,
+ npy_int32 cutoffNumber, char *pOutBuffer,
npy_uint32 bufferSize, npy_int32 *pOutExponent)
{
char *curDigit = pOutBuffer;
@@ -1053,7 +1036,7 @@ Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
BigInt optionalMarginHigh;
const npy_float64 log10_2 = 0.30102999566398119521373889472449;
- npy_int32 digitExponent, cutoffExponent, desiredCutoffExponent, hiBlock;
+ npy_int32 digitExponent, cutoffExponent, hiBlock;
npy_uint32 outputDigit; /* current digit being output */
npy_uint32 outputLen;
npy_bool isEven = (mantissa % 2) == 0;
@@ -1187,8 +1170,7 @@ Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
* increases the number. This will either correct digitExponent to an
* accurate value or it will clamp it above the accurate value.
*/
- if ( (cutoffMode == CutoffMode_FractionLength ||
- cutoffMode == CutoffMode_MaxFractionUnique) &&
+ if (cutoffNumber >= 0 && cutoffMode == CutoffMode_FractionLength &&
digitExponent <= -cutoffNumber) {
digitExponent = -cutoffNumber + 1;
}
@@ -1247,29 +1229,24 @@ Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
* Default to the maximum size of the output buffer.
*/
cutoffExponent = digitExponent - bufferSize;
- switch(cutoffMode) {
- /* print digits until we pass the accuracy margin or buffer size */
- case CutoffMode_Unique:
- DEBUG_ASSERT(cutoffNumber == -1);
- break;
- /* print cutoffNumber of digits or until we reach the buffer size */
- case CutoffMode_MaxTotalUnique:
- case CutoffMode_TotalLength:
+ if (cutoffNumber >= 0) {
+ npy_int32 desiredCutoffExponent;
+
+ if (cutoffMode == CutoffMode_TotalLength) {
desiredCutoffExponent = digitExponent - cutoffNumber;
if (desiredCutoffExponent > cutoffExponent) {
cutoffExponent = desiredCutoffExponent;
}
- break;
- /* print cutoffNumber digits past the decimal point or until we reach
- * the buffer size
+ }
+ /* Otherwise it's CutoffMode_FractionLength. Print cutoffNumber digits
+ * past the decimal point or until we reach the buffer size
*/
- case CutoffMode_MaxFractionUnique:
- case CutoffMode_FractionLength:
+ else {
desiredCutoffExponent = -cutoffNumber;
if (desiredCutoffExponent > cutoffExponent) {
cutoffExponent = desiredCutoffExponent;
}
- break;
+ }
}
/* Output the exponent of the first digit we will print */
@@ -1311,9 +1288,7 @@ Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
}
}
- if (cutoffMode == CutoffMode_Unique ||
- cutoffMode == CutoffMode_MaxFractionUnique ||
- cutoffMode == CutoffMode_MaxTotalUnique) {
+ if (digitMode == DigitMode_Unique) {
/*
* For the unique cutoff mode, we will try to print until we have
* reached a level of precision that uniquely distinguishes this value
@@ -1358,7 +1333,7 @@ Dragon4(const npy_uint64 mantissa, const npy_int32 exponent,
}
else {
/*
- * For length based cutoff modes, we will try to print until we
+ * For exact digit mode, we will try to print until we
* have exhausted all precision (i.e. all remaining digits are zeros) or
* until we reach the desired cutoff digit.
*/
@@ -1607,31 +1582,22 @@ typedef union FloatUnion80
static npy_uint32
FormatPositional(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
npy_int32 exponent, char signbit, npy_uint32 mantissaBit,
- npy_bool hasUnequalMargins, npy_bool unique,
- npy_int32 precision, TrimMode trim_mode,
- npy_int32 digits_left, npy_int32 digits_right)
+ npy_bool hasUnequalMargins, DigitMode digit_mode,
+ CutoffMode cutoff_mode, npy_int32 precision,
+ TrimMode trim_mode, npy_int32 digits_left,
+ npy_int32 digits_right)
{
npy_int32 printExponent;
npy_int32 numDigits, numWholeDigits, has_sign=0;
npy_int32 maxPrintLen = bufferSize - 1, pos = 0;
- CutoffMode cutoffMode;
/* track the # of digits past the decimal point that have been printed */
npy_int32 numFractionDigits = 0;
DEBUG_ASSERT(bufferSize > 0);
- if (unique) {
- if (precision < 0) {
- cutoffMode = CutoffMode_Unique;
- }
- else {
- cutoffMode = CutoffMode_MaxFractionUnique;
- }
- }
- else {
- cutoffMode = CutoffMode_FractionLength;
+ if (digit_mode != DigitMode_Unique) {
DEBUG_ASSERT(precision >= 0);
}
@@ -1645,7 +1611,7 @@ FormatPositional(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
}
numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins,
- cutoffMode, precision, buffer + has_sign,
+ digit_mode, cutoff_mode, precision, buffer + has_sign,
maxPrintLen - has_sign, &printExponent);
DEBUG_ASSERT(numDigits > 0);
@@ -1752,7 +1718,7 @@ FormatPositional(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
}
}
else if (trim_mode == TrimMode_None &&
- cutoffMode != CutoffMode_MaxFractionUnique &&
+ digit_mode != DigitMode_Unique &&
precision > (npy_int32)numFractionDigits && pos < maxPrintLen) {
/* add trailing zeros up to precision length */
/* compute the number of trailing zeros needed */
@@ -1848,7 +1814,7 @@ FormatPositional(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
static npy_uint32
FormatScientific (char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
npy_int32 exponent, char signbit, npy_uint32 mantissaBit,
- npy_bool hasUnequalMargins, npy_bool unique,
+ npy_bool hasUnequalMargins, DigitMode digit_mode,
npy_int32 precision, TrimMode trim_mode,
npy_int32 digits_left, npy_int32 exp_digits)
{
@@ -1857,21 +1823,12 @@ FormatScientific (char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
char *pCurOut;
npy_int32 numFractionDigits;
npy_int32 leftchars;
- CutoffMode cutoffMode;
- if (unique) {
- if (precision < 0) {
- cutoffMode = CutoffMode_Unique;
- }
- else {
- cutoffMode = CutoffMode_MaxTotalUnique;
- }
- }
- else {
- cutoffMode = CutoffMode_TotalLength;
+ if (digit_mode != DigitMode_Unique) {
DEBUG_ASSERT(precision >= 0);
}
+
DEBUG_ASSERT(bufferSize > 0);
pCurOut = buffer;
@@ -1899,8 +1856,8 @@ FormatScientific (char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
}
numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins,
- cutoffMode, precision + 1, pCurOut, bufferSize,
- &printExponent);
+ digit_mode, CutoffMode_TotalLength, precision + 1,
+ pCurOut, bufferSize, &printExponent);
DEBUG_ASSERT(numDigits > 0);
DEBUG_ASSERT(numDigits <= bufferSize);
@@ -1943,7 +1900,7 @@ FormatScientific (char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
}
}
else if (trim_mode == TrimMode_None &&
- cutoffMode != CutoffMode_MaxTotalUnique) {
+ digit_mode != DigitMode_Unique) {
/* add trailing zeros up to precision length */
if (precision > (npy_int32)numFractionDigits) {
char *pEnd;
@@ -2148,7 +2105,8 @@ PrintInfNan(char *buffer, npy_uint32 bufferSize, npy_uint64 mantissa,
*/
static npy_uint32
Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
+ npy_bool scientific, DigitMode digit_mode,
+ CutoffMode cutoff_mode, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
npy_int32 digits_right, npy_int32 exp_digits)
{
@@ -2231,20 +2189,21 @@ Dragon4_PrintFloat16(char *buffer, npy_uint32 bufferSize, npy_uint16 value,
/* format the value */
if (scientific) {
return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
+ mantissaBit, hasUnequalMargins, digit_mode,
precision, trim_mode, digits_left, exp_digits);
}
else {
return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
- precision, trim_mode,
+ mantissaBit, hasUnequalMargins, digit_mode,
+ cutoff_mode, precision, trim_mode,
digits_left, digits_right);
}
}
static npy_uint32
Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
+ npy_bool scientific, DigitMode digit_mode,
+ CutoffMode cutoff_mode, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
npy_int32 digits_right, npy_int32 exp_digits)
{
@@ -2327,20 +2286,21 @@ Dragon4_PrintFloat32(char *buffer, npy_uint32 bufferSize, npy_float32 value,
/* format the value */
if (scientific) {
return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
+ mantissaBit, hasUnequalMargins, digit_mode,
precision, trim_mode, digits_left, exp_digits);
}
else {
return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
- precision, trim_mode,
+ mantissaBit, hasUnequalMargins, digit_mode,
+ cutoff_mode, precision, trim_mode,
digits_left, digits_right);
}
}
static npy_uint32
Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
+ npy_bool scientific, DigitMode digit_mode,
+ CutoffMode cutoff_mode, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
npy_int32 digits_right, npy_int32 exp_digits)
{
@@ -2424,20 +2384,21 @@ Dragon4_PrintFloat64(char *buffer, npy_uint32 bufferSize, npy_float64 value,
/* format the value */
if (scientific) {
return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
+ mantissaBit, hasUnequalMargins, digit_mode,
precision, trim_mode, digits_left, exp_digits);
}
else {
return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
- precision, trim_mode,
+ mantissaBit, hasUnequalMargins, digit_mode,
+ cutoff_mode, precision, trim_mode,
digits_left, digits_right);
}
}
static npy_uint32
Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value,
- npy_bool scientific, npy_bool unique, npy_int32 precision,
+ npy_bool scientific, DigitMode digit_mode,
+ CutoffMode cutoff_mode, npy_int32 precision,
npy_bool sign, TrimMode trim_mode, npy_int32 digits_left,
npy_int32 digits_right, npy_int32 exp_digits)
{
@@ -2519,23 +2480,23 @@ Dragon4_PrintFloat128(char *buffer, npy_uint32 bufferSize, FloatVal128 value,
/* format the value */
if (scientific) {
return FormatScientific(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
+ mantissaBit, hasUnequalMargins, digit_mode,
precision, trim_mode, digits_left, exp_digits);
}
else {
return FormatPositional(buffer, bufferSize, mantissa, exponent, signbit,
- mantissaBit, hasUnequalMargins, unique,
- precision, trim_mode,
+ mantissaBit, hasUnequalMargins, digit_mode,
+ cutoff_mode, precision, trim_mode,
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)
+Dragon4_Positional_AnySize(void *val, size_t size, DigitMode digit_mode,
+ CutoffMode cutoff_mode, 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 */
@@ -2554,15 +2515,18 @@ Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
switch (size) {
case 2:
Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val,
- 0, unique, precision, sign, trim, pad_left, pad_right, -1);
+ 0, digit_mode, cutoff_mode, 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);
+ 0, digit_mode, cutoff_mode, 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);
+ 0, digit_mode, cutoff_mode, precision,
+ sign, trim, pad_left, pad_right, -1);
break;
#ifdef NPY_FLOAT80
case 10:
@@ -2570,7 +2534,8 @@ Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 0, digit_mode, cutoff_mode, precision,
+ sign, trim, pad_left, pad_right, -1);
break;
#endif
#ifdef NPY_FLOAT96
@@ -2579,7 +2544,8 @@ Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 0, digit_mode, cutoff_mode, precision,
+ sign, trim, pad_left, pad_right, -1);
break;
#endif
#ifdef NPY_FLOAT128
@@ -2588,7 +2554,8 @@ Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 0, digit_mode, cutoff_mode, precision,
+ sign, trim, pad_left, pad_right, -1);
break;
#endif
default:
@@ -2600,42 +2567,48 @@ Dragon4_Positional_AnySize(void *val, size_t size, npy_bool unique,
}
PyObject *
-Dragon4_Positional(PyObject *obj, npy_bool unique, int precision, int sign,
- TrimMode trim, int pad_left, int pad_right)
+Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode,
+ 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);
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_half),
+ digit_mode, cutoff_mode, 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);
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_float),
+ digit_mode, cutoff_mode, 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);
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_double),
+ digit_mode, cutoff_mode, 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);
+ return Dragon4_Positional_AnySize(&x, sizeof(npy_longdouble),
+ digit_mode, cutoff_mode, 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);
+ return Dragon4_Positional_AnySize(&val, sizeof(double),
+ digit_mode, cutoff_mode, precision,
+ sign, trim, pad_left, pad_right);
}
PyObject *
-Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
+Dragon4_Scientific_AnySize(void *val, size_t size, DigitMode digit_mode,
int precision, int sign, TrimMode trim,
int pad_left, int exp_digits)
{
@@ -2652,19 +2625,24 @@ Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
FloatUnion128 buf128;
#endif
+ /* dummy, is ignored in scientific mode */
+ CutoffMode cutoff_mode = CutoffMode_TotalLength;
switch (size) {
case 2:
Dragon4_PrintFloat16(repr, sizeof(repr), *(npy_float16*)val,
- 1, unique, precision, sign, trim, pad_left, -1, exp_digits);
+ 1, digit_mode, cutoff_mode, 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);
+ 1, digit_mode, cutoff_mode, 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);
+ 1, digit_mode, cutoff_mode, precision, sign,
+ trim, pad_left, -1, exp_digits);
break;
#ifdef NPY_FLOAT80
case 10:
@@ -2672,7 +2650,8 @@ Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 1, digit_mode, cutoff_mode, precision, sign,
+ trim, pad_left, -1, exp_digits);
break;
#endif
#ifdef NPY_FLOAT96
@@ -2681,7 +2660,8 @@ Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 1, digit_mode, cutoff_mode, precision, sign,
+ trim, pad_left, -1, exp_digits);
break;
#endif
#ifdef NPY_FLOAT128
@@ -2690,7 +2670,8 @@ Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
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);
+ 1, digit_mode, cutoff_mode, precision, sign,
+ trim, pad_left, -1, exp_digits);
break;
#endif
default:
@@ -2702,36 +2683,41 @@ Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
}
PyObject *
-Dragon4_Scientific(PyObject *obj, npy_bool unique, int precision, int sign,
- TrimMode trim, int pad_left, int exp_digits)
+Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, 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);
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_half),
+ digit_mode, 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);
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_float),
+ digit_mode, 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);
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_double),
+ digit_mode, 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);
+ return Dragon4_Scientific_AnySize(&x, sizeof(npy_longdouble),
+ digit_mode, 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);
+ return Dragon4_Scientific_AnySize(&val, sizeof(double),
+ digit_mode, precision,
+ sign, trim, pad_left, exp_digits);
}
diff --git a/numpy/core/src/multiarray/dragon4.h b/numpy/core/src/multiarray/dragon4.h
index 814c84a2f..5559c5157 100644
--- a/numpy/core/src/multiarray/dragon4.h
+++ b/numpy/core/src/multiarray/dragon4.h
@@ -40,6 +40,22 @@
#include "npy_pycompat.h"
#include "numpy/arrayscalars.h"
+typedef enum DigitMode
+{
+ /* Round digits to print shortest uniquely identifiable number. */
+ DigitMode_Unique,
+ /* Output the digits of the number as if with infinite precision */
+ DigitMode_Exact,
+} DigitMode;
+
+typedef enum CutoffMode
+{
+ /* up to cutoffNumber significant digits */
+ CutoffMode_TotalLength,
+ /* up to cutoffNumber significant digits past the decimal point */
+ CutoffMode_FractionLength,
+} CutoffMode;
+
typedef enum TrimMode
{
TrimMode_None, /* don't trim zeros, always leave a decimal point */
@@ -49,22 +65,23 @@ typedef enum TrimMode
} 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);
+Dragon4_Positional_AnySize(void *val, size_t size, DigitMode digit_mode,
+ CutoffMode cutoff_mode, int precision, int sign,
+ TrimMode trim, int pad_left, int pad_right);
PyObject *
-Dragon4_Scientific_AnySize(void *val, size_t size, npy_bool unique,
+Dragon4_Scientific_AnySize(void *val, size_t size, DigitMode digit_mode,
int precision, int sign, TrimMode trim,
- int pad_left, int exp_digits);
+ int pad_left, int pad_right);
PyObject *
-Dragon4_Positional(PyObject *obj, npy_bool unique, int precision, int sign,
- TrimMode trim, int pad_left, int pad_right);
+Dragon4_Positional(PyObject *obj, DigitMode digit_mode, CutoffMode cutoff_mode,
+ int precision, int sign, TrimMode trim, int pad_left,
+ int pad_right);
PyObject *
-Dragon4_Scientific(PyObject *obj, npy_bool unique, int precision, int sign,
- TrimMode trim, int pad_left, int exp_digits);
+Dragon4_Scientific(PyObject *obj, DigitMode digit_mode, 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 9ee53362e..81971ad0f 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -3587,27 +3587,9 @@ as_buffer(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
/*
* 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.
+ * See docstring of `np.format_float_scientific` for description of arguments.
+ * The differences is that a value of -1 is valid for pad_left, exp_digits,
+ * precision, which is equivalent to `None`.
*/
static PyObject *
dragon4_scientific(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
@@ -3617,6 +3599,7 @@ dragon4_scientific(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
"pad_left", "exp_digits", NULL};
int precision=-1, pad_left=-1, exp_digits=-1;
char *trimstr=NULL;
+ DigitMode digit_mode;
TrimMode trim = TrimMode_None;
int sign=0, unique=1;
@@ -3646,55 +3629,40 @@ dragon4_scientific(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
}
}
+ digit_mode = unique ? DigitMode_Unique : DigitMode_Exact;
+
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);
+ return Dragon4_Scientific(obj, digit_mode, 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.
+ * See docstring of `np.format_float_positional` for description of arguments.
+ * The differences is that a value of -1 is valid for pad_left, pad_right,
+ * precision, which is equivalent to `None`.
*/
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};
+ static char *kwlist[] = {"x", "precision", "unique", "fractional",
+ "sign", "trim", "pad_left", "pad_right", NULL};
int precision=-1, pad_left=-1, pad_right=-1;
char *trimstr=NULL;
+ CutoffMode cutoff_mode;
+ DigitMode digit_mode;
TrimMode trim = TrimMode_None;
- int sign=0, unique=1;
+ int sign=0, unique=1, fractional=0;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiisii", kwlist,
- &obj, &precision, &unique, &sign, &trimstr, &pad_left,
- &pad_right)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iiiisii", kwlist,
+ &obj, &precision, &unique, &fractional, &sign, &trimstr,
+ &pad_left, &pad_right)) {
return NULL;
}
@@ -3718,13 +3686,17 @@ dragon4_positional(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
}
}
+ digit_mode = unique ? DigitMode_Unique : DigitMode_Exact;
+ cutoff_mode = fractional ? CutoffMode_FractionLength :
+ CutoffMode_TotalLength;
+
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,
+ return Dragon4_Positional(obj, digit_mode, cutoff_mode, precision, sign,
trim, pad_left, pad_right);
}
@@ -3744,8 +3716,8 @@ format_longfloat(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds)
"not a longfloat");
return NULL;
}
- return Dragon4_Scientific(obj, precision, 0, 1, TrimMode_LeaveOneZero,
- -1, -1);
+ return Dragon4_Scientific(obj, DigitMode_Unique, precision, 0,
+ TrimMode_LeaveOneZero, -1, -1);
}
static PyObject *
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index a208c2f73..802d74dec 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -442,15 +442,18 @@ format_@name@(@type@ val, npy_bool scientific,
int pad_left, int pad_right, int exp_digits)
{
if (scientific) {
- return Dragon4_Scientific_AnySize(&val, sizeof(@type@), 1, precision,
- sign, trim, pad_left, exp_digits);
+ return Dragon4_Scientific_AnySize(&val, sizeof(@type@),
+ DigitMode_Unique, precision,
+ sign, trim, pad_left, exp_digits);
}
else {
- return Dragon4_Positional_AnySize(&val, sizeof(@type@), 1, precision,
- sign, trim, pad_left, pad_right);
+ return Dragon4_Positional_AnySize(&val, sizeof(@type@),
+ DigitMode_Unique, CutoffMode_TotalLength, precision,
+ sign, trim, pad_left, pad_right);
}
}
+
/**end repeat**/
/*
@@ -720,6 +723,7 @@ timedeltatype_str(PyObject *self)
/**begin repeat
* #kind = str, repr#
+ * #maxprec = 8, -1#
*/
/**begin repeat1
@@ -728,14 +732,15 @@ timedeltatype_str(PyObject *self)
* #NAME = FLOAT, DOUBLE, LONGDOUBLE#
*/
+/* helper function choose scientific of fractional output, based on a cutoff */
static PyObject *
@name@type_@kind@_either(npy_@name@ val, TrimMode trim_pos, TrimMode trim_sci,
npy_bool sign)
{
- if (val < (npy_@name@)1.e16L) {
- return format_@name@(val, 0, -1, sign, trim_pos, -1, -1, -1);
+ if (val < (npy_@name@)1.e10L) {
+ return format_@name@(val, 0, @maxprec@, sign, trim_pos, -1, -1, -1);
}
- return format_@name@(val, 1, -1, sign, trim_sci, -1, -1, -1);
+ return format_@name@(val, 1, @maxprec@, sign, trim_sci, -1, -1, -1);
}
static PyObject *
diff --git a/numpy/core/tests/test_getlimits.py b/numpy/core/tests/test_getlimits.py
index 361246c7f..455f5257c 100644
--- a/numpy/core/tests/test_getlimits.py
+++ b/numpy/core/tests/test_getlimits.py
@@ -80,7 +80,7 @@ class TestRepr(object):
assert_equal(repr(np.iinfo(np.int16)), expected)
def test_finfo_repr(self):
- expected = "finfo(resolution=0.000001, min=-3.4028235e+38," + \
+ expected = "finfo(resolution=1e-06, min=-3.4028235e+38," + \
" max=3.4028235e+38, dtype=float32)"
assert_equal(repr(np.finfo(np.float32)), expected)