Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d6a9f0

Browse files
committed
Merge pull request #6199 from aarchiba/longdouble_scanf
BUG 4381 Longdouble from string without precision loss
2 parents b478ded + 815fee6 commit 5d6a9f0

File tree

10 files changed

+490
-22
lines changed

10 files changed

+490
-22
lines changed

numpy/core/setup_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def check_api_version(apiversion, codegen_dir):
104104
OPTIONAL_STDFUNCS = ["expm1", "log1p", "acosh", "asinh", "atanh",
105105
"rint", "trunc", "exp2", "log2", "hypot", "atan2", "pow",
106106
"copysign", "nextafter", "ftello", "fseeko",
107-
"strtoll", "strtoull", "cbrt"]
107+
"strtoll", "strtoull", "cbrt", "strtold_l",]
108108

109109

110110
OPTIONAL_HEADERS = [

numpy/core/src/multiarray/arraytypes.c.src

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
#include "npy_cblas.h"
3434
#include <limits.h>
3535

36-
3736
/*
3837
*****************************************************************************
3938
** PYTHON TYPES TO C TYPES **
@@ -309,6 +308,54 @@ static int
309308

310309
/**end repeat**/
311310

311+
static NPY_INLINE npy_longdouble
312+
string_to_long_double(PyObject*op)
313+
{
314+
char *s;
315+
char *end;
316+
npy_longdouble temp;
317+
PyObject* b;
318+
319+
if (PyUnicode_Check(op)) {
320+
b = PyUnicode_AsUTF8String(op);
321+
if (!b) {
322+
return 0;
323+
}
324+
}
325+
else {
326+
b = op;
327+
Py_XINCREF(b);
328+
}
329+
s = PyBytes_AsString(b);
330+
if (s) {
331+
errno = 0;
332+
temp = NumPyOS_ascii_strtold(s, &end);
333+
if (end==s || *end) {
334+
PyErr_Format(PyExc_ValueError,
335+
"invalid literal for long double: %s",
336+
s);
337+
Py_XDECREF(b);
338+
return 0;
339+
}
340+
else if (errno) {
341+
PyErr_Format(PyExc_ValueError,
342+
"invalid literal for long double: %s (%s)",
343+
s,
344+
strerror(errno));
345+
Py_XDECREF(b);
346+
return 0;
347+
}
348+
Py_XDECREF(b);
349+
}
350+
else {
351+
/* Probably wasn't a string, try converting it via a python double */
352+
PyErr_Clear();
353+
Py_XDECREF(b);
354+
temp = (npy_longdouble) MyPyFloat_AsDouble(op);
355+
}
356+
return temp;
357+
}
358+
312359
/*
313360
* These return array scalars which are different than other date-types.
314361
*/
@@ -330,7 +377,11 @@ LONGDOUBLE_setitem(PyObject *op, void *ov, void *vap)
330377
temp = ((PyLongDoubleScalarObject *)op)->obval;
331378
}
332379
else {
333-
temp = (npy_longdouble) MyPyFloat_AsDouble(op);
380+
/* In case something funny happened in PyArray_IsScalar */
381+
if (PyErr_Occurred()) {
382+
return -1;
383+
}
384+
temp = string_to_long_double(op);
334385
}
335386
if (PyErr_Occurred()) {
336387
return -1;
@@ -1572,8 +1623,8 @@ static int
15721623
/**end repeat**/
15731624

15741625
/**begin repeat
1575-
* #fname = FLOAT, DOUBLE, LONGDOUBLE#
1576-
* #type = npy_float, npy_double, npy_longdouble#
1626+
* #fname = FLOAT, DOUBLE#
1627+
* #type = npy_float, npy_double#
15771628
*/
15781629
static int
15791630
@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore),
@@ -1588,6 +1639,18 @@ static int
15881639
}
15891640
/**end repeat**/
15901641

