lib/libm: Add acosh, asinh, atanh, tan; get working with stmhal.

acoshf, asinhf, atanhf were added from musl.  mathsincos.c was
split up into its original, separate files (from newlibe-nano-2).
tan was added.

All of the important missing float functions are now implemented,
and pyboard now passes tests/float/math_fun.py (finally!).
This commit is contained in:
Damien George 2014-12-18 14:44:02 +00:00
parent 6936f4626c
commit f04329e93b
18 changed files with 1295 additions and 638 deletions

32
lib/libm/acoshf.c Normal file
View File

@ -0,0 +1,32 @@
/*****************************************************************************/
/*****************************************************************************/
// acoshf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
#include "libm.h"
#if FLT_EVAL_METHOD==2
#undef sqrtf
#define sqrtf sqrtl
#elif FLT_EVAL_METHOD==1
#undef sqrtf
#define sqrtf sqrt
#endif
/* acosh(x) = log(x + sqrt(x*x-1)) */
float acoshf(float x)
{
union {float f; uint32_t i;} u = {x};
uint32_t a = u.i & 0x7fffffff;
if (a < 0x3f800000+(1<<23))
/* |x| < 2, invalid if x < 1 or nan */
/* up to 2ulp error in [1,1.125] */
return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1)));
if (a < 0x3f800000+(12<<23))
/* |x| < 0x1p12 */
return logf(2*x - 1/(x+sqrtf(x*x-1)));
/* x >= 0x1p12 */
return logf(x) + 0.693147180559945309417232121458176568f;
}

34
lib/libm/asinhf.c Normal file
View File

@ -0,0 +1,34 @@
/*****************************************************************************/
/*****************************************************************************/
// asinhf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
#include "libm.h"
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */
float asinhf(float x)
{
union {float f; uint32_t i;} u = {.f = x};
uint32_t i = u.i & 0x7fffffff;
unsigned s = u.i >> 31;
/* |x| */
u.i = i;
x = u.f;
if (i >= 0x3f800000 + (12<<23)) {
/* |x| >= 0x1p12 or inf or nan */
x = logf(x) + 0.693147180559945309417232121458176568f;
} else if (i >= 0x3f800000 + (1<<23)) {
/* |x| >= 2 */
x = logf(2*x + 1/(sqrtf(x*x+1)+x));
} else if (i >= 0x3f800000 - (12<<23)) {
/* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */
x = log1pf(x + x*x/(sqrtf(x*x+1)+1));
} else {
/* |x| < 0x1p-12, raise inexact if x!=0 */
FORCE_EVAL(x + 0x1p120f);
}
return s ? -x : x;
}

34
lib/libm/atanhf.c Normal file
View File

@ -0,0 +1,34 @@
/*****************************************************************************/
/*****************************************************************************/
// atanhf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
#include "libm.h"
/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */
float atanhf(float x)
{
union {float f; uint32_t i;} u = {.f = x};
unsigned s = u.i >> 31;
float_t y;
/* |x| */
u.i &= 0x7fffffff;
y = u.f;
if (u.i < 0x3f800000 - (1<<23)) {
if (u.i < 0x3f800000 - (32<<23)) {
/* handle underflow */
if (u.i < (1<<23))
FORCE_EVAL((float)(y*y));
} else {
/* |x| < 0.5, up to 1.7ulp error */
y = 0.5f*log1pf(2*y + 2*y*y/(1-y));
}
} else {
/* avoid overflow */
y = 0.5f*log1pf(2*(y/(1-y)));
}
return s ? -y : y;
}

202
lib/libm/ef_rem_pio2.c Normal file
View File

@ -0,0 +1,202 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* ef_rem_pio2.c -- float version of e_rem_pio2.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*
*/
/* __ieee754_rem_pio2f(x,y)
*
* return the remainder of x rem pi/2 in y[0]+y[1]
* use __kernel_rem_pio2f()
*/
#include "fdlibm.h"
/*
* Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
*/
#ifdef __STDC__
static const __int32_t two_over_pi[] = {
#else
static __int32_t two_over_pi[] = {
#endif
0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
};
/* This array is like the one in e_rem_pio2.c, but the numbers are
single precision and the last 8 bits are forced to 0. */
#ifdef __STDC__
static const __int32_t npio2_hw[] = {
#else
static __int32_t npio2_hw[] = {
#endif
0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
0x4242c700, 0x42490f00
};
/*
* invpio2: 24 bits of 2/pi
* pio2_1: first 17 bit of pi/2
* pio2_1t: pi/2 - pio2_1
* pio2_2: second 17 bit of pi/2
* pio2_2t: pi/2 - (pio2_1+pio2_2)
* pio2_3: third 17 bit of pi/2
* pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
*/
#ifdef __STDC__
static const float
#else
static float
#endif
zero = 0.0000000000e+00, /* 0x00000000 */
half = 5.0000000000e-01, /* 0x3f000000 */
two8 = 2.5600000000e+02, /* 0x43800000 */
invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
pio2_1t = 1.0804334124e-05, /* 0x37354443 */
pio2_2 = 1.0804273188e-05, /* 0x37354400 */
pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
#ifdef __STDC__
__int32_t __ieee754_rem_pio2f(float x, float *y)
#else
__int32_t __ieee754_rem_pio2f(x,y)
float x,y[];
#endif
{
float z,w,t,r,fn;
float tx[3];
__int32_t i,j,n,ix,hx;
int e0,nx;
GET_FLOAT_WORD(hx,x);
ix = hx&0x7fffffff;
if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */
{y[0] = x; y[1] = 0; return 0;}
if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */
if(hx>0) {
z = x - pio2_1;
if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
y[0] = z - pio2_1t;
y[1] = (z-y[0])-pio2_1t;
} else { /* near pi/2, use 24+24+24 bit pi */
z -= pio2_2;
y[0] = z - pio2_2t;
y[1] = (z-y[0])-pio2_2t;
}
return 1;
} else { /* negative x */
z = x + pio2_1;
if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
y[0] = z + pio2_1t;
y[1] = (z-y[0])+pio2_1t;
} else { /* near pi/2, use 24+24+24 bit pi */
z += pio2_2;
y[0] = z + pio2_2t;
y[1] = (z-y[0])+pio2_2t;
}
return -1;
}
}
if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
t = fabsf(x);
n = (__int32_t) (t*invpio2+half);
fn = (float)n;
r = t-fn*pio2_1;
w = fn*pio2_1t; /* 1st round good to 40 bit */
if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
y[0] = r-w; /* quick check no cancellation */
} else {
__uint32_t high;
j = ix>>23;
y[0] = r-w;
GET_FLOAT_WORD(high,y[0]);
i = j-((high>>23)&0xff);
if(i>8) { /* 2nd iteration needed, good to 57 */
t = r;
w = fn*pio2_2;
r = t-w;
w = fn*pio2_2t-((t-r)-w);
y[0] = r-w;
GET_FLOAT_WORD(high,y[0]);
i = j-((high>>23)&0xff);
if(i>25) { /* 3rd iteration need, 74 bits acc */
t = r; /* will cover all possible cases */
w = fn*pio2_3;
r = t-w;
w = fn*pio2_3t-((t-r)-w);
y[0] = r-w;
}
}
}
y[1] = (r-y[0])-w;
if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
else return n;
}
/*
* all other (large) arguments
*/
if(!FLT_UWORD_IS_FINITE(ix)) {
y[0]=y[1]=x-x; return 0;
}
/* set z = scalbn(|x|,ilogb(x)-7) */
e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */
SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
for(i=0;i<2;i++) {
tx[i] = (float)((__int32_t)(z));
z = (z-tx[i])*two8;
}
tx[2] = z;
nx = 3;
while(tx[nx-1]==zero) nx--; /* skip zero term */
n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
return n;
}

