Clean up code

Clean up code
This commit is contained in:
Theo Arends 2019-07-02 17:59:40 +02:00
parent 3d67b8dc66
commit 61807b8afa

View File

@ -1,7 +1,7 @@
/* /*
support_float.ino - support for Sonoff-Tasmota support_float.ino - Small floating point support for Sonoff-Tasmota
Copyright (C) 2019 Theo Arends Copyright (C) 2019 Theo Arends and Stephan Hadinger
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -20,11 +20,11 @@
#ifdef ARDUINO_ESP8266_RELEASE_2_3_0 #ifdef ARDUINO_ESP8266_RELEASE_2_3_0
// Functions not available in 2.3.0 // Functions not available in 2.3.0
static const float Zero[] = { 0.0, -0.0 };
// https://code.woboq.org/userspace/glibc/sysdeps/ieee754/flt-32/e_fmodf.c.html // https://code.woboq.org/userspace/glibc/sysdeps/ieee754/flt-32/e_fmodf.c.html
float fmodf(float x, float y) float fmodf(float x, float y)
{ {
const float Zero[] = { 0.0, -0.0 };
int32_t hx = (int32_t)x; int32_t hx = (int32_t)x;
int32_t hy = (int32_t)y; int32_t hy = (int32_t)y;
@ -165,9 +165,8 @@ double TaylorLog(double x)
return totalValue; return totalValue;
} }
// All code adapted from: http://www.ganssle.com/approx.htm // Following code adapted from: http://www.ganssle.com/approx.htm
// ==============================================================
/// ========================================
// The following code implements approximations to various trig functions. // The following code implements approximations to various trig functions.
// //
// This is demo code to guide developers in implementing their own approximation // This is demo code to guide developers in implementing their own approximation
@ -183,24 +182,23 @@ inline float sqrtf(float x) { return sqrt1(x); }
inline float powf(float x, float y) { return FastPrecisePow(x, y); } inline float powf(float x, float y) { return FastPrecisePow(x, y); }
// Math constants we'll use // Math constants we'll use
double const f_pi=3.1415926535897932384626433; // f_pi double const f_pi = 3.1415926535897932384626433; // f_pi
double const f_twopi=2.0*f_pi; // f_pi times 2 double const f_twopi = 2.0 * f_pi; // f_pi times 2
double const f_two_over_pi= 2.0/f_pi; // 2/f_pi double const f_two_over_pi = 2.0 / f_pi; // 2/f_pi
double const f_halfpi=f_pi/2.0; // f_pi divided by 2 double const f_halfpi = f_pi / 2.0; // f_pi divided by 2
double const f_threehalfpi=3.0*f_pi/2.0; // f_pi times 3/2, used in tan routines double const f_threehalfpi = 3.0 * f_pi / 2.0; // f_pi times 3/2, used in tan routines
double const f_four_over_pi=4.0/f_pi; // 4/f_pi, used in tan routines double const f_four_over_pi = 4.0 / f_pi; // 4/f_pi, used in tan routines
double const f_qtrpi=f_pi/4.0; // f_pi/4.0, used in tan routines double const f_qtrpi = f_pi / 4.0; // f_pi/4.0, used in tan routines
double const f_sixthpi=f_pi/6.0; // f_pi/6.0, used in atan routines double const f_sixthpi = f_pi / 6.0; // f_pi/6.0, used in atan routines
double const f_tansixthpi=tan(f_sixthpi); // tan(f_pi/6), used in atan routines double const f_tansixthpi = tan(f_sixthpi); // tan(f_pi/6), used in atan routines
double const f_twelfthpi=f_pi/12.0; // f_pi/12.0, used in atan routines double const f_twelfthpi = f_pi / 12.0; // f_pi/12.0, used in atan routines
double const f_tantwelfthpi=tan(f_twelfthpi); // tan(f_pi/12), used in atan routines double const f_tantwelfthpi = tan(f_twelfthpi); // tan(f_pi/12), used in atan routines
// ********************************************************* // *******************************************************************
// *** // ***
// *** Routines to compute sine and cosine to 5.2 digits // *** Routines to compute sine and cosine to 5.2 digits of accuracy.
// *** of accuracy.
// *** // ***
// ********************************************************* // *******************************************************************
// //
// cos_52s computes cosine (x) // cos_52s computes cosine (x)
// //
@ -215,50 +213,46 @@ double const f_tantwelfthpi=tan(f_twelfthpi); // tan(f_pi/12), used in atan rout
// //
float cos_52s(float x) float cos_52s(float x)
{ {
const float c1= 0.9999932946; const float c1 = 0.9999932946;
const float c2=-0.4999124376; const float c2 = -0.4999124376;
const float c3= 0.0414877472; const float c3 = 0.0414877472;
const float c4=-0.0012712095; const float c4 = -0.0012712095;
float x2; // The input argument squared float x2 = x * x; // The input argument squared
return (c1 + x2 * (c2 + x2 * (c3 + c4 * x2)));
x2=x * x;
return (c1 + x2*(c2 + x2*(c3 + c4*x2)));
} }
// //
// This is the main cosine approximation "driver" // This is the main cosine approximation "driver"
// It reduces the input argument's range to [0, f_pi/2], // It reduces the input argument's range to [0, f_pi/2],
// and then calls the approximator. // and then calls the approximator.
// See the notes for an explanation of the range reduction. // See the notes for an explanation of the range reduction.
// //
float cos_52(float x){ float cos_52(float x)
int quad; // what quadrant are we in? {
x = fmodf(x, f_twopi); // Get rid of values > 2* f_pi
x=fmodf(x, f_twopi); // Get rid of values > 2* f_pi if (x < 0) { x = -x; } // cos(-x) = cos(x)
if(x<0)x=-x; // cos(-x) = cos(x) int quad = int(x * (float)f_two_over_pi); // Get quadrant # (0 to 3) we're in
quad=int(x * (float)f_two_over_pi); // Get quadrant # (0 to 3) we're in switch (quad) {
switch (quad){
case 0: return cos_52s(x); case 0: return cos_52s(x);
case 1: return -cos_52s((float)f_pi-x); case 1: return -cos_52s((float)f_pi - x);
case 2: return -cos_52s(x-(float)f_pi); case 2: return -cos_52s(x-(float)f_pi);
case 3: return cos_52s((float)f_twopi-x); case 3: return cos_52s((float)f_twopi - x);
} }
} }
// //
// The sine is just cosine shifted a half-f_pi, so // The sine is just cosine shifted a half-f_pi, so
// we'll adjust the argument and call the cosine approximation. // we'll adjust the argument and call the cosine approximation.
// //
float sin_52(float x){ float sin_52(float x)
return cos_52((float)f_halfpi-x); {
return cos_52((float)f_halfpi - x);
} }
// ********************************************************* // *******************************************************************
// *** // ***
// *** Routines to compute tangent to 5.6 digits // *** Routines to compute tangent to 5.6 digits of accuracy.
// *** of accuracy.
// *** // ***
// ********************************************************* // *******************************************************************
// //
// tan_56s computes tan(f_pi*x/4) // tan_56s computes tan(f_pi*x/4)
// //
@ -272,16 +266,13 @@ float sin_52(float x){
// //
float tan_56s(float x) float tan_56s(float x)
{ {
const float c1=-3.16783027; const float c1 = -3.16783027;
const float c2= 0.134516124; const float c2 = 0.134516124;
const float c3=-4.033321984; const float c3 = -4.033321984;
float x2; // The input argument squared float x2 = x * x; // The input argument squared
return (x * (c1 + c2 * x2) / (c3 + x2));
x2=x * x;
return (x*(c1 + c2 * x2)/(c3 + x2));
} }
// //
// This is the main tangent approximation "driver" // This is the main tangent approximation "driver"
// It reduces the input argument's range to [0, f_pi/4], // It reduces the input argument's range to [0, f_pi/4],
@ -293,29 +284,27 @@ return (x*(c1 + c2 * x2)/(c3 + x2));
// which it will at x=f_pi/2 and x=3*f_pi/2. If this is a problem // which it will at x=f_pi/2 and x=3*f_pi/2. If this is a problem
// in your application, take appropriate action. // in your application, take appropriate action.
// //
float tan_56(float x){ float tan_56(float x)
int octant; // what octant are we in? {
x = fmodf(x, (float)f_twopi); // Get rid of values >2 *f_pi
x=fmodf(x, (float)f_twopi); // Get rid of values >2 *f_pi int octant = int(x * (float)f_four_over_pi); // Get octant # (0 to 7)
octant=int(x * (float)f_four_over_pi); // Get octant # (0 to 7)
switch (octant){ switch (octant){
case 0: return tan_56s(x *(float)f_four_over_pi); case 0: return tan_56s(x * (float)f_four_over_pi);
case 1: return 1.0f/tan_56s(((float)f_halfpi-x) *(float)f_four_over_pi); case 1: return 1.0f / tan_56s(((float)f_halfpi - x) * (float)f_four_over_pi);
case 2: return -1.0f/tan_56s((x-(float)f_halfpi) *(float)f_four_over_pi); case 2: return -1.0f / tan_56s((x-(float)f_halfpi) * (float)f_four_over_pi);
case 3: return - tan_56s(((float)f_pi-x) *(float)f_four_over_pi); case 3: return - tan_56s(((float)f_pi - x) * (float)f_four_over_pi);
case 4: return tan_56s((x-(float)f_pi) *(float)f_four_over_pi); case 4: return tan_56s((x-(float)f_pi) * (float)f_four_over_pi);
case 5: return 1.0f/tan_56s(((float)f_threehalfpi-x)*(float)f_four_over_pi); case 5: return 1.0f / tan_56s(((float)f_threehalfpi - x) * (float)f_four_over_pi);
case 6: return -1.0f/tan_56s((x-(float)f_threehalfpi)*(float)f_four_over_pi); case 6: return -1.0f / tan_56s((x-(float)f_threehalfpi) * (float)f_four_over_pi);
case 7: return - tan_56s(((float)f_twopi-x) *(float)f_four_over_pi); case 7: return - tan_56s(((float)f_twopi - x) * (float)f_four_over_pi);
} }
} }
// ********************************************************* // *******************************************************************
// *** // ***
// *** Routines to compute arctangent to 6.6 digits // *** Routines to compute arctangent to 6.6 digits of accuracy.
// *** of accuracy.
// *** // ***
// ********************************************************* // *******************************************************************
// //
// atan_66s computes atan(x) // atan_66s computes atan(x)
// //
@ -326,57 +315,56 @@ float tan_56(float x){
// //
float atan_66s(float x) float atan_66s(float x)
{ {
const float c1=1.6867629106; const float c1 = 1.6867629106;
const float c2=0.4378497304; const float c2 = 0.4378497304;
const float c3=1.6867633134; const float c3 = 1.6867633134;
float x2; // The input argument squared float x2 = x * x; // The input argument squared
return (x * (c1 + x2 * c2) / (c3 + x2));
x2=x * x;
return (x*(c1 + x2*c2)/(c3 + x2));
} }
// //
// This is the main arctangent approximation "driver" // This is the main arctangent approximation "driver"
// It reduces the input argument's range to [0, f_pi/12], // It reduces the input argument's range to [0, f_pi/12],
// and then calls the approximator. // and then calls the approximator.
// //
// float atan_66(float x)
float atan_66(float x){ {
float y; // return from atan__s function float y; // return from atan__s function
bool complement= false; // true if arg was >1 bool complement= false; // true if arg was >1
bool region= false; // true depending on region arg is in bool region= false; // true depending on region arg is in
bool sign= false; // true if arg was < 0 bool sign= false; // true if arg was < 0
if (x <0 ){ if (x < 0) {
x=-x; x = -x;
sign=true; // arctan(-x)=-arctan(x) sign = true; // arctan(-x)=-arctan(x)
} }
if (x > 1.0){ if (x > 1.0) {
x=1.0/x; // keep arg between 0 and 1 x = 1.0 / x; // keep arg between 0 and 1
complement=true; complement = true;
} }
if (x > (float)f_tantwelfthpi){ if (x > (float)f_tantwelfthpi) {
x = (x-(float)f_tansixthpi)/(1+(float)f_tansixthpi*x); // reduce arg to under tan(f_pi/12) x = (x - (float)f_tansixthpi) / (1 + (float)f_tansixthpi * x); // reduce arg to under tan(f_pi/12)
region=true; region = true;
} }
y=atan_66s(x); // run the approximation y = atan_66s(x); // run the approximation
if (region) y+=(float)f_sixthpi; // correct for region we're in if (region) { y += (float)f_sixthpi; } // correct for region we're in
if (complement)y=(float)f_halfpi-y; // correct for 1/x if we did that if (complement) { y = (float)f_halfpi-y; } // correct for 1/x if we did that
if (sign)y=-y; // correct for negative arg if (sign) { y = -y; } // correct for negative arg
return (y); return (y);
} }
float asinf1(float x) { float asinf1(float x)
float d = 1.0f - x*x; {
if (d < 0.0f) { return nanf(""); } float d = 1.0f - x * x;
if (d < 0.0f) { return NAN; }
return 2 * atan_66(x / (1 + sqrt1(d))); return 2 * atan_66(x / (1 + sqrt1(d)));
} }
float acosf1(float x) { float acosf1(float x)
float d = 1.0f - x*x; {
if (d < 0.0f) { return nanf(""); } float d = 1.0f - x * x;
if (d < 0.0f) { return NAN; }
float y = asinf1(sqrt1(d)); float y = asinf1(sqrt1(d));
if (x >= 0.0f) { if (x >= 0.0f) {
return y; return y;
@ -388,19 +376,18 @@ float acosf1(float x) {
// https://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi // https://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
float sqrt1(const float x) float sqrt1(const float x)
{ {
union union {
{
int i; int i;
float x; float x;
} u; } u;
u.x = x; u.x = x;
u.i = (1<<29) + (u.i >> 1) - (1<<22); u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
// Two Babylonian Steps (simplified from:) // Two Babylonian Steps (simplified from:)
// u.x = 0.5f * (u.x + x/u.x); // u.x = 0.5f * (u.x + x/u.x);
// u.x = 0.5f * (u.x + x/u.x); // u.x = 0.5f * (u.x + x/u.x);
u.x = u.x + x/u.x; u.x = u.x + x / u.x;
u.x = 0.25f*u.x + x/u.x; u.x = 0.25f * u.x + x / u.x;
return u.x; return u.x;
} }