Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 12c4bdb

Browse files
committed
Merged revisions 75117 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r75117 | mark.dickinson | 2009-09-28 19:54:55 +0100 (Mon, 28 Sep 2009) | 3 lines Issue #3366: Add gamma function to math module. (lgamma, erf and erfc to follow). ........
1 parent 40af630 commit 12c4bdb

5 files changed

Lines changed: 572 additions & 35 deletions

File tree

Doc/library/math.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,16 @@ Hyperbolic functions
278278
Return the hyperbolic tangent of *x*.
279279

280280

281+
Special functions
282+
-----------------
283+
284+
.. function:: gamma(x)
285+
286+
Return the Gamma function at *x*.
287+
288+
.. versionadded:: 2.7
289+
290+
281291
Constants
282292
---------
283293

Lib/test/math_testcases.txt

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
-- Testcases for functions in math.
2+
--
3+
-- Each line takes the form:
4+
--
5+
-- <testid> <function> <input_value> -> <output_value> <flags>
6+
--
7+
-- where:
8+
--
9+
-- <testid> is a short name identifying the test,
10+
--
11+
-- <function> is the function to be tested (exp, cos, asinh, ...),
12+
--
13+
-- <input_value> is a string representing a floating-point value
14+
--
15+
-- <output_value> is the expected (ideal) output value, again
16+
-- represented as a string.
17+
--
18+
-- <flags> is a list of the floating-point flags required by C99
19+
--
20+
-- The possible flags are:
21+
--
22+
-- divide-by-zero : raised when a finite input gives a
23+
-- mathematically infinite result.
24+
--
25+
-- overflow : raised when a finite input gives a finite result that
26+
-- is too large to fit in the usual range of an IEEE 754 double.
27+
--
28+
-- invalid : raised for invalid inputs (e.g., sqrt(-1))
29+
--
30+
-- ignore-sign : indicates that the sign of the result is
31+
-- unspecified; e.g., if the result is given as inf,
32+
-- then both -inf and inf should be accepted as correct.
33+
--
34+
-- Flags may appear in any order.
35+
--
36+
-- Lines beginning with '--' (like this one) start a comment, and are
37+
-- ignored. Blank lines, or lines containing only whitespace, are also
38+
-- ignored.
39+
40+
-- Many of the values below were computed with the help of
41+
-- version 2.4 of the MPFR library for multiple-precision
42+
-- floating-point computations with correct rounding. All output
43+
-- values in this file are (modulo yet-to-be-discovered bugs)
44+
-- correctly rounded, provided that each input and output decimal
45+
-- floating-point value below is interpreted as a representation of
46+
-- the corresponding nearest IEEE 754 double-precision value. See the
47+
-- MPFR homepage at http://www.mpfr.org for more information about the
48+
-- MPFR project.
49+
50+
---------------------------
51+
-- gamma: Gamma function --
52+
---------------------------
53+
54+
-- special values
55+
gam0000 gamma 0.0 -> inf divide-by-zero
56+
gam0001 gamma -0.0 -> -inf divide-by-zero
57+
gam0002 gamma inf -> inf
58+
gam0003 gamma -inf -> nan invalid
59+
gam0004 gamma nan -> nan
60+
61+
-- negative integers inputs are invalid
62+
gam0010 gamma -1 -> nan invalid
63+
gam0011 gamma -2 -> nan invalid
64+
gam0012 gamma -1e16 -> nan invalid
65+
gam0013 gamma -1e300 -> nan invalid
66+
67+
-- small positive integers give factorials
68+
gam0020 gamma 1 -> 1
69+
gam0021 gamma 2 -> 1
70+
gam0022 gamma 3 -> 2
71+
gam0023 gamma 4 -> 6
72+
gam0024 gamma 5 -> 24
73+
gam0025 gamma 6 -> 120
74+
75+
-- half integers
76+
gam0030 gamma 0.5 -> 1.7724538509055161
77+
gam0031 gamma 1.5 -> 0.88622692545275805
78+
gam0032 gamma 2.5 -> 1.3293403881791370
79+
gam0033 gamma 3.5 -> 3.3233509704478426
80+
gam0034 gamma -0.5 -> -3.5449077018110322
81+
gam0035 gamma -1.5 -> 2.3632718012073548
82+
gam0036 gamma -2.5 -> -0.94530872048294190
83+
gam0037 gamma -3.5 -> 0.27008820585226911
84+
85+
-- values near 0
86+
gam0040 gamma 0.1 -> 9.5135076986687306
87+
gam0041 gamma 0.01 -> 99.432585119150602
88+
gam0042 gamma 1e-8 -> 99999999.422784343
89+
gam0043 gamma 1e-16 -> 10000000000000000
90+
gam0044 gamma 1e-30 -> 9.9999999999999988e+29
91+
gam0045 gamma 1e-160 -> 1.0000000000000000e+160
92+
gam0046 gamma 1e-308 -> 1.0000000000000000e+308
93+
gam0047 gamma 5.6e-309 -> 1.7857142857142848e+308
94+
gam0048 gamma 5.5e-309 -> inf overflow
95+
gam0049 gamma 1e-309 -> inf overflow
96+
gam0050 gamma 1e-323 -> inf overflow
97+
gam0051 gamma 5e-324 -> inf overflow
98+
gam0060 gamma -0.1 -> -10.686287021193193
99+
gam0061 gamma -0.01 -> -100.58719796441078
100+
gam0062 gamma -1e-8 -> -100000000.57721567
101+
gam0063 gamma -1e-16 -> -10000000000000000
102+
gam0064 gamma -1e-30 -> -9.9999999999999988e+29
103+
gam0065 gamma -1e-160 -> -1.0000000000000000e+160
104+
gam0066 gamma -1e-308 -> -1.0000000000000000e+308
105+
gam0067 gamma -5.6e-309 -> -1.7857142857142848e+308
106+
gam0068 gamma -5.5e-309 -> -inf overflow
107+
gam0069 gamma -1e-309 -> -inf overflow
108+
gam0070 gamma -1e-323 -> -inf overflow
109+
gam0071 gamma -5e-324 -> -inf overflow
110+
111+
-- values near negative integers
112+
gam0080 gamma -0.99999999999999989 -> -9007199254740992.0
113+
gam0081 gamma -1.0000000000000002 -> 4503599627370495.5
114+
gam0082 gamma -1.9999999999999998 -> 2251799813685248.5
115+
gam0083 gamma -2.0000000000000004 -> -1125899906842623.5
116+
gam0084 gamma -100.00000000000001 -> -7.5400833348831090e-145
117+
gam0085 gamma -99.999999999999986 -> 7.5400833348840962e-145
118+
119+
-- large inputs
120+
gam0100 gamma 170 -> 4.2690680090047051e+304
121+
gam0101 gamma 171 -> 7.2574156153079990e+306
122+
gam0102 gamma 171.624 -> 1.7942117599248104e+308
123+
gam0103 gamma 171.625 -> inf overflow
124+
gam0104 gamma 172 -> inf overflow
125+
gam0105 gamma 2000 -> inf overflow
126+
gam0106 gamma 1.7e308 -> inf overflow
127+
128+
-- inputs for which gamma(x) is tiny
129+
gam0120 gamma -100.5 -> -3.3536908198076787e-159
130+
gam0121 gamma -160.5 -> -5.2555464470078293e-286
131+
gam0122 gamma -170.5 -> -3.3127395215386074e-308
132+
gam0123 gamma -171.5 -> 1.9316265431711902e-310
133+
gam0124 gamma -176.5 -> -1.1956388629358166e-321
134+
gam0125 gamma -177.5 -> 4.9406564584124654e-324
135+
gam0126 gamma -178.5 -> -0.0
136+
gam0127 gamma -179.5 -> 0.0
137+
gam0128 gamma -201.0001 -> 0.0
138+
gam0129 gamma -202.9999 -> -0.0
139+
gam0130 gamma -1000.5 -> -0.0
140+
gam0131 gamma -1000000000.3 -> -0.0
141+
gam0132 gamma -4503599627370495.5 -> 0.0
142+
143+
-- inputs that cause problems for the standard reflection formula,
144+
-- thanks to loss of accuracy in 1-x
145+
gam0140 gamma -63.349078729022985 -> 4.1777971677761880e-88
146+
gam0141 gamma -127.45117632943295 -> 1.1831110896236810e-214