227
lib/libm/fdlibm.h Normal file
View File

@ -0,0 +1,227 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* This file is adapted from from newlib-nano-2, the newlib/libm/common/fdlib.h,
* available from https://github.com/32bitmicro/newlib-nano-2. The main change
* is removal of anything to do with double precision.
*
* Appropriate copyright headers are reproduced below.
*/
/* @(#)fdlibm.h 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include <math.h>
/* Default to XOPEN_MODE. */
#define _XOPEN_MODE
/* Most routines need to check whether a float is finite, infinite, or not a
number, and many need to know whether the result of an operation will
overflow. These conditions depend on whether the largest exponent is
used for NaNs & infinities, or whether it's used for finite numbers. The
macros below wrap up that kind of information:
FLT_UWORD_IS_FINITE(X)
True if a positive float with bitmask X is finite.
FLT_UWORD_IS_NAN(X)
True if a positive float with bitmask X is not a number.
FLT_UWORD_IS_INFINITE(X)
True if a positive float with bitmask X is +infinity.
FLT_UWORD_MAX
The bitmask of FLT_MAX.
FLT_UWORD_HALF_MAX
The bitmask of FLT_MAX/2.
FLT_UWORD_EXP_MAX
The bitmask of the largest finite exponent (129 if the largest
exponent is used for finite numbers, 128 otherwise).
FLT_UWORD_LOG_MAX
The bitmask of log(FLT_MAX), rounded down. This value is the largest
input that can be passed to exp() without producing overflow.
FLT_UWORD_LOG_2MAX
The bitmask of log(2*FLT_MAX), rounded down. This value is the
largest input than can be passed to cosh() without producing
overflow.
FLT_LARGEST_EXP
The largest biased exponent that can be used for finite numbers
(255 if the largest exponent is used for finite numbers, 254
otherwise) */
#ifdef _FLT_LARGEST_EXPONENT_IS_NORMAL
#define FLT_UWORD_IS_FINITE(x) 1
#define FLT_UWORD_IS_NAN(x) 0
#define FLT_UWORD_IS_INFINITE(x) 0
#define FLT_UWORD_MAX 0x7fffffff
#define FLT_UWORD_EXP_MAX 0x43010000
#define FLT_UWORD_LOG_MAX 0x42b2d4fc
#define FLT_UWORD_LOG_2MAX 0x42b437e0
#define HUGE ((float)0X1.FFFFFEP128)
#else
#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
#define FLT_UWORD_IS_NAN(x) ((x)>0x7f800000L)
#define FLT_UWORD_IS_INFINITE(x) ((x)==0x7f800000L)
#define FLT_UWORD_MAX 0x7f7fffffL
#define FLT_UWORD_EXP_MAX 0x43000000
#define FLT_UWORD_LOG_MAX 0x42b17217
#define FLT_UWORD_LOG_2MAX 0x42b2d4fc
#define HUGE ((float)3.40282346638528860e+38)
#endif
#define FLT_UWORD_HALF_MAX (FLT_UWORD_MAX-(1L<<23))
#define FLT_LARGEST_EXP (FLT_UWORD_MAX>>23)
/* Many routines check for zero and subnormal numbers. Such things depend
on whether the target supports denormals or not:
FLT_UWORD_IS_ZERO(X)
True if a positive float with bitmask X is +0. Without denormals,
any float with a zero exponent is a +0 representation. With
denormals, the only +0 representation is a 0 bitmask.
FLT_UWORD_IS_SUBNORMAL(X)
True if a non-zero positive float with bitmask X is subnormal.
(Routines should check for zeros first.)
FLT_UWORD_MIN
The bitmask of the smallest float above +0. Call this number
REAL_FLT_MIN...
FLT_UWORD_EXP_MIN
The bitmask of the float representation of REAL_FLT_MIN's exponent.
FLT_UWORD_LOG_MIN
The bitmask of |log(REAL_FLT_MIN)|, rounding down.
FLT_SMALLEST_EXP
REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported,
-22 if they are).
*/
#ifdef _FLT_NO_DENORMALS
#define FLT_UWORD_IS_ZERO(x) ((x)<0x00800000L)
#define FLT_UWORD_IS_SUBNORMAL(x) 0
#define FLT_UWORD_MIN 0x00800000
#define FLT_UWORD_EXP_MIN 0x42fc0000
#define FLT_UWORD_LOG_MIN 0x42aeac50
#define FLT_SMALLEST_EXP 1
#else
#define FLT_UWORD_IS_ZERO(x) ((x)==0)
#define FLT_UWORD_IS_SUBNORMAL(x) ((x)<0x00800000L)
#define FLT_UWORD_MIN 0x00000001
#define FLT_UWORD_EXP_MIN 0x43160000
#define FLT_UWORD_LOG_MIN 0x42cff1b5
#define FLT_SMALLEST_EXP -22
#endif
#ifdef __STDC__
#undef __P
#define __P(p) p
#else
#define __P(p) ()
#endif
/*
* set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
* (one may replace the following line by "#include <values.h>")
*/
#define X_TLOSS 1.41484755040568800000e+16
/* Functions that are not documented, and are not in <math.h>. */
/* Undocumented float functions. */
#ifdef _SCALB_INT
extern float scalbf __P((float, int));
#else
extern float scalbf __P((float, float));
#endif
extern float significandf __P((float));
/* ieee style elementary float functions */
extern float __ieee754_sqrtf __P((float));
extern float __ieee754_acosf __P((float));
extern float __ieee754_acoshf __P((float));
extern float __ieee754_logf __P((float));
extern float __ieee754_atanhf __P((float));
extern float __ieee754_asinf __P((float));
extern float __ieee754_atan2f __P((float,float));
extern float __ieee754_expf __P((float));
extern float __ieee754_coshf __P((float));
extern float __ieee754_fmodf __P((float,float));
extern float __ieee754_powf __P((float,float));
extern float __ieee754_lgammaf_r __P((float,int *));
extern float __ieee754_gammaf_r __P((float,int *));
extern float __ieee754_log10f __P((float));
extern float __ieee754_sinhf __P((float));
extern float __ieee754_hypotf __P((float,float));
extern float __ieee754_j0f __P((float));
extern float __ieee754_j1f __P((float));
extern float __ieee754_y0f __P((float));
extern float __ieee754_y1f __P((float));
extern float __ieee754_jnf __P((int,float));
extern float __ieee754_ynf __P((int,float));
extern float __ieee754_remainderf __P((float,float));
extern __int32_t __ieee754_rem_pio2f __P((float,float*));
#ifdef _SCALB_INT
extern float __ieee754_scalbf __P((float,int));
#else
extern float __ieee754_scalbf __P((float,float));
#endif
/* float versions of fdlibm kernel functions */
extern float __kernel_sinf __P((float,float,int));
extern float __kernel_cosf __P((float,float));
extern float __kernel_tanf __P((float,float,int));
extern int __kernel_rem_pio2f __P((float*,float*,int,int,int,const __int32_t*));
/* A union which permits us to convert between a float and a 32 bit
int. */
typedef union
{
float value;
__uint32_t word;
} ieee_float_shape_type;
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(i,d) \
do { \
ieee_float_shape_type gf_u; \
gf_u.value = (d); \
(i) = gf_u.word; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,i) \
do { \
ieee_float_shape_type sf_u; \
sf_u.word = (i); \
(d) = sf_u.value; \
} while (0)
/* Macros to avoid undefined behaviour that can arise if the amount
of a shift is exactly equal to the size of the shifted operand. */
#define SAFE_LEFT_SHIFT(op,amt) \
(((amt) < 8 * sizeof(op)) ? ((op) << (amt)) : 0)
#define SAFE_RIGHT_SHIFT(op,amt) \
(((amt) < 8 * sizeof(op)) ? ((op) >> (amt)) : 0)

