test_scalarprint.py 15 KB

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