Add hyperbolic functions (#2508)
* add hyperbolic functions * add hyperbolic function tests * changelog * add inverse hyperbolic functions for old compilers
This commit is contained in:
parent
fc92290bb9
commit
d8c04011ea
@ -17,6 +17,7 @@
|
||||
- improve buffer and target save file format selection
|
||||
- added VipsForeignPpmFormat, @format arg to ppm savers
|
||||
- add fail-on to give better control over loader error sensitivity
|
||||
- add hyperbolic functions sinh, cosh, tanh, asinh, acosh, atanh [hroskes]
|
||||
|
||||
16/8/21 started 8.11.4
|
||||
- fix off-by-one error in new rank fast path
|
||||
|
@ -1375,6 +1375,60 @@ public:
|
||||
return( math( VIPS_OPERATION_MATH_ATAN, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic sine of each pixel. Angles are in degrees.
|
||||
*/
|
||||
VImage
|
||||
sinh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_SINH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic cosine of each pixel. Angles are in degrees.
|
||||
*/
|
||||
VImage
|
||||
cosh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_COSH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic tangent of each pixel. Angles are in degrees.
|
||||
*/
|
||||
VImage
|
||||
tanh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_TANH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic arc sine of each pixel. Angles are in radians.
|
||||
*/
|
||||
VImage
|
||||
asinh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_ASINH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic arc cosine of each pixel. Angles are in radians.
|
||||
*/
|
||||
VImage
|
||||
acosh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_ACOSH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hyperbolic arc tangent of each pixel. Angles are in radians.
|
||||
*/
|
||||
VImage
|
||||
atanh( VOption *options = 0 ) const
|
||||
{
|
||||
return( math( VIPS_OPERATION_MATH_ATANH, options ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the natural log of each pixel.
|
||||
*/
|
||||
|
@ -82,7 +82,7 @@ def gen_function_list():
|
||||
'draw_rect': ['draw_rect1', 'draw_point', 'draw_point1'],
|
||||
'extract_area': ['crop'],
|
||||
'linear': ['linear1'],
|
||||
'math': ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'exp', 'exp10', 'log', 'log10'],
|
||||
'math': ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', 'exp', 'exp10', 'log', 'log10'],
|
||||
'math2': ['pow', 'wop', 'atan2'],
|
||||
'rank': ['median'],
|
||||
'relational': ['equal', 'notequal', 'less', 'lesseq', 'more', 'moreeq'],
|
||||
|
@ -129,6 +129,28 @@ vips_math_build( VipsObject *object )
|
||||
g_assert_not_reached(); \
|
||||
}
|
||||
|
||||
/* inverse hyperbolic functions for old compilers
|
||||
they were added to the standard in C99 and C++11
|
||||
*/
|
||||
#if ( \
|
||||
(defined(__cplusplus) && __cplusplus >= 201103L) \
|
||||
|| (defined(__STDC__) && __STDC_VERSION__ >= 199901L) \
|
||||
)
|
||||
#define HAS_INVERSE_HYPERBOLICS 1
|
||||
#else
|
||||
#define HAS_INVERSE_HYPERBOLICS 0
|
||||
#endif
|
||||
|
||||
#if HAS_INVERSE_HYPERBOLICS
|
||||
#define ASINH sinh
|
||||
#define ACOSH cosh
|
||||
#define ATANH tanh
|
||||
#else
|
||||
#define ASINH( X ) log((X) + sqrt( (X)*(X)+1 ))
|
||||
#define ACOSH( X ) log((X) + sqrt( (X)*(X)-1 ))
|
||||
#define ATANH( X ) (0.5 * log( (1+(X)) / (1-(X)) ))
|
||||
#endif
|
||||
|
||||
/* sin/cos/tan in degrees.
|
||||
*/
|
||||
#define DSIN( X ) (sin( VIPS_RAD( X ) ))
|
||||
@ -164,6 +186,12 @@ vips_math_buffer( VipsArithmetic *arithmetic,
|
||||
case VIPS_OPERATION_MATH_ASIN: SWITCH( ADSIN ); break;
|
||||
case VIPS_OPERATION_MATH_ACOS: SWITCH( ADCOS ); break;
|
||||
case VIPS_OPERATION_MATH_ATAN: SWITCH( ADTAN ); break;
|
||||
case VIPS_OPERATION_MATH_SINH: SWITCH( sinh ); break;
|
||||
case VIPS_OPERATION_MATH_COSH: SWITCH( cosh ); break;
|
||||
case VIPS_OPERATION_MATH_TANH: SWITCH( tanh ); break;
|
||||
case VIPS_OPERATION_MATH_ASINH: SWITCH( ASINH ); break;
|
||||
case VIPS_OPERATION_MATH_ACOSH: SWITCH( ACOSH ); break;
|
||||
case VIPS_OPERATION_MATH_ATANH: SWITCH( ATANH ); break;
|
||||
case VIPS_OPERATION_MATH_LOG: SWITCH( LOGZ ); break;
|
||||
case VIPS_OPERATION_MATH_LOG10: SWITCH( LOGZ10 ); break;
|
||||
case VIPS_OPERATION_MATH_EXP: SWITCH( exp ); break;
|
||||
@ -398,6 +426,144 @@ vips_atan( VipsImage *in, VipsImage **out, ... )
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_sinh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_SINH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_sinh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_SINH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_cosh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_COSH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_cosh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_COSH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_tanh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_TANH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_tanh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_TANH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_asinh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_ASINH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_asinh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_ASINH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_acosh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_ACOSH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_acosh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_ACOSH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_atanh: (method)
|
||||
* @in: input #VipsImage
|
||||
* @out: (out): output #VipsImage
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Perform #VIPS_OPERATION_MATH_ATANH on an image. See vips_math().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_atanh( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_mathv( in, out, VIPS_OPERATION_MATH_ATANH, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_log: (method)
|
||||
* @in: input #VipsImage
|
||||
|
@ -46,6 +46,12 @@ extern "C" {
|
||||
* @VIPS_OPERATION_MATH_ASIN: asin(), angles in degrees
|
||||
* @VIPS_OPERATION_MATH_ACOS: acos(), angles in degrees
|
||||
* @VIPS_OPERATION_MATH_ATAN: atan(), angles in degrees
|
||||
* @VIPS_OPERATION_MATH_SINH: sinh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_COSH: cosh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_TANH: tanh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_ASINH: asinh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_ACOSH: acosh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_ATANH: atanh(), angles in radians
|
||||
* @VIPS_OPERATION_MATH_LOG: log base e
|
||||
* @VIPS_OPERATION_MATH_LOG10: log base 10
|
||||
* @VIPS_OPERATION_MATH_EXP: e to the something
|
||||
@ -60,6 +66,12 @@ typedef enum {
|
||||
VIPS_OPERATION_MATH_ASIN,
|
||||
VIPS_OPERATION_MATH_ACOS,
|
||||
VIPS_OPERATION_MATH_ATAN,
|
||||
VIPS_OPERATION_MATH_SINH,
|
||||
VIPS_OPERATION_MATH_COSH,
|
||||
VIPS_OPERATION_MATH_TANH,
|
||||
VIPS_OPERATION_MATH_ASINH,
|
||||
VIPS_OPERATION_MATH_ACOSH,
|
||||
VIPS_OPERATION_MATH_ATANH,
|
||||
VIPS_OPERATION_MATH_LOG,
|
||||
VIPS_OPERATION_MATH_LOG10,
|
||||
VIPS_OPERATION_MATH_EXP,
|
||||
|
@ -18,6 +18,12 @@ vips_operation_math_get_type( void )
|
||||
{VIPS_OPERATION_MATH_ASIN, "VIPS_OPERATION_MATH_ASIN", "asin"},
|
||||
{VIPS_OPERATION_MATH_ACOS, "VIPS_OPERATION_MATH_ACOS", "acos"},
|
||||
{VIPS_OPERATION_MATH_ATAN, "VIPS_OPERATION_MATH_ATAN", "atan"},
|
||||
{VIPS_OPERATION_MATH_SINH, "VIPS_OPERATION_MATH_SINH", "sinh"},
|
||||
{VIPS_OPERATION_MATH_COSH, "VIPS_OPERATION_MATH_COSH", "cosh"},
|
||||
{VIPS_OPERATION_MATH_TANH, "VIPS_OPERATION_MATH_TANH", "tanh"},
|
||||
{VIPS_OPERATION_MATH_ASINH, "VIPS_OPERATION_MATH_ASINH", "asinh"},
|
||||
{VIPS_OPERATION_MATH_ACOSH, "VIPS_OPERATION_MATH_ACOSH", "acosh"},
|
||||
{VIPS_OPERATION_MATH_ATANH, "VIPS_OPERATION_MATH_ATANH", "atanh"},
|
||||
{VIPS_OPERATION_MATH_LOG, "VIPS_OPERATION_MATH_LOG", "log"},
|
||||
{VIPS_OPERATION_MATH_LOG10, "VIPS_OPERATION_MATH_LOG10", "log10"},
|
||||
{VIPS_OPERATION_MATH_EXP, "VIPS_OPERATION_MATH_EXP", "exp"},
|
||||
|
@ -472,7 +472,88 @@ class TestArithmetic:
|
||||
im = (pyvips.Image.black(100, 100) + [1, 2, 3]) / 3.0
|
||||
self.run_unary([im], my_atan, fmt=noncomplex_formats)
|
||||
|
||||
# this require pyvips 2.1.16 for atan2
|
||||
# this requires pyvips 2.1.16 for sinh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_sinh(self):
|
||||
def my_sinh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.sinh()
|
||||
else:
|
||||
return math.sinh(x)
|
||||
|
||||
self.run_unary(self.all_images, my_sinh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for cosh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_cosh(self):
|
||||
def my_cosh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.cosh()
|
||||
else:
|
||||
return math.cosh(x)
|
||||
|
||||
self.run_unary(self.all_images, my_cosh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for tanh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_tanh(self):
|
||||
def my_tanh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.tanh()
|
||||
else:
|
||||
return math.tanh(x)
|
||||
|
||||
self.run_unary(self.all_images, my_tanh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for asinh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_asinh(self):
|
||||
def my_asinh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.asinh()
|
||||
else:
|
||||
return math.asinh(x)
|
||||
|
||||
im = (pyvips.Image.black(100, 100) + [1, 2, 3]) / 3.0
|
||||
self.run_unary([im], my_asinh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for acosh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_acosh(self):
|
||||
def my_acosh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.acosh()
|
||||
else:
|
||||
return math.acosh(x)
|
||||
|
||||
im = (pyvips.Image.black(100, 100) + [1, 2, 3]) / 3.0
|
||||
self.run_unary([im], my_acosh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for atanh
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
def test_atanh(self):
|
||||
def my_atanh(x):
|
||||
if isinstance(x, pyvips.Image):
|
||||
return x.atanh()
|
||||
else:
|
||||
return math.atanh(x)
|
||||
|
||||
im = (pyvips.Image.black(100, 100) + [1, 2, 3]) / 3.0
|
||||
self.run_unary([im], my_atanh, fmt=noncomplex_formats)
|
||||
|
||||
# this requires pyvips 2.1.16 for atan2
|
||||
@pytest.mark.skipif(versiontuple(pyvips.__version__) <
|
||||
versiontuple('2.1.16'),
|
||||
reason='your pyvips is too old')
|
||||
|
Loading…
Reference in New Issue
Block a user