68
lib/libm/kf_cos.c Normal file
View File

@ -0,0 +1,68 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* kf_cos.c -- float version of k_cos.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
static const float
#else
static float
#endif
one = 1.0000000000e+00, /* 0x3f800000 */
C1 = 4.1666667908e-02, /* 0x3d2aaaab */
C2 = -1.3888889225e-03, /* 0xbab60b61 */
C3 = 2.4801587642e-05, /* 0x37d00d01 */
C4 = -2.7557314297e-07, /* 0xb493f27c */
C5 = 2.0875723372e-09, /* 0x310f74f6 */
C6 = -1.1359647598e-11; /* 0xad47d74e */
#ifdef __STDC__
float __kernel_cosf(float x, float y)
#else
float __kernel_cosf(x, y)
float x,y;
#endif
{
float a,hz,z,r,qx;
__int32_t ix;
GET_FLOAT_WORD(ix,x);
ix &= 0x7fffffff; /* ix = |x|'s high word*/
if(ix<0x32000000) { /* if x < 2**27 */
if(((int)x)==0) return one; /* generate inexact */
}
z = x*x;
r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
if(ix < 0x3e99999a) /* if |x| < 0.3 */
return one - ((float)0.5*z - (z*r - x*y));
else {
if(ix > 0x3f480000) { /* x > 0.78125 */
qx = (float)0.28125;
} else {
SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
}
hz = (float)0.5*z-qx;
a = one-qx;
return a - (hz - (z*r-x*y));
}
}

217
lib/libm/kf_rem_pio2.c Normal file
View File

