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!).
crypto-aes
Damien George 8 years ago
parent 6936f4626c
commit f04329e93b
  1. 32
      lib/libm/acoshf.c
  2. 34
      lib/libm/asinhf.c
  3. 34
      lib/libm/atanhf.c
  4. 202
      lib/libm/ef_rem_pio2.c
  5. 227
      lib/libm/fdlibm.h
  6. 68
      lib/libm/kf_cos.c
  7. 217
      lib/libm/kf_rem_pio2.c
  8. 58
      lib/libm/kf_sin.c
  9. 105
      lib/libm/kf_tan.c
  10. 2
      lib/libm/libm.h
  11. 83
      lib/libm/log1pf.c
  12. 4
      lib/libm/math.c
  13. 627
      lib/libm/mathsincos.c
  14. 77
      lib/libm/sf_cos.c
  15. 71
      lib/libm/sf_sin.c
  16. 66
      lib/libm/sf_tan.c
  17. 13
      stmhal/Makefile
  18. 13
      tests/float/math_fun.py

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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)

@ -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));
}
}

@ -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;
}

@ -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);
}

@ -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);
}
}

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

@ -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;
}

@ -113,10 +113,6 @@ float log10f(float x) { return logf(x) / (float)_M_LN10; }
float tanhf(float x) { return sinhf(x) / coshf(x); }
// 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 lgammaf(float x) { return 0.0; }
float erff(float x) { return 0.0; }

@ -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