Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Lib/test/test_cmath.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ def test_constants(self):
self.assertAlmostEqual(cmath.e, e_expected, places=9,
msg="cmath.e is {}; should be {}".format(cmath.e, e_expected))

def test_precomputed_constants(self):
self.assertEqual(
cmath.acos(complex(math.inf, math.inf)).real,
math.pi / 4,
)
self.assertEqual(
cmath.acos(complex(0.0, math.inf)).real,
math.pi / 2,
)
self.assertEqual(
cmath.acos(complex(-math.inf, math.inf)).real,
math.pi * 3 / 4,
)

def test_infinity_and_nan_constants(self):
self.assertEqual(cmath.inf.real, math.inf)
self.assertEqual(cmath.inf.imag, 0.0)
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ def testCosh(self):

def testDegrees(self):
self.assertRaises(TypeError, math.degrees)
self.assertEqual(math.degrees(1.0), 180.0 / math.pi)
self.ftest('degrees(pi)', math.degrees(math.pi), 180.0)
self.ftest('degrees(pi/2)', math.degrees(math.pi/2), 90.0)
self.ftest('degrees(-pi/4)', math.degrees(-math.pi/4), -45.0)
Expand Down Expand Up @@ -1748,6 +1749,7 @@ def testPow(self):

def testRadians(self):
self.assertRaises(TypeError, math.radians)
self.assertEqual(math.radians(1.0), math.pi / 180.0)
self.ftest('radians(180)', math.radians(180), math.pi)
self.ftest('radians(90)', math.radians(90), math.pi/2)
self.ftest('radians(-45)', math.radians(-45), -math.pi/4)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix the Windows build when using the MSVC ``/fp:strict`` option.
91 changes: 58 additions & 33 deletions Modules/cmathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,40 @@ special_type(double d)
return ST_NINF;
}

#define P Py_MATH_PI
/* Precomputed for static initialization with MSVC /fp:strict. */
#define P14 0.78539816339744830962 /* P/4: 0x3fe921fb54442d18 */
#define P12 1.57079632679489661923 /* P/2: 0x3ff921fb54442d18 */
#define P34 2.35619449019234492885 /* P*3/4: 0x4002d97c7f3321d2 */
#define INF INFINITY
/* MSVC /fp:strict does not accept NAN in static initializers. This finite
value does not otherwise occur in the tables and is decoded when read. */
#define N 9.5426319407711027e33
#define U -9.5426319407711027e33 /* unlikely value, used as placeholder */

static Py_complex
special_value(const Py_complex table[7][7],
enum special_types real_type,
enum special_types imag_type)
{
Py_complex value = table[real_type][imag_type];
if (value.real == N) {
value.real = fabs(nan(""));
}
if (value.imag == N) {
value.imag = fabs(nan(""));
}
return value;
}

#define SPECIAL_VALUE(z, table) \
if (!isfinite((z).real) || !isfinite((z).imag)) { \
errno = 0; \
return table[special_type((z).real)] \
[special_type((z).imag)]; \
return special_value( \
table, special_type((z).real), \
special_type((z).imag)); \
}

#define P Py_MATH_PI
#define P14 0.25*Py_MATH_PI
#define P12 0.5*Py_MATH_PI
#define P34 0.75*Py_MATH_PI
#define INF INFINITY
#define N Py_NAN
#define U -9.5426319407711027e33 /* unlikely value, used as placeholder */

/* First, the C functions that do the real work. Each of the c_*
functions computes and returns the C99 Annex G recommended result
and also sets errno as follows: errno = 0 if no floating-point
Expand All @@ -163,7 +182,7 @@ special_type(double d)
raised.
*/