@ -0,0 +1,217 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* kf_rem_pio2.c -- float version of k_rem_pio2.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
/* In the float version, the input parameter x contains 8 bit
integers, not 24 bit integers. 113 bit precision is not supported. */
#ifdef __STDC__
static const int init_jk[] = {4,7,9}; /* initial value for jk */
#else
static int init_jk[] = {4,7,9};
#endif
#ifdef __STDC__
static const float PIo2[] = {
#else
static float PIo2[] = {
#endif
1.5703125000e+00, /* 0x3fc90000 */
4.5776367188e-04, /* 0x39f00000 */
2.5987625122e-05, /* 0x37da0000 */
7.5437128544e-08, /* 0x33a20000 */
6.0026650317e-11, /* 0x2e840000 */
7.3896444519e-13, /* 0x2b500000 */
5.3845816694e-15, /* 0x27c20000 */
5.6378512969e-18, /* 0x22d00000 */
8.3009228831e-20, /* 0x1fc40000 */
3.2756352257e-22, /* 0x1bc60000 */
6.3331015649e-25, /* 0x17440000 */
};
#ifdef __STDC__
static const float
#else
static float
#endif
zero = 0.0,
one = 1.0,
two8 = 2.5600000000e+02, /* 0x43800000 */
twon8 = 3.9062500000e-03; /* 0x3b800000 */
#ifdef __STDC__
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2)
#else
int __kernel_rem_pio2f(x,y,e0,nx,prec,ipio2)
float x[], y[]; int e0,nx,prec; __int32_t ipio2[];
#endif
{
__int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
float z,fw,f[20],fq[20],q[20];
/* initialize jk*/
jk = init_jk[prec];
jp = jk;
/* determine jx,jv,q0, note that 3>q0 */
jx = nx-1;
jv = (e0-3)/8; if(jv<0) jv=0;
q0 = e0-8*(jv+1);
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
j = jv-jx; m = jx+jk;
for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
/* compute q[0],q[1],...q[jk] */
for (i=0;i<=jk;i++) {
for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
}
jz = jk;
recompute:
/* distill q[] into iq[] reversingly */
for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
fw = (float)((__int32_t)(twon8* z));
iq[i] = (__int32_t)(z-two8*fw);
z = q[j-1]+fw;
}
/* compute n */
z = scalbnf(z,(int)q0); /* actual value of z */
z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
n = (__int32_t) z;
z -= (float)n;
ih = 0;
if(q0>0) { /* need iq[jz-1] to determine n */
i = (iq[jz-1]>>(8-q0)); n += i;
iq[jz-1] -= i<<(8-q0);
ih = iq[jz-1]>>(7-q0);
}
else if(q0==0) ih = iq[jz-1]>>8;
else if(z>=(float)0.5) ih=2;
if(ih>0) { /* q > 0.5 */
n += 1; carry = 0;
for(i=0;i<jz ;i++) { /* compute 1-q */
j = iq[i];
if(carry==0) {
if(j!=0) {
carry = 1; iq[i] = 0x100- j;
}
} else iq[i] = 0xff - j;
}
if(q0>0) { /* rare case: chance is 1 in 12 */
switch(q0) {
case 1:
iq[jz-1] &= 0x7f; break;
case 2:
iq[jz-1] &= 0x3f; break;
}
}
if(ih==2) {
z = one - z;
if(carry!=0) z -= scalbnf(one,(int)q0);
}
}
/* check if recomputation is needed */
if(z==zero) {
j = 0;
for (i=jz-1;i>=jk;i--) j |= iq[i];
if(j==0) { /* need recomputation */
for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
f[jx+i] = (float) ipio2[jv+i];
for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
q[i] = fw;
}
jz += k;
goto recompute;
}
}
/* chop off zero terms */
if(z==(float)0.0) {
jz -= 1; q0 -= 8;
while(iq[jz]==0) { jz--; q0-=8;}
} else { /* break z into 8-bit if necessary */
z = scalbnf(z,-(int)q0);
if(z>=two8) {
fw = (float)((__int32_t)(twon8*z));
iq[jz] = (__int32_t)(z-two8*fw);
jz += 1; q0 += 8;
iq[jz] = (__int32_t) fw;
} else iq[jz] = (__int32_t) z ;
}
/* convert integer "bit" chunk to floating-point value */
fw = scalbnf(one,(int)q0);
for(i=jz;i>=0;i--) {
q[i] = fw*(float)iq[i]; fw*=twon8;
}
/* compute PIo2[0,...,jp]*q[jz,...,0] */
for(i=jz;i>=0;i--) {
for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
fq[jz-i] = fw;
}
/* compress fq[] into y[] */
switch(prec) {
case 0:
fw = 0.0;
for (i=jz;i>=0;i--) fw += fq[i];
y[0] = (ih==0)? fw: -fw;
break;
case 1:
case 2:
fw = 0.0;
for (i=jz;i>=0;i--) fw += fq[i];
y[0] = (ih==0)? fw: -fw;
fw = fq[0]-fw;
for (i=1;i<=jz;i++) fw += fq[i];
y[1] = (ih==0)? fw: -fw;
break;
case 3: /* painful */
for (i=jz;i>0;i--) {
fw = fq[i-1]+fq[i];
fq[i] += fq[i-1]-fw;
fq[i-1] = fw;
}
for (i=jz;i>1;i--) {
fw = fq[i-1]+fq[i];
fq[i] += fq[i-1]-fw;
fq[i-1] = fw;
}
for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
if(ih==0) {
y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
} else {
y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
}
}
return n&7;
}

58
lib/libm/kf_sin.c Normal file
View File

@ -0,0 +1,58 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* kf_sin.c -- float version of k_sin.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
static const float
#else
static float
#endif
half = 5.0000000000e-01,/* 0x3f000000 */
S1 = -1.6666667163e-01, /* 0xbe2aaaab */
S2 = 8.3333337680e-03, /* 0x3c088889 */
S3 = -1.9841270114e-04, /* 0xb9500d01 */
S4 = 2.7557314297e-06, /* 0x3638ef1b */
S5 = -2.5050759689e-08, /* 0xb2d72f34 */
S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
#ifdef __STDC__
float __kernel_sinf(float x, float y, int iy)
#else
float __kernel_sinf(x, y, iy)
float x,y; int iy; /* iy=0 if y is zero */
#endif
{
float z,r,v;
__int32_t ix;
GET_FLOAT_WORD(ix,x);
ix &= 0x7fffffff; /* high word of x */
if(ix<0x32000000) /* |x| < 2**-27 */
{if((int)x==0) return x;} /* generate inexact */
z = x*x;
v = z*x;
r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
if(iy==0) return x+v*(S1+z*r);
else return x-((z*(half*y-v*r)-y)-v*S1);
}

105
lib/libm/kf_tan.c Normal file
View File

