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

Skip to content

Generate ufuncs for frexp and ldexp #4852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2014
Merged
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
36 changes: 35 additions & 1 deletion numpy/core/code_generators/generate_umath.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
class FullTypeDescr(object):
pass

class FuncNameSuffix(object):
"""Stores the suffix to append when generating functions names.
"""
def __init__(self, suffix):
self.suffix = suffix

class TypeDescription(object):
"""Type signature for a ufunc.

Expand Down Expand Up @@ -795,6 +801,30 @@ def english_upper(s):
None,
TD(flts),
),
'ldexp' :
Ufunc(2, 1, None,
docstrings.get('numpy.core.umath.ldexp'),
None,
[TypeDescription('e', None, 'ei', 'e'),
TypeDescription('f', None, 'fi', 'f'),
TypeDescription('e', FuncNameSuffix('long'), 'el', 'e'),
TypeDescription('f', FuncNameSuffix('long'), 'fl', 'f'),
TypeDescription('d', None, 'di', 'd'),
TypeDescription('d', FuncNameSuffix('long'), 'dl', 'd'),
TypeDescription('g', None, 'gi', 'g'),
TypeDescription('g', FuncNameSuffix('long'), 'gl', 'g'),
],
),
'frexp' :
Ufunc(1, 2, None,
docstrings.get('numpy.core.umath.frexp'),
None,
[TypeDescription('e', None, 'e', 'ei'),
TypeDescription('f', None, 'f', 'fi'),
TypeDescription('d', None, 'd', 'di'),
TypeDescription('g', None, 'g', 'gi'),
],
)
}

if sys.version_info[0] >= 3:
Expand Down Expand Up @@ -854,7 +884,7 @@ def make_arrays(funcdict):
thedict = chartotype1 # one input and one output

for t in uf.type_descriptions:
if t.func_data not in (None, FullTypeDescr):
if t.func_data not in (None, FullTypeDescr) and not isinstance(t.func_data, FuncNameSuffix):
funclist.append('NULL')
astype = ''
if not t.astype is None:
Expand All @@ -880,6 +910,10 @@ def make_arrays(funcdict):
tname = english_upper(chartoname[t.type])
datalist.append('(void *)NULL')
funclist.append('%s_%s_%s_%s' % (tname, t.in_, t.out, name))
elif isinstance(t.func_data, FuncNameSuffix):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it not be better to put this if first? I think this if block can be cleaned up a bit.

datalist.append('(void *)NULL')
tname = english_upper(chartoname[t.type])
funclist.append('%s_%s_%s' % (tname, name, t.func_data.suffix))
else:
datalist.append('(void *)NULL')
tname = english_upper(chartoname[t.type])
Expand Down
6 changes: 0 additions & 6 deletions numpy/core/code_generators/ufunc_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3324,9 +3324,6 @@ def add_newdoc(place, name, doc):

""")

# This doc is not currently used, but has been converted to a C string
# that can be found in numpy/core/src/umath/umathmodule.c where the
# frexp ufunc is constructed.
add_newdoc('numpy.core.umath', 'frexp',
"""
Decompose the elements of x into mantissa and twos exponent.
Expand Down Expand Up @@ -3372,9 +3369,6 @@ def add_newdoc(place, name, doc):

""")

