Repository navigation
BUG: clongdouble(str) loses precision during string conversion - #29746
MyUserNameWasTakenLinux wants to merge 1 commit into
Conversation
|
Neat! Just a head's up - longdouble is a bit of an unloved feature. That said, this seems reasonable to support. Some suggestions:
I wonder if the linalg test that is failing is relying on the old broken conversion. Ping @SwayamInSync - you might be interested in this. Swayam has been working on a quad precision DType we're hoping will ultimately allow us to deprecate longdouble support (or at least the float128 alias) in NumPy proper. The fact that longdouble has a subtly different meaning under different architectures is a constant source of bug reports and most users won't need it at all. |
|
Not a full review, but here are a couple issues that should be easy to fix:
|
|
Again not a full review (sorry), but it looks like the failures are because the new |
There was a problem hiding this comment.
Probably should allow parentheses (as CPython, and hence np.cdouble does). Python likes to put parentheses in complex reprs, so I think it is important to handle this case at least, even if you're dropping support for some of the more esoteric bits of the CPython parser, like 1-j and 1_000.
There was a problem hiding this comment.
The parser can handle parentheses now, though I'm not sure if dropping support for 1-j or 1_000 would be okay.
There was a problem hiding this comment.
For the case of 1_000, although it's technically a regression, np.longdouble doesn't support underscores either, so I think it's perfectly reasonable for np.clongdouble not to support them anymore. As for 1-j, CPython says it's for backwards compatibility and may be removed in the future. So in my opinion, probably fine to drop as well. But I do think it would be good to get the opinion of a numpy maintainer.
There was a problem hiding this comment.
Supporting it seems easy enough, I would lean towards just keeping it if it's simple and adding a test that will fail if Python ever breaks it.
But if you don't, at least add a test for it raising!
|
Currently, I'm relying on Python's complex type to deal with Python types as input to |
|
That test specifically excludes It's kinda funny because IIRC running the numpy tests is what was used to determine how small of a limit they could get away with for integer string conversion, and yet the chosen limit is still is a problem even for the numpy tests... |
|
I've added a few tests that cover some of the conversion cases. Please let me know if there is anything you'd like me to change. Something I don't understand is why def test_from_zerodim_array(self):
x = np.zeros(1, dtype=np.clongdouble)
py_val = 2.0 + 3.0j
y = np.array(np.clongdouble(py_val))
x[0] = y
assert np.allclose(complex(x[0]), py_val)doesn't pass through the |
Maybe? You could try putting a breakpoint inside that branch with a C debugger and see if the breakpoint ever gets hit. Although if the tests don't cover that branch then this exercise wouldn't prove anythig - maybe test coverage is bad? But if it is covered then that might give you more context if you look at the call stack. I recently added docs for using C debuggers with NumPy's internals, you can try it out: https://numpy.org/devdocs/dev/development_advanced_debugging.html#c-debuggers |
seberg
left a comment
There was a problem hiding this comment.
Overall, looks reasonable, I think a few more tests would be good, this type of code is deceptive. But maybe Nathan or Warren have a look through again, then I am happy (with that code duplication removed, it's a lot of lines and it confused me).
| npy_bool has_brackets = NPY_FALSE; | ||
| start = s; | ||
|
|
||
| while (isspace((unsigned char) *s)) { |
There was a problem hiding this comment.
Hmmm, we'll lose the ability to parse certain strings in principle that Python parses (e.g. non-breaking space). But clongdouble currently doesn't parse these either. So maybe OK.
| Py_XDECREF(b); | ||
| return temp; | ||
| } | ||
| } |
There was a problem hiding this comment.
This is a huge repeated block, and not very clear that it is the finalization and will never continue below. Even a goto would seem better, I think just put what is after this into the if instead.
| "not a number", | ||
| "(2+2j" # Missing closing brackets | ||
| "2+5j )" # Missing opening brackets | ||
| "3+4k" |
There was a problem hiding this comment.
I think this could have more tests, e.g. 3j+3, 3+-1j? Also maybe unicode characters for example (but that is different test maybe).
There was a problem hiding this comment.
Supporting it seems easy enough, I would lean towards just keeping it if it's simple and adding a test that will fail if Python ever breaks it.
But if you don't, at least add a test for it raising!
8e7bfb2 to
edd6529
Compare
edd6529 to
e4733b9
Compare
|
Sorry for the long delay, I've removed the code duplication and added some tests for invalid strings. |
ngoldbaum
left a comment
There was a problem hiding this comment.
Sorry for letting this sit for so long! I'll also add a milestone while will help us avoid forgetting.
This pull request addresses #26701. Converting to a
np.clongdoublefrom a string would result in a loss of precision. This is because the conversion process involves Python's complex type as an intermediate, which has less precision thannp.clongdouble. The pull request adds a test which fails on themainbranch on linux, x86.