@ -0,0 +1,105 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* kf_tan.c -- float version of k_tan.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "libm.h"
#ifdef __STDC__
static const float
#else
static float
#endif
one = 1.0000000000e+00, /* 0x3f800000 */
pio4 = 7.8539812565e-01, /* 0x3f490fda */
pio4lo= 3.7748947079e-08, /* 0x33222168 */
T[] = {
3.3333334327e-01, /* 0x3eaaaaab */
1.3333334029e-01, /* 0x3e088889 */
5.3968254477e-02, /* 0x3d5d0dd1 */
2.1869488060e-02, /* 0x3cb327a4 */
8.8632395491e-03, /* 0x3c11371f */
3.5920790397e-03, /* 0x3b6b6916 */
1.4562094584e-03, /* 0x3abede48 */
5.8804126456e-04, /* 0x3a1a26c8 */
2.4646313977e-04, /* 0x398137b9 */
7.8179444245e-05, /* 0x38a3f445 */
7.1407252108e-05, /* 0x3895c07a */
-1.8558637748e-05, /* 0xb79bae5f */
2.5907305826e-05, /* 0x37d95384 */
};
#ifdef __STDC__
float __kernel_tanf(float x, float y, int iy)
#else
float __kernel_tanf(x, y, iy)
float x,y; int iy;
#endif
{
float z,r,v,w,s;
__int32_t ix,hx;
GET_FLOAT_WORD(hx,x);
ix = hx&0x7fffffff; /* high word of |x| */
if(ix<0x31800000) /* x < 2**-28 */
{if((int)x==0) { /* generate inexact */
if((ix|(iy+1))==0) return one/fabsf(x);
else return (iy==1)? x: -one/x;
}
}
if(ix>=0x3f2ca140) { /* |x|>=0.6744 */
if(hx<0) {x = -x; y = -y;}
z = pio4-x;
w = pio4lo-y;
x = z+w; y = 0.0;
}
z = x*x;
w = z*z;
/* Break x^5*(T[1]+x^2*T[2]+...) into
* x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
* x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
*/
r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
s = z*x;
r = y + z*(s*(r+v)+y);
r += T[0]*s;
w = x+r;
if(ix>=0x3f2ca140) {
v = (float)iy;
return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r)));
}
if(iy==1) return w;
else { /* if allow error up to 2 ulp,
simply return -1.0/(x+r) here */
/* compute -1.0/(x+r) accurately */
float a,t;
__int32_t i;
z = w;
GET_FLOAT_WORD(i,z);
SET_FLOAT_WORD(z,i&0xfffff000);
v = r-(z - x); /* z+v = r+x */
t = a = -(float)1.0/w; /* a = -1.0/w */
GET_FLOAT_WORD(i,t);
SET_FLOAT_WORD(t,i&0xfffff000);
s = (float)1.0+t*z;
return t+a*(s+t*v);
}
}

View File

@ -19,6 +19,8 @@
#include <stdint.h> #include <stdint.h>
#include <math.h> #include <math.h>
#define FLT_EVAL_METHOD 0
#define FORCE_EVAL(x) do { \ #define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \ if (sizeof(x) == sizeof(float)) { \
volatile float __x; \ volatile float __x; \

83
lib/libm/log1pf.c Normal file
View File

@ -0,0 +1,83 @@
/*****************************************************************************/
/*****************************************************************************/
// log1pf from musl-0.9.15
/*****************************************************************************/
/*****************************************************************************/
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "libm.h"
static const float
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
float log1pf(float x)
{
union {float f; uint32_t i;} u = {x};
float_t hfsq,f,c,s,z,R,w,t1,t2,dk;
uint32_t ix,iu;
int k;
ix = u.i;
k = 1;
if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */
if (ix >= 0xbf800000) { /* x <= -1.0 */
if (x == -1)
return x/0.0f; /* log1p(-1)=+inf */
return (x-x)/0.0f; /* log1p(x<-1)=NaN */
}
if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */
/* underflow if subnormal */
if ((ix&0x7f800000) == 0)
FORCE_EVAL(x*x);
return x;
}
if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
k = 0;
c = 0;
f = x;
}
} else if (ix >= 0x7f800000)
return x;
if (k) {
u.f = 1 + x;
iu = u.i;
iu += 0x3f800000 - 0x3f3504f3;
k = (int)(iu>>23) - 0x7f;
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
if (k < 25) {
c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
c /= u.f;
} else
c = 0;
/* reduce u into [sqrt(2)/2, sqrt(2)] */
iu = (iu&0x007fffff) + 0x3f3504f3;
u.i = iu;
f = u.f - 1;
}
s = f/(2.0f + f);
z = s*s;
w = z*z;
t1= w*(Lg2+w*Lg4);
t2= z*(Lg1+w*Lg3);
R = t2 + t1;
hfsq = 0.5f*f*f;
dk = k;
return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
}

View File

@ -113,10 +113,6 @@ float log10f(float x) { return logf(x) / (float)_M_LN10; }
float tanhf(float x) { return sinhf(x) / coshf(x); } float tanhf(float x) { return sinhf(x) / coshf(x); }
// TODO we need import these functions from some library (eg musl or newlib) // TODO we need import these functions from some library (eg musl or newlib)
float acoshf(float x) { return 0.0; }
float asinhf(float x) { return 0.0; }
float atanhf(float x) { return 0.0; }
float tanf(float x) { return 0.0; }
float tgammaf(float x) { return 0.0; } float tgammaf(float x) { return 0.0; }
float lgammaf(float x) { return 0.0; } float lgammaf(float x) { return 0.0; }
float erff(float x) { return 0.0; } float erff(float x) { return 0.0; }

View File

