sincos.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 256 行

C
256
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  Sine, cosine and tangent routines.
*
****************************************************************************/


#include "variety.h"
#include "libsupp.h"
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include "ifprag.h"
#include "mathcode.h"
#include "rtdata.h"

#define PI              3.14159265358979323846
#define PIby2   (PI/2)
#define PIby4   (PI/4)

extern  double  _cos87(double);
extern  double  _sin87(double);
extern  double  _tan87(double);
extern  void    __fprem( double, double, int *, double * );
#if defined(__386__)
#pragma aux     _cos87  "_*" parm [edx eax] value [edx eax];
#pragma aux     _sin87  "_*" parm [edx eax] value [edx eax];
#pragma aux     _tan87  "_*" parm [edx eax] value [edx eax];
#pragma aux     __fprem "*_" parm [];
#elif defined(M_I86)
#pragma aux     _cos87  "_*" parm [ax bx cx dx] value [ax bx cx dx];
#pragma aux     _sin87  "_*" parm [ax bx cx dx] value [ax bx cx dx];
#pragma aux     _tan87  "_*" parm [ax bx cx dx] value [ax bx cx dx];
#pragma aux     __fprem "*_" parm [];
#endif

extern  double  _EvalPoly( double, const double *, int );
extern  double  _OddPoly( double, const double *, int );


static const double _sinpoly[] = {
     1.0 / (2.*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17),
    -1.0 / (2.*3*4*5*6*7*8*9*10*11*12*13*14*15),
     1.0 / (2.*3*4*5*6*7*8*9*10*11*12*13),
    -1.0 / (2.*3*4*5*6*7*8*9*10*11),
     1.0 / (2.*3*4*5*6*7*8*9),
    -1.0 / (2.*3*4*5*6*7),
     1.0 / (2.*3*4*5),
    -1.0 / (2.*3),
     1.0
};

static const double _cospoly[] = {
     1.0 / (2.*3*4*5*6*7*8*9*10*11*12*13*14*15*16),
    -1.0 / (2.*3*4*5*6*7*8*9*10*11*12*13*14),
     1.0 / (2.*3*4*5*6*7*8*9*10*11*12),
    -1.0 / (2.*3*4*5*6*7*8*9*10),
     1.0 / (2.*3*4*5*6*7*8),
    -1.0 / (2.*3*4*5*6),
     1.0 / (2.*3*4),
    -1.0 / 2.,
    1.0
};

static const int Degree[]    = { 0, 1, 2, 3, 4, 4, 5, 5, 6 };


double __sincos( double x, int flag )
{
    int     i;
    int     exponent;
    int     index;
    double  y;
    double  siny, cosy;
    double  sinx, cosx;
    static const int func_name[] = {
        FUNC_SIN,
        FUNC_TAN,
        FUNC_COS
    };

    frexp( x, &exponent );
    if( exponent >= 32 ) {
//      return( _matherr( TLOSS, func_name[flag], &x, &x, 0.0 ) );
        return( __math1err( func_name[flag] | M_TLOSS | V_ZERO, &x ) );
    }
    __fprem( x, PIby4, &i, &y );    /* 24-nov-88 */
    i = (i + (flag & 2)) & 7;
    if( i & 1 ) {                   /* if odd octant */
        y = PIby4 - y;
    }
    frexp( y, &index );
/*  if( z < ldexp( 1.0, -26 ) ) { */
//  if( z < 1.49011611938476580e-008 ) {
    if( index < -26 ) {
        siny = y;
        cosy = 1.0;
    } else {
        if( index > 0 ) {
            index = 0;
        }
        index = - index;
        if( index > 8 ) {
            index = 8;
        }
        index = Degree[ index ];
        /* only calculate the necessary polynomials */
        if( ((i + 1) & 2) || flag == 1 ) {
            cosy = _EvalPoly( y * y, &_cospoly[index], 8 - index );
        }
        if( (((i + 1) & 2) == 0) || flag == 1 ) {
            siny = _OddPoly( y, &_sinpoly[index], 8 - index );
        }
    }
#if 0
    switch( i ) {
    case 0: sinx =   siny;  cosx =   cosy;  break;
    case 1: sinx =   cosy;  cosx =   siny;  break;
    case 2: sinx =   cosy;  cosx = - siny;  break;
    case 3: sinx =   siny;  cosx = - cosy;  break;
    case 4: sinx = - siny;  cosx = - cosy;  break;
    case 5: sinx = - cosy;  cosx = - siny;  break;
    case 6: sinx = - cosy;  cosx =   siny;  break;
    case 7: sinx = - siny;  cosx =   cosy;  break;
    }
#endif
    if( (i + 1) & 2 ) {     /* if octants 1,2,5,6 */
        sinx = cosy;
    } else {                /* octants 0,3,4,7 */
        sinx = siny;
    }
    if( i & 4 ) {
        sinx = - sinx;      /* octants 4,5,6,7 */
    }
    if( flag == 1 ) {           /* if "tan" */

        /* cos is out of phase with sin by 2 octants */

        i += 2;
        if( (i + 1) & 2 ) {     /* if octants 1,2,5,6 */
            cosx = cosy;
        } else {                /* octants 0,3,4,7 */
            cosx = siny;
        }
        if( i & 4 ) {
            cosx = - cosx;      /* octants 4,5,6,7 */
        }
        if( cosx == 0.0 ) {
            __set_ERANGE();
            if( sinx > 0.0 ) return( HUGE_VAL );
            return( -HUGE_VAL );
        }
        sinx = sinx / cosx;         /* calculate value of tan function */
    }
    if( exponent >= 28 ) {
//      return( _matherr( PLOSS, func_name[flag], &x, &x, sinx ) );
        return( __math2err( func_name[flag] | M_PLOSS, &x, &sinx ) );
    }
    return( sinx );
}



_WMRTLINK float _IF_sin( float x )
/********************************/
{
    return( _IF_dsin( x ) );
}

_WMRTLINK double (sin)( double x )
/********************************/
{
    return( _IF_dsin( x ) );
}

_WMRTLINK double _IF_dsin( double x )
/************************/
{
#if defined(_M_IX86)
    if( _RWD_real87 ) return( _sin87(x) );
#endif
    return( __sincos( x, 0 ) );
}




_WMRTLINK float _IF_cos( float x )
/********************************/
{
    return( _IF_dcos( x ) );
}

_WMRTLINK double (cos)( double x )
/********************************/
{
    return( _IF_dcos( x ) );
}

_WMRTLINK double _IF_dcos( double x )
/***********************************/
{
#if defined(_M_IX86)
    if( _RWD_real87 ) return( _cos87(x) );
#endif
    return( __sincos( x, 2 ) );
}




_WMRTLINK float _IF_tan( float x )
/********************************/
{
    return( _IF_dtan( x ) );
}

_WMRTLINK double (tan)( double x )
/********************************/
{
    return( _IF_dtan( x ) );
}

_WMRTLINK double _IF_dtan( double x )
/***********************************/
{
#if defined(_M_IX86)
    if( _RWD_real87 ) return( _tan87(x) );
#endif
    return( __sincos( x, 1 ) );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?