test_scalarprint.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. """ Test printing of scalar types.
  2. """
  3. import code
  4. import platform
  5. import pytest
  6. import sys
  7. from tempfile import TemporaryFile
  8. import numpy as np
  9. from numpy.testing import assert_, assert_equal, assert_raises
  10. class TestRealScalars:
  11. def test_str(self):
  12. svals = [0.0, -0.0, 1, -1, np.inf, -np.inf, np.nan]
  13. styps = [np.float16, np.float32, np.float64, np.longdouble]
  14. wanted = [
  15. ['0.0', '0.0', '0.0', '0.0' ],
  16. ['-0.0', '-0.0', '-0.0', '-0.0'],
  17. ['1.0', '1.0', '1.0', '1.0' ],
  18. ['-1.0', '-1.0', '-1.0', '-1.0'],
  19. ['inf', 'inf', 'inf', 'inf' ],
  20. ['-inf', '-inf', '-inf', '-inf'],
  21. ['nan', 'nan', 'nan', 'nan']]
  22. for wants, val in zip(wanted, svals):
  23. for want, styp in zip(wants, styps):
  24. msg = 'for str({}({}))'.format(np.dtype(styp).name, repr(val))
  25. assert_equal(str(styp(val)), want, err_msg=msg)
  26. def test_scalar_cutoffs(self):
  27. # test that both the str and repr of np.float64 behaves
  28. # like python floats in python3.
  29. def check(v):
  30. assert_equal(str(np.float64(v)), str(v))
  31. assert_equal(str(np.float64(v)), repr(v))
  32. assert_equal(repr(np.float64(v)), repr(v))
  33. assert_equal(repr(np.float64(v)), str(v))
  34. # check we use the same number of significant digits
  35. check(1.12345678901234567890)
  36. check(0.0112345678901234567890)
  37. # check switch from scientific output to positional and back
  38. check(1e-5)
  39. check(1e-4)
  40. check(1e15)
  41. check(1e16)
  42. def test_py2_float_print(self):
  43. # gh-10753
  44. # In python2, the python float type implements an obsolete method
  45. # tp_print, which overrides tp_repr and tp_str when using "print" to
  46. # output to a "real file" (ie, not a StringIO). Make sure we don't
  47. # inherit it.
  48. x = np.double(0.1999999999999)
  49. with TemporaryFile('r+t') as f:
  50. print(x, file=f)
  51. f.seek(0)
  52. output = f.read()
  53. assert_equal(output, str(x) + '\n')
  54. # In python2 the value float('0.1999999999999') prints with reduced
  55. # precision as '0.2', but we want numpy's np.double('0.1999999999999')
  56. # to print the unique value, '0.1999999999999'.
  57. # gh-11031
  58. # Only in the python2 interactive shell and when stdout is a "real"
  59. # file, the output of the last command is printed to stdout without
  60. # Py_PRINT_RAW (unlike the print statement) so `>>> x` and `>>> print
  61. # x` are potentially different. Make sure they are the same. The only
  62. # way I found to get prompt-like output is using an actual prompt from
  63. # the 'code' module. Again, must use tempfile to get a "real" file.
  64. # dummy user-input which enters one line and then ctrl-Ds.
  65. def userinput():
  66. yield 'np.sqrt(2)'
  67. raise EOFError
  68. gen = userinput()
  69. input_func = lambda prompt="": next(gen)
  70. with TemporaryFile('r+t') as fo, TemporaryFile('r+t') as fe:
  71. orig_stdout, orig_stderr = sys.stdout, sys.stderr
  72. sys.stdout, sys.stderr = fo, fe
  73. code.interact(local={'np': np}, readfunc=input_func, banner='')
  74. sys.stdout, sys.stderr = orig_stdout, orig_stderr
  75. fo.seek(0)
  76. capture = fo.read().strip()
  77. assert_equal(capture, repr(np.sqrt(2)))
  78. def test_dragon4(self):
  79. # these tests are adapted from Ryan Juckett's dragon4 implementation,
  80. # see dragon4.c for details.
  81. fpos32 = lambda x, **k: np.format_float_positional(np.float32(x), **k)
  82. fsci32 = lambda x, **k: np.format_float_scientific(np.float32(x), **k)
  83. fpos64 = lambda x, **k: np.format_float_positional(np.float64(x), **k)
  84. fsci64 = lambda x, **k: np.format_float_scientific(np.float64(x), **k)
  85. preckwd = lambda prec: {'unique': False, 'precision': prec}
  86. assert_equal(fpos32('1.0'), "1.")
  87. assert_equal(fsci32('1.0'), "1.e+00")
  88. assert_equal(fpos32('10.234'), "10.234")
  89. assert_equal(fpos32('-10.234'), "-10.234")
  90. assert_equal(fsci32('10.234'), "1.0234e+01")
  91. assert_equal(fsci32('-10.234'), "-1.0234e+01")
  92. assert_equal(fpos32('1000.0'), "1000.")
  93. assert_equal(fpos32('1.0', precision=0), "1.")
  94. assert_equal(fsci32('1.0', precision=0), "1.e+00")
  95. assert_equal(fpos32('10.234', precision=0), "10.")
  96. assert_equal(fpos32('-10.234', precision=0), "-10.")
  97. assert_equal(fsci32('10.234', precision=0), "1.e+01")
  98. assert_equal(fsci32('-10.234', precision=0), "-1.e+01")
  99. assert_equal(fpos32('10.234', precision=2), "10.23")
  100. assert_equal(fsci32('-10.234', precision=2), "-1.02e+01")
  101. assert_equal(fsci64('9.9999999999999995e-08', **preckwd(16)),
  102. '9.9999999999999995e-08')
  103. assert_equal(fsci64('9.8813129168249309e-324', **preckwd(16)),
  104. '9.8813129168249309e-324')
  105. assert_equal(fsci64('9.9999999999999694e-311', **preckwd(16)),
  106. '9.9999999999999694e-311')
  107. # test rounding
  108. # 3.1415927410 is closest float32 to np.pi
  109. assert_equal(fpos32('3.14159265358979323846', **preckwd(10)),
  110. "3.1415927410")
  111. assert_equal(fsci32('3.14159265358979323846', **preckwd(10)),
  112. "3.1415927410e+00")
  113. assert_equal(fpos64('3.14159265358979323846', **preckwd(10)),
  114. "3.1415926536")
  115. assert_equal(fsci64('3.14159265358979323846', **preckwd(10)),
  116. "3.1415926536e+00")
  117. # 299792448 is closest float32 to 299792458
  118. assert_equal(fpos32('299792458.0', **preckwd(5)), "299792448.00000")
  119. assert_equal(fsci32('299792458.0', **preckwd(5)), "2.99792e+08")
  120. assert_equal(fpos64('299792458.0', **preckwd(5)), "299792458.00000")
  121. assert_equal(fsci64('299792458.0', **preckwd(5)), "2.99792e+08")
  122. assert_equal(fpos32('3.14159265358979323846', **preckwd(25)),
  123. "3.1415927410125732421875000")
  124. assert_equal(fpos64('3.14159265358979323846', **preckwd(50)),
  125. "3.14159265358979311599796346854418516159057617187500")
  126. assert_equal(fpos64('3.14159265358979323846'), "3.141592653589793")
  127. # smallest numbers
  128. assert_equal(fpos32(0.5**(126 + 23), unique=False, precision=149),
  129. "0.00000000000000000000000000000000000000000000140129846432"
  130. "4817070923729583289916131280261941876515771757068283889791"
  131. "08268586060148663818836212158203125")
  132. assert_equal(fpos64(5e-324, unique=False, precision=1074),
  133. "0.00000000000000000000000000000000000000000000000000000000"
  134. "0000000000000000000000000000000000000000000000000000000000"
  135. "0000000000000000000000000000000000000000000000000000000000"
  136. "0000000000000000000000000000000000000000000000000000000000"
  137. "0000000000000000000000000000000000000000000000000000000000"
  138. "0000000000000000000000000000000000049406564584124654417656"
  139. "8792868221372365059802614324764425585682500675507270208751"
  140. "8652998363616359923797965646954457177309266567103559397963"
  141. "9877479601078187812630071319031140452784581716784898210368"
  142. "8718636056998730723050006387409153564984387312473397273169"
  143. "6151400317153853980741262385655911710266585566867681870395"
  144. "6031062493194527159149245532930545654440112748012970999954"
  145. "1931989409080416563324524757147869014726780159355238611550"
  146. "1348035264934720193790268107107491703332226844753335720832"
  147. "4319360923828934583680601060115061698097530783422773183292"
  148. "4790498252473077637592724787465608477820373446969953364701"
  149. "7972677717585125660551199131504891101451037862738167250955"
  150. "8373897335989936648099411642057026370902792427675445652290"
  151. "87538682506419718265533447265625")
  152. # largest numbers
  153. f32x = np.finfo(np.float32).max
  154. assert_equal(fpos32(f32x, **preckwd(0)),
  155. "340282346638528859811704183484516925440.")
  156. assert_equal(fpos64(np.finfo(np.float64).max, **preckwd(0)),
  157. "1797693134862315708145274237317043567980705675258449965989"
  158. "1747680315726078002853876058955863276687817154045895351438"
  159. "2464234321326889464182768467546703537516986049910576551282"
  160. "0762454900903893289440758685084551339423045832369032229481"
  161. "6580855933212334827479782620414472316873817718091929988125"
  162. "0404026184124858368.")
  163. # Warning: In unique mode only the integer digits necessary for
  164. # uniqueness are computed, the rest are 0.
  165. assert_equal(fpos32(f32x),
  166. "340282350000000000000000000000000000000.")
  167. # Further tests of zero-padding vs rounding in different combinations
  168. # of unique, fractional, precision, min_digits
  169. # precision can only reduce digits, not add them.
  170. # min_digits can only extend digits, not reduce them.
  171. assert_equal(fpos32(f32x, unique=True, fractional=True, precision=0),
  172. "340282350000000000000000000000000000000.")
  173. assert_equal(fpos32(f32x, unique=True, fractional=True, precision=4),
  174. "340282350000000000000000000000000000000.")
  175. assert_equal(fpos32(f32x, unique=True, fractional=True, min_digits=0),
  176. "340282346638528859811704183484516925440.")
  177. assert_equal(fpos32(f32x, unique=True, fractional=True, min_digits=4),
  178. "340282346638528859811704183484516925440.0000")
  179. assert_equal(fpos32(f32x, unique=True, fractional=True,
  180. min_digits=4, precision=4),
  181. "340282346638528859811704183484516925440.0000")
  182. assert_raises(ValueError, fpos32, f32x, unique=True, fractional=False,
  183. precision=0)
  184. assert_equal(fpos32(f32x, unique=True, fractional=False, precision=4),
  185. "340300000000000000000000000000000000000.")
  186. assert_equal(fpos32(f32x, unique=True, fractional=False, precision=20),
  187. "340282350000000000000000000000000000000.")
  188. assert_equal(fpos32(f32x, unique=True, fractional=False, min_digits=4),
  189. "340282350000000000000000000000000000000.")
  190. assert_equal(fpos32(f32x, unique=True, fractional=False,
  191. min_digits=20),
  192. "340282346638528859810000000000000000000.")
  193. assert_equal(fpos32(f32x, unique=True, fractional=False,
  194. min_digits=15),
  195. "340282346638529000000000000000000000000.")
  196. assert_equal(fpos32(f32x, unique=False, fractional=False, precision=4),
  197. "340300000000000000000000000000000000000.")
  198. # test that unique rounding is preserved when precision is supplied
  199. # but no extra digits need to be printed (gh-18609)
  200. a = np.float64.fromhex('-1p-97')
  201. assert_equal(fsci64(a, unique=True), '-6.310887241768095e-30')
  202. assert_equal(fsci64(a, unique=False, precision=15),
  203. '-6.310887241768094e-30')
  204. assert_equal(fsci64(a, unique=True, precision=15),
  205. '-6.310887241768095e-30')
  206. assert_equal(fsci64(a, unique=True, min_digits=15),
  207. '-6.310887241768095e-30')
  208. assert_equal(fsci64(a, unique=True, precision=15, min_digits=15),
  209. '-6.310887241768095e-30')
  210. # adds/remove digits in unique mode with unbiased rnding
  211. assert_equal(fsci64(a, unique=True, precision=14),
  212. '-6.31088724176809e-30')
  213. assert_equal(fsci64(a, unique=True, min_digits=16),
  214. '-6.3108872417680944e-30')
  215. assert_equal(fsci64(a, unique=True, precision=16),
  216. '-6.310887241768095e-30')
  217. assert_equal(fsci64(a, unique=True, min_digits=14),
  218. '-6.310887241768095e-30')
  219. # test min_digits in unique mode with different rounding cases
  220. assert_equal(fsci64('1e120', min_digits=3), '1.000e+120')
  221. assert_equal(fsci64('1e100', min_digits=3), '1.000e+100')
  222. # test trailing zeros
  223. assert_equal(fpos32('1.0', unique=False, precision=3), "1.000")
  224. assert_equal(fpos64('1.0', unique=False, precision=3), "1.000")
  225. assert_equal(fsci32('1.0', unique=False, precision=3), "1.000e+00")
  226. assert_equal(fsci64('1.0', unique=False, precision=3), "1.000e+00")
  227. assert_equal(fpos32('1.5', unique=False, precision=3), "1.500")
  228. assert_equal(fpos64('1.5', unique=False, precision=3), "1.500")
  229. assert_equal(fsci32('1.5', unique=False, precision=3), "1.500e+00")
  230. assert_equal(fsci64('1.5', unique=False, precision=3), "1.500e+00")
  231. # gh-10713
  232. assert_equal(fpos64('324', unique=False, precision=5,
  233. fractional=False), "324.00")
  234. def test_dragon4_interface(self):
  235. tps = [np.float16, np.float32, np.float64]
  236. if hasattr(np, 'float128'):
  237. tps.append(np.float128)
  238. fpos = np.format_float_positional
  239. fsci = np.format_float_scientific
  240. for tp in tps:
  241. # test padding
  242. assert_equal(fpos(tp('1.0'), pad_left=4, pad_right=4), " 1. ")
  243. assert_equal(fpos(tp('-1.0'), pad_left=4, pad_right=4), " -1. ")
  244. assert_equal(fpos(tp('-10.2'),
  245. pad_left=4, pad_right=4), " -10.2 ")
  246. # test exp_digits
  247. assert_equal(fsci(tp('1.23e1'), exp_digits=5), "1.23e+00001")
  248. # test fixed (non-unique) mode
  249. assert_equal(fpos(tp('1.0'), unique=False, precision=4), "1.0000")
  250. assert_equal(fsci(tp('1.0'), unique=False, precision=4),
  251. "1.0000e+00")
  252. # test trimming
  253. # trim of 'k' or '.' only affects non-unique mode, since unique
  254. # mode will not output trailing 0s.
  255. assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='k'),
  256. "1.0000")
  257. assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='.'),
  258. "1.")
  259. assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='.'),
  260. "1.2" if tp != np.float16 else "1.2002")
  261. assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='0'),
  262. "1.0")
  263. assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='0'),
  264. "1.2" if tp != np.float16 else "1.2002")
  265. assert_equal(fpos(tp('1.'), trim='0'), "1.0")
  266. assert_equal(fpos(tp('1.'), unique=False, precision=4, trim='-'),
  267. "1")
  268. assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='-'),
  269. "1.2" if tp != np.float16 else "1.2002")
  270. assert_equal(fpos(tp('1.'), trim='-'), "1")
  271. assert_equal(fpos(tp('1.001'), precision=1, trim='-'), "1")
  272. @pytest.mark.skipif(not platform.machine().startswith("ppc64"),
  273. reason="only applies to ppc float128 values")
  274. def test_ppc64_ibm_double_double128(self):
  275. # check that the precision decreases once we get into the subnormal
  276. # range. Unlike float64, this starts around 1e-292 instead of 1e-308,
  277. # which happens when the first double is normal and the second is
  278. # subnormal.
  279. x = np.float128('2.123123123123123123123123123123123e-286')
  280. got = [str(x/np.float128('2e' + str(i))) for i in range(0,40)]
  281. expected = [
  282. "1.06156156156156156156156156156157e-286",
  283. "1.06156156156156156156156156156158e-287",
  284. "1.06156156156156156156156156156159e-288",
  285. "1.0615615615615615615615615615616e-289",
  286. "1.06156156156156156156156156156157e-290",
  287. "1.06156156156156156156156156156156e-291",
  288. "1.0615615615615615615615615615616e-292",
  289. "1.0615615615615615615615615615615e-293",
  290. "1.061561561561561561561561561562e-294",
  291. "1.06156156156156156156156156155e-295",
  292. "1.0615615615615615615615615616e-296",
  293. "1.06156156156156156156156156e-297",
  294. "1.06156156156156156156156157e-298",
  295. "1.0615615615615615615615616e-299",
  296. "1.06156156156156156156156e-300",
  297. "1.06156156156156156156155e-301",
  298. "1.0615615615615615615616e-302",
  299. "1.061561561561561561562e-303",
  300. "1.06156156156156156156e-304",
  301. "1.0615615615615615618e-305",
  302. "1.06156156156156156e-306",
  303. "1.06156156156156157e-307",
  304. "1.0615615615615616e-308",
  305. "1.06156156156156e-309",
  306. "1.06156156156157e-310",
  307. "1.0615615615616e-311",
  308. "1.06156156156e-312",
  309. "1.06156156154e-313",
  310. "1.0615615616e-314",
  311. "1.06156156e-315",
  312. "1.06156155e-316",
  313. "1.061562e-317",
  314. "1.06156e-318",
  315. "1.06155e-319",
  316. "1.0617e-320",
  317. "1.06e-321",
  318. "1.04e-322",
  319. "1e-323",
  320. "0.0",
  321. "0.0"]
  322. assert_equal(got, expected)
  323. # Note: we follow glibc behavior, but it (or gcc) might not be right.
  324. # In particular we can get two values that print the same but are not
  325. # equal:
  326. a = np.float128('2')/np.float128('3')
  327. b = np.float128(str(a))
  328. assert_equal(str(a), str(b))
  329. assert_(a != b)
  330. def float32_roundtrip(self):
  331. # gh-9360
  332. x = np.float32(1024 - 2**-14)
  333. y = np.float32(1024 - 2**-13)
  334. assert_(repr(x) != repr(y))
  335. assert_equal(np.float32(repr(x)), x)
  336. assert_equal(np.float32(repr(y)), y)
  337. def float64_vs_python(self):
  338. # gh-2643, gh-6136, gh-6908
  339. assert_equal(repr(np.float64(0.1)), repr(0.1))
  340. assert_(repr(np.float64(0.20000000000000004)) != repr(0.2))