# This doc is not currently used, but has been converted to a C string
# that can be found in numpy/core/src/umath/umathmodule.c where the
# ldexp ufunc is constructed.
add_newdoc('numpy.core.umath', 'ldexp',
"""
Returns x1 * 2**x2, element-wise.
Expand Down
10 changes: 6 additions & 4 deletions numpy/core/include/numpy/npy_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,6 @@ double npy_tanh(double x);
double npy_asin(double x);
double npy_acos(double x);
double npy_atan(double x);
double npy_aexp(double x);
double npy_alog(double x);
double npy_asqrt(double x);
double npy_afabs(double x);

double npy_log(double x);
double npy_log10(double x);
Expand All @@ -147,6 +143,8 @@ double npy_log2(double x);
double npy_atan2(double x, double y);
double npy_pow(double x, double y);
double npy_modf(double x, double* y);
double npy_frexp(double x, int* y);
double npy_ldexp(double n, int y);

double npy_copysign(double x, double y);
double npy_nextafter(double x, double y);
Expand Down Expand Up @@ -251,6 +249,8 @@ float npy_powf(float x, float y);
float npy_fmodf(float x, float y);

float npy_modff(float x, float* y);
float npy_frexpf(float x, int* y);
float npy_ldexpf(float x, int y);

float npy_copysignf(float x, float y);
float npy_nextafterf(float x, float y);
Expand Down Expand Up @@ -292,6 +292,8 @@ npy_longdouble npy_powl(npy_longdouble x, npy_longdouble y);
npy_longdouble npy_fmodl(npy_longdouble x, npy_longdouble y);

npy_longdouble npy_modfl(npy_longdouble x, npy_longdouble* y);
npy_longdouble npy_frexpl(npy_longdouble x, int* y);
npy_longdouble npy_ldexpl(npy_longdouble x, int y);

npy_longdouble npy_copysignl(npy_longdouble x, npy_longdouble y);
npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y);
Expand Down
35 changes: 35 additions & 0 deletions numpy/core/src/npymath/npy_math.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ double npy_log2(double x)
* asinh, acosh, atanh
*
* hypot, atan2, pow, fmod, modf
* ldexp, frexp
*
* We assume the above are always available in their double versions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a good assumption for us? It didn't used to be, but admittedly, that was a long time ago.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I suppose I don't really know. I know linux and windows have them both and I'd assume apple does too. Anything beyond that I can't say. Both are part of C89 FWIW. I suppose if we'd like I could add a implementation to npymath.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to follow up here, python uses both of these unconditionally. We're fine.

*
Expand Down Expand Up @@ -405,6 +406,26 @@ double npy_log2(double x)
}
#endif

#ifdef ldexp@c@
#undef ldexp@c@
#endif
#ifndef HAVE_LDEXP@C@
@type@ npy_ldexp@c@(@type@ x, int exp)
{
return (@type@) npy_ldexp((double)x, exp);
}
#endif

#ifdef frexp@c@
#undef frexp@c@
#endif
#ifndef HAVE_FREXP@C@
@type@ npy_frexp@c@(@type@ x, int* exp)
{
return (@type@) npy_frexp(x, exp);
}
#endif

/**end repeat**/


Expand Down Expand Up @@ -451,6 +472,20 @@ double npy_log2(double x)
}
#endif

#ifdef HAVE_LDEXP@C@
@type@ npy_ldexp@c@(@type@ x, int exp)
{
return ldexp@c@(x, exp);
}
#endif

#ifdef HAVE_FREXP@C@
@type@ npy_frexp@c@(@type@ x, int* exp)
{
return frexp@c@(x, exp);
}
#endif

/**end repeat**/


Expand Down
28 changes: 10 additions & 18 deletions numpy/core/src/umath/loops.c.src
Original file line number Diff line number Diff line change
Expand Up @@ -1743,25 +1743,22 @@ NPY_NO_EXPORT void
}
}

#ifdef HAVE_FREXP@C@
NPY_NO_EXPORT void
@TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP_TWO_OUT {
const @type@ in1 = *(@type@ *)ip1;
*((@type@ *)op1) = frexp@c@(in1, (int *)op2);
*((@type@ *)op1) = npy_frexp@c@(in1, (int *)op2);
}
}
#endif

#ifdef HAVE_LDEXP@C@
NPY_NO_EXPORT void
@TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
const int in2 = *(int *)ip2;
*((@type@ *)op1) = ldexp@c@(in1, in2);
*((@type@ *)op1) = npy_ldexp@c@(in1, in2);
}
}

Expand All @@ -1778,23 +1775,22 @@ NPY_NO_EXPORT void
const long in2 = *(long *)ip2;
if (((int)in2) == in2) {
/* Range OK */
*((@type@ *)op1) = ldexp@c@(in1, ((int)in2));
*((@type@ *)op1) = npy_ldexp@c@(in1, ((int)in2));
}
else {
/*
* Outside npy_int range -- also ldexp will overflow in this case,
* given that exponent has less bits than npy_int.
*/
if (in2 > 0) {
*((@type@ *)op1) = ldexp@c@(in1, NPY_MAX_INT);
*((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MAX_INT);
}
else {
*((@type@ *)op1) = ldexp@c@(in1, NPY_MIN_INT);
*((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MIN_INT);
}
}
}
}
#endif

#define @TYPE@_true_divide @TYPE@_divide

Expand Down Expand Up @@ -2059,25 +2055,22 @@ HALF_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(f
}
}

#ifdef HAVE_FREXPF
NPY_NO_EXPORT void
HALF_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP_TWO_OUT {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
*((npy_half *)op1) = npy_float_to_half(frexpf(in1, (int *)op2));
*((npy_half *)op1) = npy_float_to_half(npy_frexpf(in1, (int *)op2));
}
}
#endif

#ifdef HAVE_LDEXPF
NPY_NO_EXPORT void
HALF_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
const int in2 = *(int *)ip2;
*((npy_half *)op1) = npy_float_to_half(ldexpf(in1, in2));
*((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, in2));
}
}

Expand All @@ -2094,23 +2087,22 @@ HALF_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN
const long in2 = *(long *)ip2;
if (((int)in2) == in2) {
/* Range OK */
*((npy_half *)op1) = npy_float_to_half(ldexpf(in1, ((int)in2)));
*((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, ((int)in2)));
}
else {
/*
* Outside npy_int range -- also ldexp will overflow in this case,
* given that exponent has less bits than npy_int.
*/
if (in2 > 0) {
*((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MAX_INT));
*((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MAX_INT));
}
else {
*((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MIN_INT));
*((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MIN_INT));
}
}
}
}
#endif

#define HALF_true_divide HALF_divide

Expand Down
4 changes: 0 additions & 4 deletions numpy/core/src/umath/loops.h.src
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,13 @@ NPY_NO_EXPORT void
NPY_NO_EXPORT void
@TYPE@_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));

#ifdef HAVE_FREXP@C@
NPY_NO_EXPORT void
@TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
#endif

#ifdef HAVE_LDEXP@C@
NPY_NO_EXPORT void
@TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
NPY_NO_EXPORT void
@TYPE@_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func));
#endif

#define @TYPE@_true_divide @TYPE@_divide

Expand Down
Loading