@ -1,627 +0,0 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib 2.1.0, the newlib/libm directory.
* Appropriate copyright headers are reproduced below.
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <math.h>
/* @(#)fdlibm.h 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
/* A union which permits us to convert between a float and a 32 bit
int. */
typedef union
{
float value;
__uint32_t word;
} ieee_float_shape_type;
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(i,d) \
do { \
ieee_float_shape_type gf_u; \
gf_u.value = (d); \
(i) = gf_u.word; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,i) \
do { \
ieee_float_shape_type sf_u; \
sf_u.word = (i); \
(d) = sf_u.value; \
} while (0)
/* kf_rem_pio2.c -- float version of k_rem_pio2.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* In the float version, the input parameter x contains 8 bit
integers, not 24 bit integers. 113 bit precision is not supported. */
#ifdef __STDC__
static const int init_jk[] = {4,7,9}; /* initial value for jk */
#else
static int init_jk[] = {4,7,9};
#endif
#ifdef __STDC__
static const float PIo2[] = {
#else
static float PIo2[] = {
#endif
1.5703125000e+00, /* 0x3fc90000 */
4.5776367188e-04, /* 0x39f00000 */
2.5987625122e-05, /* 0x37da0000 */
7.5437128544e-08, /* 0x33a20000 */
6.0026650317e-11, /* 0x2e840000 */
7.3896444519e-13, /* 0x2b500000 */
5.3845816694e-15, /* 0x27c20000 */
5.6378512969e-18, /* 0x22d00000 */
8.3009228831e-20, /* 0x1fc40000 */
3.2756352257e-22, /* 0x1bc60000 */
6.3331015649e-25, /* 0x17440000 */
};
static const float
zero = 0.0000000000e+00, /* 0x00000000 */
one = 1.0000000000e+00, /* 0x3f800000 */
two8 = 2.5600000000e+02, /* 0x43800000 */
twon8 = 3.9062500000e-03; /* 0x3b800000 */
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2)
{
__int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
float z,fw,f[20],fq[20],q[20];
/* initialize jk*/
jk = init_jk[prec];
jp = jk;
/* determine jx,jv,q0, note that 3>q0 */
jx = nx-1;
jv = (e0-3)/8; if(jv<0) jv=0;
q0 = e0-8*(jv+1);
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
j = jv-jx; m = jx+jk;
for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
/* compute q[0],q[1],...q[jk] */
for (i=0;i<=jk;i++) {
for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
}
jz = jk;
recompute:
/* distill q[] into iq[] reversingly */
for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
fw = (float)((__int32_t)(twon8* z));
iq[i] = (__int32_t)(z-two8*fw);
z = q[j-1]+fw;
}
/* compute n */
z = scalbnf(z,(int)q0); /* actual value of z */
z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
n = (__int32_t) z;
z -= (float)n;
ih = 0;
if(q0>0) { /* need iq[jz-1] to determine n */
i = (iq[jz-1]>>(8-q0)); n += i;
iq[jz-1] -= i<<(8-q0);
ih = iq[jz-1]>>(7-q0);
}
else if(q0==0) ih = iq[jz-1]>>8;
else if(z>=(float)0.5) ih=2;
if(ih>0) { /* q > 0.5 */
n += 1; carry = 0;
for(i=0;i<jz ;i++) { /* compute 1-q */
j = iq[i];
if(carry==0) {
if(j!=0) {
carry = 1; iq[i] = 0x100- j;
}
} else iq[i] = 0xff - j;
}
if(q0>0) { /* rare case: chance is 1 in 12 */
switch(q0) {
case 1:
iq[jz-1] &= 0x7f; break;
case 2:
iq[jz-1] &= 0x3f; break;
}
}
if(ih==2) {
z = one - z;
if(carry!=0) z -= scalbnf(one,(int)q0);
}
}
/* check if recomputation is needed */
if(z==zero) {
j = 0;
for (i=jz-1;i>=jk;i--) j |= iq[i];
if(j==0) { /* need recomputation */
for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
f[jx+i] = (float) ipio2[jv+i];
for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
q[i] = fw;
}
jz += k;
goto recompute;
}
}
/* chop off zero terms */
if(z==(float)0.0) {
jz -= 1; q0 -= 8;
while(iq[jz]==0) { jz--; q0-=8;}
} else { /* break z into 8-bit if necessary */
z = scalbnf(z,-(int)q0);
if(z>=two8) {
fw = (float)((__int32_t)(twon8*z));
iq[jz] = (__int32_t)(z-two8*fw);
jz += 1; q0 += 8;
iq[jz] = (__int32_t) fw;
} else iq[jz] = (__int32_t) z ;
}
/* convert integer "bit" chunk to floating-point value */
fw = scalbnf(one,(int)q0);
for(i=jz;i>=0;i--) {
q[i] = fw*(float)iq[i]; fw*=twon8;
}
/* compute PIo2[0,...,jp]*q[jz,...,0] */
for(i=jz;i>=0;i--) {
for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
fq[jz-i] = fw;
}
/* compress fq[] into y[] */
switch(prec) {
case 0:
fw = 0.0;
for (i=jz;i>=0;i--) fw += fq[i];
y[0] = (ih==0)? fw: -fw;
break;
case 1:
case 2:
fw = 0.0;
for (i=jz;i>=0;i--) fw += fq[i];
y[0] = (ih==0)? fw: -fw;
fw = fq[0]-fw;
for (i=1;i<=jz;i++) fw += fq[i];
y[1] = (ih==0)? fw: -fw;
break;
case 3: /* painful */
for (i=jz;i>0;i--) {
fw = fq[i-1]+fq[i];
fq[i] += fq[i-1]-fw;
fq[i-1] = fw;
}
for (i=jz;i>1;i--) {
fw = fq[i-1]+fq[i];
fq[i] += fq[i-1]-fw;
fq[i-1] = fw;
}
for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
if(ih==0) {
y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
} else {
y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
}
}
return n&7;
}
/* ef_rem_pio2.c -- float version of e_rem_pio2.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*
*/
/* __ieee754_rem_pio2f(x,y)
*
* return the remainder of x rem pi/2 in y[0]+y[1]
* use __kernel_rem_pio2f()
*/
/*
* Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
*/
static const __int32_t two_over_pi[] = {
0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62,
0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A,
0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29,
0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41,
0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8,
0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF,
0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5,
0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08,
0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3,
0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80,
0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B,
};
/* This array is like the one in e_rem_pio2.c, but the numbers are
single precision and the last 8 bits are forced to 0. */
static const __int32_t npio2_hw[] = {
0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
0x4242c700, 0x42490f00
};
/*
* invpio2: 24 bits of 2/pi
* pio2_1: first 17 bit of pi/2
* pio2_1t: pi/2 - pio2_1
* pio2_2: second 17 bit of pi/2
* pio2_2t: pi/2 - (pio2_1+pio2_2)
* pio2_3: third 17 bit of pi/2
* pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
*/
static const float
half = 5.0000000000e-01, /* 0x3f000000 */
invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
pio2_1t = 1.0804334124e-05, /* 0x37354443 */
pio2_2 = 1.0804273188e-05, /* 0x37354400 */
pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
__int32_t __ieee754_rem_pio2f(float x, float *y)
{
float z,w,t,r,fn;
float tx[3];
__int32_t i,j,n,ix,hx;
int e0,nx;
GET_FLOAT_WORD(hx,x);
ix = hx&0x7fffffff;
if(ix<=0x3f490fd8) /* |x| ~<= pi/4 , no need for reduction */
{y[0] = x; y[1] = 0; return 0;}
if(ix<0x4016cbe4) { /* |x| < 3pi/4, special case with n=+-1 */
if(hx>0) {
z = x - pio2_1;
if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
y[0] = z - pio2_1t;
y[1] = (z-y[0])-pio2_1t;
} else { /* near pi/2, use 24+24+24 bit pi */
z -= pio2_2;
y[0] = z - pio2_2t;
y[1] = (z-y[0])-pio2_2t;
}
return 1;
} else { /* negative x */
z = x + pio2_1;
if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
y[0] = z + pio2_1t;
y[1] = (z-y[0])+pio2_1t;
} else { /* near pi/2, use 24+24+24 bit pi */
z += pio2_2;
y[0] = z + pio2_2t;
y[1] = (z-y[0])+pio2_2t;
}
return -1;
}
}
if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
t = fabsf(x);
n = (__int32_t) (t*invpio2+half);
fn = (float)n;
r = t-fn*pio2_1;
w = fn*pio2_1t; /* 1st round good to 40 bit */
if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {
y[0] = r-w; /* quick check no cancellation */
} else {
__uint32_t high;
j = ix>>23;
y[0] = r-w;
GET_FLOAT_WORD(high,y[0]);
i = j-((high>>23)&0xff);
if(i>8) { /* 2nd iteration needed, good to 57 */
t = r;
w = fn*pio2_2;
r = t-w;
w = fn*pio2_2t-((t-r)-w);
y[0] = r-w;
GET_FLOAT_WORD(high,y[0]);
i = j-((high>>23)&0xff);
if(i>25) { /* 3rd iteration need, 74 bits acc */
t = r; /* will cover all possible cases */
w = fn*pio2_3;
r = t-w;
w = fn*pio2_3t-((t-r)-w);
y[0] = r-w;
}
}
}
y[1] = (r-y[0])-w;
if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
else return n;
}
/*
* all other (large) arguments
*/
if(!FLT_UWORD_IS_FINITE(ix)) {
y[0]=y[1]=x-x; return 0;
}
/* set z = scalbn(|x|,ilogb(x)-7) */
e0 = (int)((ix>>23)-134); /* e0 = ilogb(z)-7; */
SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
for(i=0;i<2;i++) {
tx[i] = (float)((__int32_t)(z));
z = (z-tx[i])*two8;
}
tx[2] = z;
nx = 3;
while(tx[nx-1]==zero) nx--; /* skip zero term */
n = __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
return n;
}
/* kf_sin.c -- float version of k_sin.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
static const float
S1 = -1.6666667163e-01, /* 0xbe2aaaab */
S2 = 8.3333337680e-03, /* 0x3c088889 */
S3 = -1.9841270114e-04, /* 0xb9500d01 */
S4 = 2.7557314297e-06, /* 0x3638ef1b */
S5 = -2.5050759689e-08, /* 0xb2d72f34 */
S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
float __kernel_sinf(float x, float y, int iy) /* iy=0 if y is zero */
{
float z,r,v;
__int32_t ix;
GET_FLOAT_WORD(ix,x);
ix &= 0x7fffffff; /* high word of x */
if(ix<0x32000000) /* |x| < 2**-27 */
{if((int)x==0) return x;} /* generate inexact */
z = x*x;
v = z*x;
r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
if(iy==0) return x+v*(S1+z*r);
else return x-((z*(half*y-v*r)-y)-v*S1);
}
/* kf_cos.c -- float version of k_cos.c
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
static const float
C1 = 4.1666667908e-02, /* 0x3d2aaaab */
C2 = -1.3888889225e-03, /* 0xbab60b61 */
C3 = 2.4801587642e-05, /* 0x37d00d01 */
C4 = -2.7557314297e-07, /* 0xb493f27c */
C5 = 2.0875723372e-09, /* 0x310f74f6 */
C6 = -1.1359647598e-11; /* 0xad47d74e */
float __kernel_cosf(float x, float y)
{
float a,hz,z,r,qx;
__int32_t ix;
GET_FLOAT_WORD(ix,x);
ix &= 0x7fffffff; /* ix = |x|'s high word*/
if(ix<0x32000000) { /* if x < 2**27 */
if(((int)x)==0) return one; /* generate inexact */
}
z = x*x;
r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
if(ix < 0x3e99999a) /* if |x| < 0.3 */
return one - ((float)0.5*z - (z*r - x*y));
else {
if(ix > 0x3f480000) { /* x > 0.78125 */
qx = (float)0.28125;
} else {
SET_FLOAT_WORD(qx,ix-0x01000000); /* x/4 */
}
hz = (float)0.5*z-qx;
a = one-qx;
return a - (hz - (z*r-x*y));
}
}
/* sf_sin.c -- float version of s_sin.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
float sinf(float x)
{
float y[2],z=0.0;
__int32_t n,ix;
GET_FLOAT_WORD(ix,x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
/* sin(Inf or NaN) is NaN */
else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2f(x,y);
switch(n&3) {
case 0: return __kernel_sinf(y[0],y[1],1);
case 1: return __kernel_cosf(y[0],y[1]);
case 2: return -__kernel_sinf(y[0],y[1],1);
default:
return -__kernel_cosf(y[0],y[1]);
}
}
}
/* sf_cos.c -- float version of s_cos.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
float cosf(float x)
{
float y[2],z=0.0;
__int32_t n,ix;
GET_FLOAT_WORD(ix,x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
/* cos(Inf or NaN) is NaN */
else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2f(x,y);
switch(n&3) {
case 0: return __kernel_cosf(y[0],y[1]);
case 1: return -__kernel_sinf(y[0],y[1],1);
case 2: return -__kernel_cosf(y[0],y[1]);
default:
return __kernel_sinf(y[0],y[1],1);
}
}
}