1642+
static int
1643+
LONGDOUBLE_scan(FILE *fp, npy_longdouble *ip, void *NPY_UNUSED(ignore),
1644+
PyArray_Descr *NPY_UNUSED(ignored))
1645+
{
1646+
long double result;
1647+
int ret;
1648+
1649+
ret = NumPyOS_ascii_ftoLf(fp, &result);
1650+
*ip = (npy_longdouble) result;
1651+
return ret;
1652+
}
1653+
15911654
static int
15921655
HALF_scan(FILE *fp, npy_half *ip, void *NPY_UNUSED(ignore),
15931656
PyArray_Descr *NPY_UNUSED(ignored))
@@ -1675,8 +1738,8 @@ static int
16751738

16761739
/**begin repeat
16771740
*
1678-
* #fname = FLOAT, DOUBLE, LONGDOUBLE#
1679-
* #type = npy_float, npy_double, npy_longdouble#
1741+
* #fname = FLOAT, DOUBLE#
1742+
* #type = npy_float, npy_double#
16801743
*/
16811744
static int
16821745
@fname@_fromstr(char *str, void *ip, char **endptr,
@@ -1690,6 +1753,17 @@ static int
16901753
}
16911754
/**end repeat**/
16921755

1756+
static int
1757+
LONGDOUBLE_fromstr(char *str, void *ip, char **endptr,
1758+
PyArray_Descr *NPY_UNUSED(ignore))
1759+
{
1760+
long double result;
1761+
1762+
result = NumPyOS_ascii_strtold(str, endptr);
1763+
*(npy_longdouble *)ip = result;
1764+
return 0;
1765+
}
1766+
16931767
static int
16941768
HALF_fromstr(char *str, void *ip, char **endptr,
16951769
PyArray_Descr *NPY_UNUSED(ignore))

numpy/core/src/multiarray/convert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format)
171171
/*
172172
* standard writing
173173
*/
174-
strobj = PyObject_Str(obj);
174+
strobj = PyObject_Repr(obj);
175175
Py_DECREF(obj);
176176
if (strobj == NULL) {
177177
Py_DECREF(it);

numpy/core/src/multiarray/ctors.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,18 @@ static int
4545
fromstr_next_element(char **s, void *dptr, PyArray_Descr *dtype,
4646
const char *end)
4747
{
48-
int r = dtype->f->fromstr(*s, dptr, s, dtype);
48+
char *e = *s;
49+
int r = dtype->f->fromstr(*s, dptr, &e, dtype);
50+
/*
51+
* fromstr always returns 0 for basic dtypes
52+
* s points to the end of the parsed string
53+
* if an error occurs s is not changed
54+
*/
55+
if (*s == e) {
56+
/* Nothing read */
57+
return -1;
58+
}
59+
*s = e;
4960
if (end != NULL && *s > end) {
5061
return -1;
5162
}
@@ -57,7 +68,14 @@ fromfile_next_element(FILE **fp, void *dptr, PyArray_Descr *dtype,
5768
void *NPY_UNUSED(stream_data))
5869
{
5970
/* the NULL argument is for backwards-compatibility */
60-
return dtype->f->scanfunc(*fp, dptr, NULL, dtype);
71+
int r = dtype->f->scanfunc(*fp, dptr, NULL, dtype);
72+
/* r can be EOF or the number of items read (0 or 1) */
73+
if (r == 1) {
74+
return 0;
75+
}
76+
else {
77+
return -1;
78+
}
6179
}
6280

6381
/*
@@ -3279,6 +3297,7 @@ array_from_text(PyArray_Descr *dtype, npy_intp num, char *sep, size_t *nread,
32793297
dptr = PyArray_DATA(r);
32803298
for (i= 0; num < 0 || i < num; i++) {
32813299
if (next(&stream, dptr, dtype, stream_data) < 0) {
3300+
/* EOF */
32823301
break;
32833302
}
32843303
*nread += 1;

0 commit comments

Comments
 (0)