Lib/test/test_math.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import sys
99
import random
10+
import struct
1011

1112
eps = 1E-05
1213
NAN = float('nan')
@@ -29,8 +30,50 @@
2930
else:
3031
file = __file__
3132
test_dir = os.path.dirname(file) or os.curdir
33+
math_testcases = os.path.join(test_dir, 'math_testcases.txt')
3234
test_file = os.path.join(test_dir, 'cmath_testcases.txt')
3335

36+
def to_ulps(x):
37+
"""Convert a non-NaN float x to an integer, in such a way that
38+
adjacent floats are converted to adjacent integers. Then
39+
abs(ulps(x) - ulps(y)) gives the difference in ulps between two
40+
floats.
41+
42+
The results from this function will only make sense on platforms
43+
where C doubles are represented in IEEE 754 binary64 format.
44+
45+
"""
46+
n = struct.unpack('q', struct.pack('<d', x))[0]
47+
if n < 0:
48+
n = ~(n+2**63)
49+
return n
50+
51+
52+
def parse_mtestfile(fname):
53+
"""Parse a file with test values
54+
55+
-- starts a comment
56+
blank lines, or lines containing only a comment, are ignored
57+
other lines are expected to have the form
58+
id fn arg -> expected [flag]*
59+
60+
"""
61+
with open(fname) as fp:
62+
for line in fp:
63+
# strip comments, and skip blank lines
64+
if '--' in line:
65+
line = line[:line.index('--')]
66+
if not line.strip():
67+
continue
68+
69+
lhs, rhs = line.split('->')
70+
id, fn, arg = lhs.split()
71+
rhs_pieces = rhs.split()
72+
exp = rhs_pieces[0]
73+
flags = rhs_pieces[1:]
74+
75+
yield (id, fn, float(arg), float(exp), flags)
76+
3477
def parse_testfile(fname):
3578
"""Parse a file with test values
3679
@@ -884,6 +927,51 @@ def test_testfile(self):
884927
self.fail(message)
885928
self.ftest("%s:%s(%r)" % (id, fn, ar), result, er)
886929

930+
@unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
931+
"test requires IEEE 754 doubles")
932+
def test_mtestfile(self):
933+
ALLOWED_ERROR = 20 # permitted error, in ulps
934+
fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}"
935+
936+
failures = []
937+
for id, fn, arg, expected, flags in parse_mtestfile(math_testcases):
938+
func = getattr(math, fn)
939+
940+
if 'invalid' in flags or 'divide-by-zero' in flags:
941+
expected = 'ValueError'
942+
elif 'overflow' in flags:
943+
expected = 'OverflowError'
944+
945+
try:
946+
got = func(arg)
947+
except ValueError:
948+
got = 'ValueError'
949+
except OverflowError:
950+
got = 'OverflowError'
951+
952+
diff_ulps = None
953+
if isinstance(got, float) and isinstance(expected, float):
954+
if math.isnan(expected) and math.isnan(got):
955+
continue
956+
if not math.isnan(expected) and not math.isnan(got):
957+
diff_ulps = to_ulps(expected) - to_ulps(got)
958+
if diff_ulps <= ALLOWED_ERROR:
959+
continue
960+
961+
if isinstance(got, str) and isinstance(expected, str):
962+
if got == expected:
963+
continue
964+
965+
fail_msg = fail_fmt.format(id, fn, arg, expected, got)
966+
if diff_ulps is not None:
967+
fail_msg += ' ({} ulps)'.format(diff_ulps)
968+
failures.append(fail_msg)
969+
970+
if failures:
971+
self.fail('Failures in test_mtestfile:\n ' +
972+
'\n '.join(failures))
973+
974+
887975
def test_main():
888976
from doctest import DocFileSuite
889977
suite = unittest.TestSuite()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ Library
201201

202202
Extension Modules
203203
-----------------
204+
205+
- Issue #3366: Add gamma function to math module.
206+
204207
- Issue #6877: It is now possible to link the readline extension to the
205208
libedit readline emulation on OSX 10.5 or later.
206209

0 commit comments

Comments
 (0)