Beispiel #1
0
char
float_tanh(
  floatnum x,
  int digits)
{
  signed char sgn;

  if (!chckmathparam(x, digits))
    return 0;
  sgn = float_getsign(x);
  float_abs(x);
  if (float_cmp(x, &c1Div2) >= 0)
    _tanhgt0_5(x, digits);
  else
    _tanhlt0_5(x, digits);
  float_setsign(x, sgn);
  return 1;
}
Beispiel #2
0
char
float_raise(
  floatnum power,
  cfloatnum base,
  cfloatnum exponent,
  int digits)
{
  signed char sgn;

  if (float_isnan(exponent) || float_isnan(base))
    return _seterror(power, NoOperand);
  if (digits <= 0 || digits > MATHPRECISION)
    return _seterror(power, InvalidPrecision);
  if (float_iszero(base))
  {
    switch(float_getsign(exponent))
    {
    case 0:
      return _seterror(power, OutOfDomain);
    case -1:
      return _seterror(power, ZeroDivide);
    }
    return _setzero(power);
  }
  sgn = float_getsign(base);
  if (sgn < 0)
  {
    if (!float_isinteger(exponent))
      return _seterror(power, OutOfDomain);
    if ((float_getdigit(exponent, float_getexponent(exponent)) & 1) == 0)
      sgn = 1;
  }
  float_copy(power, base, digits+1);
  float_abs(power);
  if (!_raise(power, exponent, digits))
  {
    float_seterror(Overflow);
    if (float_getexponent(base) * float_getsign(exponent) < 0)
      float_seterror(Underflow);
    return _setnan(power);
  }
  float_setsign(power, sgn);
  return 1;
}
Beispiel #3
0
/* evaluates arctan x for all x. The result is in the
   range -pi/2 < result < pi/2
   relative error for a 100 digit result is 9e-100 */
void
_arctan(
  floatnum x,
  int digits)
{
  signed char sgn;

  if (float_abscmp(x, &c1) > 0)
  {
    sgn = float_getsign(x);
    float_abs(x);
    float_reciprocal(x, digits);
    _arctanlt1(x, digits);
    float_sub(x, &cPiDiv2, x, digits+1);
    float_setsign(x, sgn);
  }
  else
    _arctanlt1(x, digits);
}
Beispiel #4
0
void
_logic2floatnum(
  floatnum f,
  t_longint* longint)
{
  int idx;
  signed char sign;

  sign = _signextend(longint);
  if (sign < 0)
    _neg(longint);
  idx = MAXIDX;
  while (idx >= 0 && longint->value[idx] == 0)
    --idx;
  if (idx < 0)
    longint->length = 0;
  else
    longint->length = idx + 1;
  _longint2floatnum(f, longint);
  float_setsign(f, sign);
}
Beispiel #5
0
/* evaluate sin x for |x| <= pi/4,
   using |sin x| = sqrt((1-cos x)*(2 + cos x-1)) 
   relative error for 100 digit results is < 6e-100*/
void
_sinltPiDiv4(
  floatnum x,
  int digits)
{
  floatstruct tmp;
  signed char sgn;

  if (2*float_getexponent(x)+2 < -digits)
    /* for small x: sin x approx.== x */
    return;
  float_create(&tmp);
  sgn = float_getsign(x);
  _cosminus1ltPiDiv4(x, digits);
  float_add(&tmp, x, &c2, digits+1);
  float_mul(x, x, &tmp, digits+1);
  float_abs(x);
  float_sqrt(x, digits);
  float_setsign(x, sgn);
  float_free(&tmp);
}
Beispiel #6
0
/* evaluates sin x for |x| <= pi. */
void
_sin(
  floatnum x,
  int digits)
{
  signed char sgn;

  sgn = float_getsign(x);
  float_abs(x);
  if (float_cmp(x, &cPiDiv2) > 0)
    float_sub(x, &cPi, x, digits+1);
  if (float_cmp(x, &cPiDiv4) <= 0)
    _sinltPiDiv4(x, digits);
  else
  {
    float_sub(x, &cPiDiv2, x, digits+1);
    if (2*float_getexponent(x)+2 < - digits)
      float_setzero(x);
    else
      _cosminus1ltPiDiv4(x, digits);
    float_add(x, x, &c1, digits);
  }
  float_setsign(x, sgn);
}
Beispiel #7
0
/* the Taylor series of arctan/arctanh x at x == 0. For small
   |x| < 0.01 this series converges very fast, yielding 4 or
   more digits of the result with every summand. The working
   precision is adjusted, so that the relative error for
   100-digit arguments is around 5.0e-100. This means, the error
   is 1 in the 100-th place (or less) */
void
arctanseries(
  floatnum x,
  int digits,
  char alternating)
{
  int expx;
  int expsqrx;
  int pwrsz;
  int addsz;
  int i;
  floatstruct xsqr;
  floatstruct pwr;
  floatstruct smd;
  floatstruct sum;

  /* upper limit of log(x) and log(result) */
  expx = float_getexponent(x)+1;

  /* the summands of the series from the second on are
     bounded by x^(2*i-1)/3. So the summation yields a
     result bounded by (x^3/(1-x*x))/3.
     For x < sqrt(1/3) approx.= 0.5, this is less than 0.5*x^3.
     We need to sum up only, if the first <digits> places
     of the result (roughly x) are touched. Ignoring the effect of
     a possile carry, this is only the case, if
     x*x >= 2*10^(-digits) > 10^(-digits)
     Example: for x = 9e-51, a 100-digits result covers
     the decimal places from 1e-51 to 1e-150. x^3/3
     is roughly 3e-151, and so is the sum of the series.
     So we can ignore the sum, but we couldn't for x = 9e-50 */
  if (float_iszero(x) || 2*expx < -digits)
    /* for very tiny arguments arctan/arctanh x is approx.== x */
    return;
  float_create(&xsqr);
  float_create(&pwr);
  float_create(&smd);
  float_create(&sum);

  /* we adapt the working precision to the decreasing
     summands, saving time when multiplying. Unfortunately,
     there is no error bound given for the operations of
     bc_num. Tests show, that the last digit in an incomplete
     multiplication is usually not correct up to 5 ULP's. */
  pwrsz = digits + 2*expx + 1;
  /* the precision of the addition must not decrease, of course */
  addsz = pwrsz;
  i = 3;
  float_mul(&xsqr, x, x, pwrsz);
  float_setsign(&xsqr, alternating? -1 : 1);
  expsqrx = float_getexponent(&xsqr);
  float_copy(&pwr, x, pwrsz);
  float_setzero(&sum);

  for(; pwrsz > 0; )
  {
    /* x^i */
    float_mul(&pwr, &pwr, &xsqr, pwrsz+1);
    /* x^i/i */
    float_divi(&smd, &pwr, i, pwrsz);
    /* The addition virtually does not introduce errors */
    float_add(&sum, &sum, &smd, addsz);
    /* reduce the working precision according to the decreasing powers */
    pwrsz = digits - expx + float_getexponent(&smd) + expsqrx + 3;
    i += 2;
  }
  /* add the first summand */
  float_add(x, x, &sum, digits+1);

  float_free(&xsqr);
  float_free(&pwr);
  float_free(&smd);
  float_free(&sum);
}