Repository navigation
Fortran-exponents - #3655
Fortran-exponents#3655dhomeier wants to merge 24 commits into
Conversation
|
Something like this would be nice to have for #3430, since FITS ASCII tables use FORTRAN-inspired string formatting. |
|
If it's already using the c parser that should be fairly straightforward; if it isn't it would certainly benefit from the speedup as well. I'll have a look when I have time; I have some python-level code to check for the various exponent styles as well. |
There was a problem hiding this comment.
If I'm following along correctly, I think fortran_exp is used to specify the exponent character, but otherwise isn't really related to Fortran per se. Maybe a better name would be expchar?
|
I think the automatic mode (where all of the reasonable options, Any sense of how common is the triple-digit exponent thing is? I've never come across it (not that that means anything). |
|
The triple-digit exponent could happen if you computed for example blackbody fluxes in float64 as a function of frequency, since some values would be really small. |
|
Or chemical equilibrium fractions of compounds that don't really exist under the given conditions... |
|
I see -- so the triple-digit simplification happens automatically? That's what I was getting at -- whether it was an automatic behavior or something a Fortran programmer would opt-in to. Sounds like the former. As for the potential performance hit: Let's do the most straightforward implementation, and benchmark it to get a sense of what the hit is. If we can't deal with the hit, a solution would be to have multiple implementations of |
|
Yes, the programmer can avoid it with an explicit format statement like OK, I've added the auto-detection with a bit of extra optimisation (thought the compiler would actually be able to abstract from the nested ifs...); for a real-world test case with some 2.3 Mio. lines, 26 columns 21 of which are read, maybe 20-40% of the original speed-up of use_fast_converter is lost (i.e. 7.02 s vs. 7.4 s have now increased to 7.12-7.2 s), but that's close to the timing uncertainty IMO. In fact the fastest runs have now occurred with the auto-detection turned on. |
|
I guess the way to add it to the standard parser would be to pre-process the entire string before passing it to fgets(buf, sizeof buf, str);
for (p = buf; p = strchr(p, 'D'); *p = 'E') {}
for (p = buf; p = strchr(p, 'Q'); *p = 'E') {}(not tested nor seriously reviewed due to lack of C expertise!) |
|
@dhomeier - thanks, this is looking pretty good from a top-level look! I'll try to go through in detail in the next couple days. Perhaps @mdmueller can take a look as well. I think just having this in the fast parser is reasonable. Since the pure Python parser really just relies on numpy it would be a significant change to add this capability to the slow readers. |
|
@taldcroft - I rather had the not-so-fast C parser in mind anyway; for the Python parser it would mainly amount to providing a convenience function to specify converters like |
|
Reviewing the build failures reported on AppVeyor and Travis, the former fails with the parallel version of Travis build fails due to a Sphinx warning: |
|
For the user API (the key in
So not really any change to the C code, just a more obvious front-end interface. |
|
About the Sphinx warnings, you'll just need to play around until you get something that builds locally without warnings. I'm often surprised by what Sphinx doesn't like. I do like your idea of making it visually parseable. |
|
This change will also benefit from updating a couple of places in the narrative docs so people actually know about. First is in the page about the fast reader: Next, I would suggest a new section called "Fortran-style exponents" just after the |
|
Humm, running build_sphinx on my Mac returns a couple of warnings I'll upload those doc fixes after changing the API to your suggestions. Any objections against silently accepting any substring of |
|
2028 warnings? That's not normal... |
|
Don't know if the sphinx installation is broken - it's not terribly old, 1.2.3, but the python 3.4 variant does not work at all... Most of the warnings seem to be of this kind: |
|
That seems like errors that would happen if there was an issue with the internet connection. If you re-run the build, do you still get that many warnings? |
|
1633 - the connection should be fast enough, not sure if the firewall might cause any problems. |
|
Near the beginning of the doc build it should say something like: These are all http requests. Are there any messages about them failing? You may try removing the |
|
@mdboom - thanks, you're right; they are failing: This is a "feature" of the latest openssl (at least the one in use on Mac OS since ~January); no idea if it is correct in not trusting certain certificate servers... |
|
Just pinging - is there anything left to be done at this point, suggestions for labels (I missed to mark it as ENH, it's obviously |
There was a problem hiding this comment.
Can you put the statements on a new line, e.g:
case '-':
negative = 1;
etc.
There was a problem hiding this comment.
I assume in the old code as well.
Moved check of fast_reader for invalid Fortran-style exponent patterns to separate test to avoid known issues (segfaults) with large exponents on Travis CI.
|
Finally realised that the segfaults on Travis occur on the same cases as known from I note that there are still three different outcomes of too large exponents: Should one ultimately try to make the C reader return |
|
One more thought, whatever the opinion on reading in extended-precision floats, the above listing shows one difference remaining between the existing So is there a general feeling it would be desirable to ensure consistency with the existing |
| if TRAVIS: | ||
| pytest.xfail("Large exponents can sometimes fail on Travis CI") | ||
|
|
||
| text = 'A B C D E\n1.0001+1 2.3+10 3+1001 2 8.e3\n.42d0 0.5 3 4.56-123.4 0.42-123' |
There was a problem hiding this comment.
Testing with two rows is not so definitive because if either value parses as a string then the whole column is converted to string. Better to write a clean, easy to read test like:
values = ['1.0001+1', '2.3+10', ..., '0.42-123']
expected = ['1.0001+1', '2.3+10', ..., 4.2e-122]
table = ascii.read(' '.join(values), format='no_header', ...)
out_values = [col[0] for col in table.itercols()]
assert out_values == expected
|
About the too-large exponents, for this PR I would suggest maintaining consistency with Python and returning |
|
Overall it is difficult to look at the tests and get a good understanding of what is being tested, in particular with regard to what parses and what does not. What would help is defining this in terms of a uniform test matrix like: You could actually do the same in code by just making a big list of tuples with those same three |
Fixed handling of a couple of corner cases in xstrtod() and made sure the function returns cleanly. str_to_double() returns values outside float64 range as -inf,0,inf, in accordance with the Python parser. Trying to get this through tests on Travis once more.
I suspect xstrtod returning without setting *endptr may have caused the segfaults...
|
OK, looks like the Travis errors are checked at last. The fast readers now return It seems for numbers larger than the smallest representable |
|
Ah, I guess |
|
I obviously haven't dug into this at the level of detail you have been doing, but I think the guiding principle here should be predictability and consistency. I.e. is there a simple way to predict what will happen for different cases, and is it consistent with behavior of Python and especially Numpy. I'm not super worried about the extreme edge cases like 2.5e-324. |
|
I actually can't think of any case where the |
|
BTW long integer conversion is still handled inconsistently between the Python parser, which switches right away to |
|
To summarise, I see 3 options for handling input values extending the respective numerical range:
*1 is the present situation, *2 would be the consistent solution keeping the spirit of #2234, so I'd tend to this option. In principle one could think of a 4th option always returning |
|
I would vote for option 2 as well. |
Raise only warning for floats outside of float64 range read in by ascii fast reader and return +-inf/0; better handling of limiting cases like 0.00000314e+314 or 2500e-327.
Changed the fallback of io.ascii fast_reader for integers outside of int64 range to string columns, consistent with the Python reader behaviour. Removed auto-detect flag from strtol call in tokenizer.c so it won't try to interpret integers with leading zeros as octal. Added tests and cleaned up tests for Fortran exponent_style options. Note: return type of mixed huge integer/float columns still depends on row order!
|
OK, it's been some time again before I got back to this; I have implemented option 2 from above
I've changed the invalid exponents tests according to taldcroft's suggestions, but left the multi-row input for some of the other tests, since columns with mixed types are part of the test case (see above). However I feel rather lost with the new CI system - I cannot see any details at all on what's happening on AppVeyor, and CircleCI only shows this quite unhelpful message:
Also I don't find any way to investigate the merge conflicts reported for |
|
Could not find any way to work around the conflicts here, so I've merged the branch locally into the updated master and submitted this as a new PR #5552. |
My next highest priority after having a fast C reader was always being able to read in Fortran-written ascii files in its standard double-precision notation (
1.495978707D+13…) without further processing,which required setting up converters for each column with
np.loadtxtornp.genfromtxt.Taking a shot here at the fast_reader module to enable the c parser to directly recognise 'D' or other characters in the exponent.
This adds ‘fortran_exp’ as new option to the fast_reader arguments.
This patch automatically activates the fast_converter, as changing the call to xstrtod was
by far the simplest implementation. I guess it would be possible to add it to the more
precise parser as well, but don’t know how big the demand for this is. I have yet to see
a case where use_fast_converter gave a different result.
Asking for other exponent characters than 'E' therefore now turns use_fast_converter on by default; however setting it explicitly to False raises a FastOptionsError.
Notes following my initial post:
I have since noted that 'q' or 'Q' may be used in Fortran output as well, see post
#3herehttp://computer-programming-forum.com/17-c-language/9b704e6e49d734b8.htm
and therefore modified the option to
'fortran_exp': 'char'Implementing an ‘automatic’ option in
xtstrtodI've experimented with a bit should be able to recognise any mix ofe,d,q(or any other characters) as well as the triple-digit exponents mentioned in the link above, but with a probable performance penalty of 5-10 %. Also might increase the risk of converting strings to float64 one does not want to convert... Could probably try the auto-detection on the first lines and then stick with one format for each column, but that would require getting deeper into the entrails ofcparser.pyx.