#include "bg_math.h"

#define crumb Com_Printf


int
Q_floor (float x)
{
  int retval;

  retval = (int)(floor(x));
  return retval;
}


int
Q_ceil (float x)
{
  int retval;

  retval = (int)(ceil(x));
  return retval;
}


int
Q_trunc (float x)
{
  int retval;

//crumb("trunc: start %f\n", x);
  retval = (int)x; /* XXX: ghetto. */
//crumb("trunc: done %d\n", retval);
  return retval;
}


/*
  Round towards nearest, towards even if halfway.
*/
int
Q_round (float x)
{
  int retval;
  int i, up, down;
  float checkpart;

//crumb("round: start %f\n", x);
  i = Q_trunc(x);
  checkpart = x - (float)i;
  if (x < 0)
    {
      up = i;
      down = i - 1;
      if (checkpart == -0.5)
        {
          if ((up % 2) == 0)
            {
              retval = up;
            }
          else
            {
              retval = down;
            }
        }
      else if (checkpart > -0.5)
        {
          retval = up;
        }
      else if (checkpart < -0.5)
        {
          retval = down;
        }
    }
  else if (x > 0)
    {
      down = i;
      up = i + 1;
      if (checkpart == 0.5)
        {
          if ((up % 2) == 0)
            {
              retval = up;
            }
          else
            {
              retval = down;
            }
        }
      else if (checkpart > 0.5)
        {
          retval = up;
        }
      else if (checkpart < 0.5)
        {
          retval = down;
        }
    }
  else
    {
      retval = 0;
    }
//crumb("round: done %d\n", retval);
  return retval;
}


float
Q_exp (float x)
{
  float retval;

  retval = exp(x);  /* The re-implemented log. */
  return retval;
}


float
Q_log (float x)
{
  float retval;

  retval = ln(x);
  return retval;
}


float
Q_sin (float theta)
{
  float retval;

  retval = sin(theta);
  return retval;
}


float
Q_cos (float theta)
{
  float retval;

  retval = cos(theta);
  return retval;
}


float
Q_tan (float theta)
{
  float retval;

  retval = (Q_sin(theta) / Q_cos(theta));
  return retval;
}


float
Q_atan2 (float y, float x)
{
  float retval;

  retval = atan2(y, x);
  return retval;
}


float
Q_atan (float x)
{
  return atan2(x, 1.0);
}


float
Q_asin (float x)
{
  float retval;

  retval = Q_atan2(x, sqrt(1 - (x * x)));
  return retval;
}


/* Derivation of arccosine/inverse-cosine, by PhaethonH:

           /|
      h  /  |
       /    | o
     /      |
  T --------+
       a

 (1) x = cos(T)
 (2) sin(T) = o/h
 (3) cos(T) = a/h
 (4) tan(T) = o/a
 (5) (sin(T))^2 + (cos(T))^2 = 1
 (6) tan(T) = sin(T) / cos(T)

Equation (1) tells us we know what the value of cos(T) is, but not of sin(T).
From (5); getting sin(T) in terms of cos(T):
     (sin(T))^2 + (cos(T))^2 = 1
     (sin(T))^2              = 1 - (cos(T))^2
 (7) sin(T)             = sqrt(1 - (cos(T))^2)

Taking (6):
      tan(T) = sin(T) / cos(T)
Applying (7); substituting sin(T):
      tan(T) = (sqrt(1 - (cos(T))^2)) / cos(T)
Apply atan; isolating T:
 (8)  T  = atan(sqrt(1 - (cos(T))^2)) / cos(T))
Apply (1); substituting cos(T):
 (9)  T  = atan(sqrt(1 -  (x * x)) / x)


Similar process for obtaining asin.

*/

float
Q_acos (float x)
{
  float retval;

  retval = Q_atan2(sqrt(1 - (x * x)), x);
  return retval;
}


float
Q_sqrt (float x)
{
  float retval;

  retval = sqrt(x);
  return retval;
}


float
Q_hypot (float a, float b)
{
  float retval;

  retval = Q_sqrt(a*a + b*b);
  return retval;
}


float
Q_rint (float x)
{
  float retval;
//crumb("rint: start %f\n", x);
  retval = (float)(Q_round(x));
/* Raise inexact exception how? */
//crumb("rint: done %f\n", x);
  return retval;
}








/* Following added to support Ogg Vorbis. */

double
atan (double x)
{
  double retval;
  retval = Q_atan(x);
  return retval;
}

double
log (double x)
{
  double retval;
  retval = Q_log(x);
  return retval;
}

float
hypot (float a, float b)
{
  return (sqrt(a*a + b*b));
}

double
rint (double x)
{
  double retval;
//crumb("_rint: start %f\n", x);
  retval = Q_rint(x);
//crumb("_rint: done %f\n", retval);
  return retval;
}

long int
labs (long int x)
{
  return abs(x);
}

double
ldexp (double x, int y)
{
  double retval;
  double z;
  /* x * (2 ^ y) */
//crumb("ldexp: start %f * 2 ^ %d\n", x, y);
  z = pow(2.0, (float)y);
//crumb("ldexp: z = %f\n", z);
  retval = x * z;
//crumb("ldexp: retval = %f\n", retval);
  return retval;
}