static Py_complex acos_special_values[7][7] = {
static const Py_complex acos_special_values[7][7] = {
{ {P34,INF}, {P,INF}, {P,INF}, {P,-INF}, {P,-INF}, {P34,-INF}, {N,INF} },
{ {P12,INF}, {U,U}, {U,U}, {U,U}, {U,U}, {P12,-INF}, {N,N} },
{ {P12,INF}, {U,U}, {P12,0.}, {P12,-0.}, {U,U}, {P12,-INF}, {P12,N} },
Expand Down Expand Up @@ -209,7 +228,7 @@ cmath_acos_impl(PyObject *module, Py_complex z)
}


static Py_complex acosh_special_values[7][7] = {
static const Py_complex acosh_special_values[7][7] = {
{ {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} },
{ {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} },
{ {INF,-P12}, {U,U}, {0.,-P12}, {0.,P12}, {U,U}, {INF,P12}, {N,P12} },
Expand Down Expand Up @@ -272,7 +291,7 @@ cmath_asin_impl(PyObject *module, Py_complex z)
}


static Py_complex asinh_special_values[7][7] = {
static const Py_complex asinh_special_values[7][7] = {
{ {-INF,-P14}, {-INF,-0.}, {-INF,-0.}, {-INF,0.}, {-INF,0.}, {-INF,P14}, {-INF,N} },
{ {-INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-INF,P12}, {N,N} },
{ {-INF,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-INF,P12}, {N,N} },
Expand Down Expand Up @@ -341,7 +360,7 @@ cmath_atan_impl(PyObject *module, Py_complex z)
}


static Py_complex atanh_special_values[7][7] = {
static const Py_complex atanh_special_values[7][7] = {
{ {-0.,-P12}, {-0.,-P12}, {-0.,-P12}, {-0.,P12}, {-0.,P12}, {-0.,P12}, {-0.,N} },
{ {-0.,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-0.,P12}, {N,N} },
{ {-0.,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.,P12}, {-0.,N} },
Expand Down Expand Up @@ -422,7 +441,7 @@ cmath_cos_impl(PyObject *module, Py_complex z)


/* cosh(infinity + i*y) needs to be dealt with specially */
static Py_complex cosh_special_values[7][7] = {
static const Py_complex cosh_special_values[7][7] = {
{ {INF,N}, {U,U}, {INF,0.}, {INF,-0.}, {U,U}, {INF,N}, {INF,N} },
{ {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} },
{ {N,0.}, {U,U}, {1.,0.}, {1.,-0.}, {U,U}, {N,0.}, {N,0.} },
Expand Down Expand Up @@ -459,8 +478,9 @@ cmath_cosh_impl(PyObject *module, Py_complex z)
}
}
else {
r = cosh_special_values[special_type(z.real)]
[special_type(z.imag)];
r = special_value(cosh_special_values,
special_type(z.real),
special_type(z.imag));
}
/* need to set errno = EDOM if y is +/- infinity and x is not
a NaN */
Expand Down Expand Up @@ -492,7 +512,7 @@ cmath_cosh_impl(PyObject *module, Py_complex z)

/* exp(infinity + i*y) and exp(-infinity + i*y) need special treatment for
finite y */
static Py_complex exp_special_values[7][7] = {
static const Py_complex exp_special_values[7][7] = {
{ {0.,0.}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,0.}, {0.,0.} },
{ {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} },
{ {N,N}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,N}, {N,N} },
Expand Down Expand Up @@ -528,8 +548,9 @@ cmath_exp_impl(PyObject *module, Py_complex z)
}
}
else {
r = exp_special_values[special_type(z.real)]
[special_type(z.imag)];
r = special_value(exp_special_values,
special_type(z.real),
special_type(z.imag));
}
/* need to set errno = EDOM if y is +/- infinity and x is not
a NaN and not -infinity */
Expand Down Expand Up @@ -559,7 +580,7 @@ cmath_exp_impl(PyObject *module, Py_complex z)
return r;
}

static Py_complex log_special_values[7][7] = {
static const Py_complex log_special_values[7][7] = {
{ {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} },
{ {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} },
{ {INF,-P12}, {U,U}, {-INF,-P}, {-INF,P}, {U,U}, {INF,P12}, {N,N} },
Expand Down Expand Up @@ -683,7 +704,7 @@ cmath_sin_impl(PyObject *module, Py_complex z)


/* sinh(infinity + i*y) needs to be dealt with specially */
static Py_complex sinh_special_values[7][7] = {
static const Py_complex sinh_special_values[7][7] = {
{ {INF,N}, {U,U}, {-INF,-0.}, {-INF,0.}, {U,U}, {INF,N}, {INF,N} },
{ {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} },
{ {0.,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {0.,N}, {0.,N} },
Expand Down Expand Up @@ -721,8 +742,9 @@ cmath_sinh_impl(PyObject *module, Py_complex z)
}
}
else {
r = sinh_special_values[special_type(z.real)]
[special_type(z.imag)];
r = special_value(sinh_special_values,
special_type(z.real),
special_type(z.imag));
}
/* need to set errno = EDOM if y is +/- infinity and x is not
a NaN */
Expand Down Expand Up @@ -750,7 +772,7 @@ cmath_sinh_impl(PyObject *module, Py_complex z)
}


static Py_complex sqrt_special_values[7][7] = {
static const Py_complex sqrt_special_values[7][7] = {
{ {INF,-INF}, {0.,-INF}, {0.,-INF}, {0.,INF}, {0.,INF}, {INF,INF}, {N,INF} },
{ {INF,-INF}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,INF}, {N,N} },
{ {INF,-INF}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,INF}, {N,N} },
Expand Down Expand Up @@ -857,7 +879,7 @@ cmath_tan_impl(PyObject *module, Py_complex z)


/* tanh(infinity + i*y) needs to be dealt with specially */
static Py_complex tanh_special_values[7][7] = {
static const Py_complex tanh_special_values[7][7] = {
{ {-1.,0.}, {U,U}, {-1.,-0.}, {-1.,0.}, {U,U}, {-1.,0.}, {-1.,0.} },
{ {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} },
{ {-0.0,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.0,N}, {-0.,N} },
Expand Down Expand Up @@ -909,8 +931,9 @@ cmath_tanh_impl(PyObject *module, Py_complex z)
}
}
else {
r = tanh_special_values[special_type(z.real)]
[special_type(z.imag)];
r = special_value(tanh_special_values,
special_type(z.real),
special_type(z.imag));
}
/* need to set errno = EDOM if z.imag is +/-infinity and
z.real is finite */
Expand Down Expand Up @@ -1049,7 +1072,7 @@ cmath_polar_impl(PyObject *module, Py_complex z)

*/

static Py_complex rect_special_values[7][7] = {
static const Py_complex rect_special_values[7][7] = {
{ {INF,N}, {U,U}, {-INF,0.}, {-INF,-0.}, {U,U}, {INF,N}, {INF,N} },
{ {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} },
{ {0.,0.}, {U,U}, {-0.,0.}, {-0.,-0.}, {U,U}, {0.,0.}, {0.,0.} },
Expand Down Expand Up @@ -1093,8 +1116,9 @@ cmath_rect_impl(PyObject *module, double r, double phi)
}
}
else {
z = rect_special_values[special_type(r)]
[special_type(phi)];
z = special_value(rect_special_values,
special_type(r),
special_type(phi));
}
/* need to set errno = EDOM if r is a nonzero number and phi
is infinite */
Expand Down Expand Up @@ -1278,10 +1302,11 @@ cmath_exec(PyObject *mod)
if (PyModule_Add(mod, "infj", PyComplex_FromCComplex(infj)) < 0) {
return -1;
}
if (PyModule_Add(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
double nan_value = fabs(nan(""));
if (PyModule_Add(mod, "nan", PyFloat_FromDouble(nan_value)) < 0) {
return -1;
}
Py_complex nanj = {0.0, fabs(Py_NAN)};
Py_complex nanj = {0.0, nan_value};
if (PyModule_Add(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) {
return -1;
}
Expand Down
10 changes: 7 additions & 3 deletions Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2610,8 +2610,11 @@ math_pow_impl(PyObject *module, double x, double y)
}


static const double degToRad = Py_MATH_PI / 180.0;
static const double radToDeg = 180.0 / Py_MATH_PI;
/* Precomputed for static initialization with MSVC /fp:strict. */
/* Py_MATH_PI / 180: binary64 0x3f91df46a2529d39 */
static const double degToRad = 0.017453292519943295769236907684886;
/* 180 / Py_MATH_PI: binary64 0x404ca5dc1a63c1f8 */
static const double radToDeg = 57.295779513082320876798154814105;

/*[clinic input]
math.degrees
Expand Down Expand Up @@ -3190,7 +3193,8 @@ math_exec(PyObject *module)
if (PyModule_Add(module, "inf", PyFloat_FromDouble(INFINITY)) < 0) {
return -1;
}
if (PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
if (PyModule_Add(module, "nan",
PyFloat_FromDouble(fabs(nan("")))) < 0) {
return -1;
}

Expand Down
6 changes: 4 additions & 2 deletions Python/dtoa.c
Original file line number Diff line number Diff line change
Expand Up @@ -1108,8 +1108,10 @@ tens[] = {
static const double
bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
9007199254740992.*9007199254740992.e-256
/* = 2^106 * 1e-256 */
8.112963841460668e-225
/* 2^106 * 1e-256, precomputed for
MSVC /fp:strict; binary64
0x1168062864ac6f43 */
};
/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
Expand Down
Loading