summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorAntony Lee <anntzer.lee@gmail.com>2021-08-05 12:20:12 +0200
committerGitHub <noreply@github.com>2021-08-05 13:20:12 +0300
commitd97e31e891e868457d710d53b8ddadb0d473ec8a (patch)
tree3515f22bb31a111ae029a9c5a5384b379f46ffca /numpy
parentb3e3567544dc2b41e1bcc89157b977cf12ef2efb (diff)
downloadnumpy-d97e31e891e868457d710d53b8ddadb0d473ec8a.tar.gz
PERF: Speed-up common case of loadtxt()ing non-hex floats. (#19598)
* PERF: Speed-up common case of loadtxt()ing non-hex floats. `python runtests.py --bench bench_io` reports a ~5-10% perf gain. * TST: Add tests to check fromhex not called unintentionally. Adds regression tests to check that the logic surrounding when the default floatconv applies the fromhex conversion does not change. Co-authored-by: Ross Barnowski <rossbar@berkeley.edu>
Diffstat (limited to 'numpy')
-rw-r--r--numpy/lib/npyio.py13
-rw-r--r--numpy/lib/tests/test_io.py22
2 files changed, 31 insertions, 4 deletions
diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py
index 9ae5d0b59..3b6a1c563 100644
--- a/numpy/lib/npyio.py
+++ b/numpy/lib/npyio.py
@@ -732,10 +732,15 @@ def _getconv(dtype):
""" Find the correct dtype converter. Adapted from matplotlib """
def floatconv(x):
- x.lower()
- if '0x' in x:
- return float.fromhex(x)
- return float(x)
+ try:
+ return float(x) # The fastest path.
+ except ValueError:
+ if '0x' in x: # Don't accidentally convert "a" ("0xa") to 10.
+ try:
+ return float.fromhex(x)
+ except ValueError:
+ pass
+ raise # Raise the original exception, which makes more sense.
typ = dtype.type
if issubclass(typ, np.bool_):
diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py
index 534ab683c..d97ad76df 100644
--- a/numpy/lib/tests/test_io.py
+++ b/numpy/lib/tests/test_io.py
@@ -984,6 +984,28 @@ class TestLoadTxt(LoadTxtBase):
res = np.loadtxt(c, dtype=dt)
assert_equal(res, tgt, err_msg="%s" % dt)
+ def test_default_float_converter_no_default_hex_conversion(self):
+ """
+ Ensure that fromhex is only used for values with the correct prefix and
+ is not called by default. Regression test related to gh-19598.
+ """
+ c = TextIO("a b c")
+ with pytest.raises(
+ ValueError, match="could not convert string to float"
+ ):
+ np.loadtxt(c)
+
+ def test_default_float_converter_exception(self):
+ """
+ Ensure that the exception message raised during failed floating point
+ conversion is correct. Regression test related to gh-19598.
+ """
+ c = TextIO("qrs tuv") # Invalid values for default float converter
+ with pytest.raises(
+ ValueError, match="could not convert string to float"
+ ):
+ np.loadtxt(c)
+
def test_from_complex(self):
tgt = (complex(1, 1), complex(1, -1))
c = TextIO()