test_longdouble.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. import warnings
  2. import pytest
  3. import numpy as np
  4. from numpy.testing import (
  5. assert_, assert_equal, assert_raises, assert_warns, assert_array_equal,
  6. temppath,
  7. )
  8. from numpy.core.tests._locales import CommaDecimalPointLocale
  9. LD_INFO = np.finfo(np.longdouble)
  10. longdouble_longer_than_double = (LD_INFO.eps < np.finfo(np.double).eps)
  11. _o = 1 + LD_INFO.eps
  12. string_to_longdouble_inaccurate = (_o != np.longdouble(repr(_o)))
  13. del _o
  14. def test_scalar_extraction():
  15. """Confirm that extracting a value doesn't convert to python float"""
  16. o = 1 + LD_INFO.eps
  17. a = np.array([o, o, o])
  18. assert_equal(a[1], o)
  19. # Conversions string -> long double
  20. # 0.1 not exactly representable in base 2 floating point.
  21. repr_precision = len(repr(np.longdouble(0.1)))
  22. # +2 from macro block starting around line 842 in scalartypes.c.src.
  23. @pytest.mark.skipif(LD_INFO.precision + 2 >= repr_precision,
  24. reason="repr precision not enough to show eps")
  25. def test_repr_roundtrip():
  26. # We will only see eps in repr if within printing precision.
  27. o = 1 + LD_INFO.eps
  28. assert_equal(np.longdouble(repr(o)), o, "repr was %s" % repr(o))
  29. @pytest.mark.skipif(string_to_longdouble_inaccurate, reason="Need strtold_l")
  30. def test_repr_roundtrip_bytes():
  31. o = 1 + LD_INFO.eps
  32. assert_equal(np.longdouble(repr(o).encode("ascii")), o)
  33. @pytest.mark.skipif(string_to_longdouble_inaccurate, reason="Need strtold_l")
  34. @pytest.mark.parametrize("strtype", (np.str_, np.bytes_, str, bytes))
  35. def test_array_and_stringlike_roundtrip(strtype):
  36. """
  37. Test that string representations of long-double roundtrip both
  38. for array casting and scalar coercion, see also gh-15608.
  39. """
  40. o = 1 + LD_INFO.eps
  41. if strtype in (np.bytes_, bytes):
  42. o_str = strtype(repr(o).encode("ascii"))
  43. else:
  44. o_str = strtype(repr(o))
  45. # Test that `o` is correctly coerced from the string-like
  46. assert o == np.longdouble(o_str)
  47. # Test that arrays also roundtrip correctly:
  48. o_strarr = np.asarray([o] * 3, dtype=strtype)
  49. assert (o == o_strarr.astype(np.longdouble)).all()
  50. # And array coercion and casting to string give the same as scalar repr:
  51. assert (o_strarr == o_str).all()
  52. assert (np.asarray([o] * 3).astype(strtype) == o_str).all()
  53. def test_bogus_string():
  54. assert_raises(ValueError, np.longdouble, "spam")
  55. assert_raises(ValueError, np.longdouble, "1.0 flub")
  56. @pytest.mark.skipif(string_to_longdouble_inaccurate, reason="Need strtold_l")
  57. def test_fromstring():
  58. o = 1 + LD_INFO.eps
  59. s = (" " + repr(o))*5
  60. a = np.array([o]*5)
  61. assert_equal(np.fromstring(s, sep=" ", dtype=np.longdouble), a,
  62. err_msg="reading '%s'" % s)
  63. def test_fromstring_complex():
  64. for ctype in ["complex", "cdouble", "cfloat"]:
  65. # Check spacing between separator
  66. assert_equal(np.fromstring("1, 2 , 3 ,4", sep=",", dtype=ctype),
  67. np.array([1., 2., 3., 4.]))
  68. # Real component not specified
  69. assert_equal(np.fromstring("1j, -2j, 3j, 4e1j", sep=",", dtype=ctype),
  70. np.array([1.j, -2.j, 3.j, 40.j]))
  71. # Both components specified
  72. assert_equal(np.fromstring("1+1j,2-2j, -3+3j, -4e1+4j", sep=",", dtype=ctype),
  73. np.array([1. + 1.j, 2. - 2.j, - 3. + 3.j, - 40. + 4j]))
  74. # Spaces at wrong places
  75. with assert_warns(DeprecationWarning):
  76. assert_equal(np.fromstring("1+2 j,3", dtype=ctype, sep=","),
  77. np.array([1.]))
  78. with assert_warns(DeprecationWarning):
  79. assert_equal(np.fromstring("1+ 2j,3", dtype=ctype, sep=","),
  80. np.array([1.]))
  81. with assert_warns(DeprecationWarning):
  82. assert_equal(np.fromstring("1 +2j,3", dtype=ctype, sep=","),
  83. np.array([1.]))
  84. with assert_warns(DeprecationWarning):
  85. assert_equal(np.fromstring("1+j", dtype=ctype, sep=","),
  86. np.array([1.]))
  87. with assert_warns(DeprecationWarning):
  88. assert_equal(np.fromstring("1+", dtype=ctype, sep=","),
  89. np.array([1.]))
  90. with assert_warns(DeprecationWarning):
  91. assert_equal(np.fromstring("1j+1", dtype=ctype, sep=","),
  92. np.array([1j]))
  93. def test_fromstring_bogus():
  94. with assert_warns(DeprecationWarning):
  95. assert_equal(np.fromstring("1. 2. 3. flop 4.", dtype=float, sep=" "),
  96. np.array([1., 2., 3.]))
  97. def test_fromstring_empty():
  98. with assert_warns(DeprecationWarning):
  99. assert_equal(np.fromstring("xxxxx", sep="x"),
  100. np.array([]))
  101. def test_fromstring_missing():
  102. with assert_warns(DeprecationWarning):
  103. assert_equal(np.fromstring("1xx3x4x5x6", sep="x"),
  104. np.array([1]))
  105. class TestFileBased:
  106. ldbl = 1 + LD_INFO.eps
  107. tgt = np.array([ldbl]*5)
  108. out = ''.join([repr(t) + '\n' for t in tgt])
  109. def test_fromfile_bogus(self):
  110. with temppath() as path:
  111. with open(path, 'wt') as f:
  112. f.write("1. 2. 3. flop 4.\n")
  113. with assert_warns(DeprecationWarning):
  114. res = np.fromfile(path, dtype=float, sep=" ")
  115. assert_equal(res, np.array([1., 2., 3.]))
  116. def test_fromfile_complex(self):
  117. for ctype in ["complex", "cdouble", "cfloat"]:
  118. # Check spacing between separator and only real component specified
  119. with temppath() as path:
  120. with open(path, 'wt') as f:
  121. f.write("1, 2 , 3 ,4\n")
  122. res = np.fromfile(path, dtype=ctype, sep=",")
  123. assert_equal(res, np.array([1., 2., 3., 4.]))
  124. # Real component not specified
  125. with temppath() as path:
  126. with open(path, 'wt') as f:
  127. f.write("1j, -2j, 3j, 4e1j\n")
  128. res = np.fromfile(path, dtype=ctype, sep=",")
  129. assert_equal(res, np.array([1.j, -2.j, 3.j, 40.j]))
  130. # Both components specified
  131. with temppath() as path:
  132. with open(path, 'wt') as f:
  133. f.write("1+1j,2-2j, -3+3j, -4e1+4j\n")
  134. res = np.fromfile(path, dtype=ctype, sep=",")
  135. assert_equal(res, np.array([1. + 1.j, 2. - 2.j, - 3. + 3.j, - 40. + 4j]))
  136. # Spaces at wrong places
  137. with temppath() as path:
  138. with open(path, 'wt') as f:
  139. f.write("1+2 j,3\n")
  140. with assert_warns(DeprecationWarning):
  141. res = np.fromfile(path, dtype=ctype, sep=",")
  142. assert_equal(res, np.array([1.]))
  143. # Spaces at wrong places
  144. with temppath() as path:
  145. with open(path, 'wt') as f:
  146. f.write("1+ 2j,3\n")
  147. with assert_warns(DeprecationWarning):
  148. res = np.fromfile(path, dtype=ctype, sep=",")
  149. assert_equal(res, np.array([1.]))
  150. # Spaces at wrong places
  151. with temppath() as path:
  152. with open(path, 'wt') as f:
  153. f.write("1 +2j,3\n")
  154. with assert_warns(DeprecationWarning):
  155. res = np.fromfile(path, dtype=ctype, sep=",")
  156. assert_equal(res, np.array([1.]))
  157. # Spaces at wrong places
  158. with temppath() as path:
  159. with open(path, 'wt') as f:
  160. f.write("1+j\n")
  161. with assert_warns(DeprecationWarning):
  162. res = np.fromfile(path, dtype=ctype, sep=",")
  163. assert_equal(res, np.array([1.]))
  164. # Spaces at wrong places
  165. with temppath() as path:
  166. with open(path, 'wt') as f:
  167. f.write("1+\n")
  168. with assert_warns(DeprecationWarning):
  169. res = np.fromfile(path, dtype=ctype, sep=",")
  170. assert_equal(res, np.array([1.]))
  171. # Spaces at wrong places
  172. with temppath() as path:
  173. with open(path, 'wt') as f:
  174. f.write("1j+1\n")
  175. with assert_warns(DeprecationWarning):
  176. res = np.fromfile(path, dtype=ctype, sep=",")
  177. assert_equal(res, np.array([1.j]))
  178. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  179. reason="Need strtold_l")
  180. def test_fromfile(self):
  181. with temppath() as path:
  182. with open(path, 'wt') as f:
  183. f.write(self.out)
  184. res = np.fromfile(path, dtype=np.longdouble, sep="\n")
  185. assert_equal(res, self.tgt)
  186. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  187. reason="Need strtold_l")
  188. def test_genfromtxt(self):
  189. with temppath() as path:
  190. with open(path, 'wt') as f:
  191. f.write(self.out)
  192. res = np.genfromtxt(path, dtype=np.longdouble)
  193. assert_equal(res, self.tgt)
  194. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  195. reason="Need strtold_l")
  196. def test_loadtxt(self):
  197. with temppath() as path:
  198. with open(path, 'wt') as f:
  199. f.write(self.out)
  200. res = np.loadtxt(path, dtype=np.longdouble)
  201. assert_equal(res, self.tgt)
  202. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  203. reason="Need strtold_l")
  204. def test_tofile_roundtrip(self):
  205. with temppath() as path:
  206. self.tgt.tofile(path, sep=" ")
  207. res = np.fromfile(path, dtype=np.longdouble, sep=" ")
  208. assert_equal(res, self.tgt)
  209. # Conversions long double -> string
  210. def test_repr_exact():
  211. o = 1 + LD_INFO.eps
  212. assert_(repr(o) != '1')
  213. @pytest.mark.skipif(longdouble_longer_than_double, reason="BUG #2376")
  214. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  215. reason="Need strtold_l")
  216. def test_format():
  217. o = 1 + LD_INFO.eps
  218. assert_("{0:.40g}".format(o) != '1')
  219. @pytest.mark.skipif(longdouble_longer_than_double, reason="BUG #2376")
  220. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  221. reason="Need strtold_l")
  222. def test_percent():
  223. o = 1 + LD_INFO.eps
  224. assert_("%.40g" % o != '1')
  225. @pytest.mark.skipif(longdouble_longer_than_double,
  226. reason="array repr problem")
  227. @pytest.mark.skipif(string_to_longdouble_inaccurate,
  228. reason="Need strtold_l")
  229. def test_array_repr():
  230. o = 1 + LD_INFO.eps
  231. a = np.array([o])
  232. b = np.array([1], dtype=np.longdouble)
  233. if not np.all(a != b):
  234. raise ValueError("precision loss creating arrays")
  235. assert_(repr(a) != repr(b))
  236. #
  237. # Locale tests: scalar types formatting should be independent of the locale
  238. #
  239. class TestCommaDecimalPointLocale(CommaDecimalPointLocale):
  240. def test_repr_roundtrip_foreign(self):
  241. o = 1.5
  242. assert_equal(o, np.longdouble(repr(o)))
  243. def test_fromstring_foreign_repr(self):
  244. f = 1.234
  245. a = np.fromstring(repr(f), dtype=float, sep=" ")
  246. assert_equal(a[0], f)
  247. def test_fromstring_best_effort_float(self):
  248. with assert_warns(DeprecationWarning):
  249. assert_equal(np.fromstring("1,234", dtype=float, sep=" "),
  250. np.array([1.]))
  251. def test_fromstring_best_effort(self):
  252. with assert_warns(DeprecationWarning):
  253. assert_equal(np.fromstring("1,234", dtype=np.longdouble, sep=" "),
  254. np.array([1.]))
  255. def test_fromstring_foreign(self):
  256. s = "1.234"
  257. a = np.fromstring(s, dtype=np.longdouble, sep=" ")
  258. assert_equal(a[0], np.longdouble(s))
  259. def test_fromstring_foreign_sep(self):
  260. a = np.array([1, 2, 3, 4])
  261. b = np.fromstring("1,2,3,4,", dtype=np.longdouble, sep=",")
  262. assert_array_equal(a, b)
  263. def test_fromstring_foreign_value(self):
  264. with assert_warns(DeprecationWarning):
  265. b = np.fromstring("1,234", dtype=np.longdouble, sep=" ")
  266. assert_array_equal(b[0], 1)
  267. @pytest.mark.parametrize("int_val", [
  268. # cases discussed in gh-10723
  269. # and gh-9968
  270. 2 ** 1024, 0])
  271. def test_longdouble_from_int(int_val):
  272. # for issue gh-9968
  273. str_val = str(int_val)
  274. # we'll expect a RuntimeWarning on platforms
  275. # with np.longdouble equivalent to np.double
  276. # for large integer input
  277. with warnings.catch_warnings(record=True) as w:
  278. warnings.filterwarnings('always', '', RuntimeWarning)
  279. # can be inf==inf on some platforms
  280. assert np.longdouble(int_val) == np.longdouble(str_val)
  281. # we can't directly compare the int and
  282. # max longdouble value on all platforms
  283. if np.allclose(np.finfo(np.longdouble).max,
  284. np.finfo(np.double).max) and w:
  285. assert w[0].category is RuntimeWarning
  286. @pytest.mark.parametrize("bool_val", [
  287. True, False])
  288. def test_longdouble_from_bool(bool_val):
  289. assert np.longdouble(bool_val) == np.longdouble(int(bool_val))