URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
[/] [forwardcom/] [libraries/] [sincosf.as] - Rev 166
Go to most recent revision | Compare with Previous | Blame | View Log
/********************************* sincosf.as *******************************
* Author: Agner Fog
* date created: 2020-04-29
* Last modified: 2021-04-25
* Version: 1.11
* Project: ForwardCom library math.li
* Description: sin, cos, and tan functions. Calculate in radians, single precision
* The argument x can be a scalar or a vector
* The return value will be a vector with the same length
* C declaration: float sin(float x);
* C declaration: float cos(float x);
* C declaration: float tan(float x);
* C declaration: struct {float s; float c;} sincos(float x);
*
* This code is adapted from C++ vector class library www.github.com/vectorclass
* Copyright 2020-2021 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
// define constants
% M_2_PI = 0.636619772367581343076 // 2./pi
% P0sinf = -1.6666654611E-1
% P1sinf = 8.3321608736E-3
% P2sinf = -1.9515295891E-4
% P0cosf = 4.166664568298827E-2
% P1cosf = -1.388731625493765E-3
% P2cosf = 2.443315711809948E-5
% DP1F = 0.78515625 * 2.
% DP2F = 2.4187564849853515625E-4 * 2.
% DP3F = 3.77489497744594108E-8 * 2.
code section execute align = 4
public _sinf: function, reguse = 0, 0x1BF
public _cosf: function, reguse = 0, 0x1BF
public _sincosf: function, reguse = 0, 0x1BF
public _tanf: function, reguse = 0, 0x1BF
// common entry for sin and sincos functions
_sinf function
_sincosf:
/* registers:
v0 = x
v1 = abs(x)
v1 = quadrant
v2 = x^2
v3 = x^3
v4 = x^4
v5 = temp
v5 = sin
v6 = unused (vacant flag for calling function)
v7 = cos
v8 = abs(x) reduced modulo pi/2
*/
// Find quadrant:
// 0 - pi/4 => 0
// pi/4 - 3*pi/4 => 1
// 3*pi/4 - 5*pi/4 => 2
// 5*pi/4 - 7*pi/4 => 3
// 7*pi/4 - 8*pi/4 => 4
// reduce modulo pi/2, with extended precision
//nop
float v1 = clear_bit(v0, 31) // abs(x)
float v5 = v1 * M_2_PI
float v5 = round(v5, 0) // round to integer
// x = ((xa - y * DP1) - y * DP2) - y * DP3;
float v8 = v5 * (-DP1F) + v1
float v8 = v5 * (-DP2F) + v8
float v8 = v5 * (-DP3F) + v8
float v3 = !(v5 > ((1 << 22) + 0.0)) // check for loss of precision and overflow, but not NAN
float v1 = v5 + ((1 << 23) + 0.0) // add magic number 2^23 to get integer into lowest bit
float v8 = v3 ? v8 : 0 // zero if out of range. result will be -1, 0, or 1
// Taylor expansion of sin and cos, valid for -pi/4 <= x <= pi/4
// s = polynomial_2(x^2, P0sinf, P1sinf, P2sinf) * (x*x^2) + x;
float v2 = v8 * v8 // x^2
float v3 = v8 * v2 // x^3
float v4 = v2 * v2 // x^4
float v5 = replace(v8, P0sinf) // broadcast to same length as x
float v5 = v2 * P1sinf + v5
float v5 = v4 * P2sinf + v5
float v5 = v5 * v3 + v8 // sin
// c = polynomial_2(x2, P0cosf, P1cosf, P2cosf) * (x2*x2) + nmul_add(0.5f, x2, 1.0f);
float v7 = replace(v8, P0cosf) // broadcast to same length as x
float v7 = v2 * P1cosf + v7
float v7 = v4 * P2cosf + v7
float v3 = replace(v8, 1.0)
float v3 = v2 * (-0.5) + v3 // 1 - 0.5*x^2
float v7 = v7 * v4 + v3 // cos
// swap sin and cos if odd quadrant
float v3 = v1 ? v7 : v5 // sin
float v4 = v1 ? v5 : v7 // cos
// get sign of sin
int32 v5 = v1 << 30 // get bit 1 into sign bit, x modulo pi/2 = 2 or 3
int32 v5 ^= v0 // toggle with sign of original x
int32 v5 = and(v5, 1 << 31) // isolate sign bit
float v0 = v3 ^ v5 // apply sign bit to sin
// get sign of cos
int32 v1 = v1 + 1 // change sign when x modulo pi/2 = 1 or 2
int32 v1 = v1 << 30 // get bit 1 into sign bit
int32 v1 = and(v1, 1 << 31) // isolate sign bit
float v1 = v4 ^ v1 // apply sign bit to cos
// return sin in v0, cos in v1
return
_sinf end
// cosine function
_cosf function
call _sincosf
float v0 = v1 // cos is in v1
return
_cosf end
// tangent function
_tanf function
call _sincosf
float v0 = v0 / v1 // tan(x) = sin(x)/cos(x)
return
_tanf end
code end
Go to most recent revision | Compare with Previous | Blame | View Log