77
lib/libm/sf_cos.c Normal file
View File

@ -0,0 +1,77 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* sf_cos.c -- float version of s_cos.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
static const float one=1.0;
#else
static float one=1.0;
#endif
#ifdef __STDC__
float cosf(float x)
#else
float cosf(x)
float x;
#endif
{
float y[2],z=0.0;
__int32_t n,ix;
GET_FLOAT_WORD(ix,x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
/* cos(Inf or NaN) is NaN */
else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2f(x,y);
switch(n&3) {
case 0: return __kernel_cosf(y[0],y[1]);
case 1: return -__kernel_sinf(y[0],y[1],1);
case 2: return -__kernel_cosf(y[0],y[1]);
default:
return __kernel_sinf(y[0],y[1],1);
}
}
}
#ifdef _DOUBLE_IS_32BITS
#ifdef __STDC__
double cos(double x)
#else
double cos(x)
double x;
#endif
{
return (double) cosf((float) x);
}
#endif /* defined(_DOUBLE_IS_32BITS) */

71
lib/libm/sf_sin.c Normal file
View File

@ -0,0 +1,71 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* sf_sin.c -- float version of s_sin.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
float sinf(float x)
#else
float sinf(x)
float x;
#endif
{
float y[2],z=0.0;
__int32_t n,ix;
GET_FLOAT_WORD(ix,x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
/* sin(Inf or NaN) is NaN */
else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2f(x,y);
switch(n&3) {
case 0: return __kernel_sinf(y[0],y[1],1);
case 1: return __kernel_cosf(y[0],y[1]);
case 2: return -__kernel_sinf(y[0],y[1],1);
default:
return -__kernel_cosf(y[0],y[1]);
}
}
}
#ifdef _DOUBLE_IS_32BITS
#ifdef __STDC__
double sin(double x)
#else
double sin(x)
double x;
#endif
{
return (double) sinf((float) x);
}
#endif /* defined(_DOUBLE_IS_32BITS) */

66
lib/libm/sf_tan.c Normal file
View File

@ -0,0 +1,66 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* sf_tan.c -- float version of s_tan.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
float tanf(float x)
#else
float tanf(x)
float x;
#endif
{
float y[2],z=0.0;
__int32_t n,ix;
GET_FLOAT_WORD(ix,x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1);
/* tan(Inf or NaN) is NaN */
else if (!FLT_UWORD_IS_FINITE(ix)) return x-x; /* NaN */
/* argument reduction needed */
else {
n = __ieee754_rem_pio2f(x,y);
return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
-1 -- n odd */
}
}
#ifdef _DOUBLE_IS_32BITS
#ifdef __STDC__
double tan(double x)
#else
double tan(x)
double x;
#endif
{
return (double) tanf((float) x);
}
#endif /* defined(_DOUBLE_IS_32BITS) */

View File

@ -63,12 +63,23 @@ endif
SRC_LIB = $(addprefix lib/,\ SRC_LIB = $(addprefix lib/,\
libm/math.c \ libm/math.c \
libm/mathsincos.c \
libm/asinfacosf.c \ libm/asinfacosf.c \
libm/atanf.c \ libm/atanf.c \
libm/atan2f.c \ libm/atan2f.c \
libm/fmodf.c \ libm/fmodf.c \
libm/roundf.c \ libm/roundf.c \
libm/log1pf.c \
libm/acoshf.c \
libm/asinhf.c \
libm/atanhf.c \
libm/kf_rem_pio2.c \
libm/kf_sin.c \
libm/kf_cos.c \
libm/kf_tan.c \
libm/ef_rem_pio2.c \
libm/sf_sin.c \
libm/sf_cos.c \
libm/sf_tan.c \
) )
SRC_C = \ SRC_C = \

View File

@ -8,18 +8,19 @@ except ImportError:
sys.exit() sys.exit()
test_values = [-100., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 100.] test_values = [-100., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 100.]
test_values_small = [-10., -1.23456, -1, -0.5, 0.0, 0.5, 1.23456, 10.] # so we don't overflow 32-bit precision
p_test_values = [0.1, 0.5, 1.23456] p_test_values = [0.1, 0.5, 1.23456]
unit_range_test_values = [-1., -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 1.] unit_range_test_values = [-1., -0.75, -0.5, -0.25, 0., 0.25, 0.5, 0.75, 1.]
functions = [('sqrt', sqrt, p_test_values), functions = [('sqrt', sqrt, p_test_values),
('exp', exp, test_values), ('exp', exp, test_values_small),
('expm1', expm1, test_values), ('expm1', expm1, test_values_small),
('log', log, p_test_values), ('log', log, p_test_values),
('log2', log2, p_test_values), ('log2', log2, p_test_values),
('log10', log10, p_test_values), ('log10', log10, p_test_values),
('cosh', cosh, test_values), ('cosh', cosh, test_values_small),
('sinh', sinh, test_values), ('sinh', sinh, test_values_small),
('tanh', tanh, test_values), ('tanh', tanh, test_values_small),
('acosh', acosh, [1.0, 5.0, 1.0]), ('acosh', acosh, [1.0, 5.0, 1.0]),
('asinh', asinh, test_values), ('asinh', asinh, test_values),
('atanh', atanh, [-0.99, -0.5, 0.0, 0.5, 0.99]), ('atanh', atanh, [-0.99, -0.5, 0.0, 0.5, 0.99]),
@ -39,7 +40,7 @@ functions = [('sqrt', sqrt, p_test_values),
for function_name, function, test_vals in functions: for function_name, function, test_vals in functions:
print(function_name) print(function_name)
for value in test_vals: for value in test_vals:
print("{:.7g}".format(function(value))) print("{:.5g}".format(function(value)))
binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.), binary_functions = [('copysign', copysign, [(23., 42.), (-23., 42.), (23., -42.),
(-23., -42.), (1., 0.0), (1., -0.0)]) (-23., -42.), (1., 0.0), (1., -0.0)])