/* Copyright (C) 1993, 2000 artofcode LLC.  All rights reserved.
  
  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 the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA, 02111-1307.

*/

/*$Id: gxfarith.h,v 1.3.6.1.2.1 2003/01/17 00:49:03 giles Exp $ */
/* Floating point arithmetic macros for Ghostscript library */

#ifndef gxfarith_INCLUDED
#  define gxfarith_INCLUDED

#include "gconfigv.h"		/* for USE_FPU */
#include "gxarith.h"

/*
 * The following macros replace the ones in gxarith.h on machines
 * that are likely to have very slow floating point.
 *
 * None of these macros would be necessary if compilers had a clue
 * about generating good floating point comparisons on machines with
 * slow (or no) floating point hardware.
 */

# if USE_FPU <= 0 && arch_floats_are_IEEE && (arch_sizeof_float == arch_sizeof_int || arch_sizeof_float == arch_sizeof_long)

#  if arch_sizeof_float == arch_sizeof_int
typedef int _f_int_t;
typedef uint _f_uint_t;

#  else				/* arch_sizeof_float == arch_sizeof_long */
typedef long _f_int_t;
typedef ulong _f_uint_t;

#  endif
#  define _f_as_int(f) *(const _f_int_t *)(&(f))
#  define _f_as_uint(f) *(const _f_uint_t *)(&(f))

#  if arch_sizeof_double == arch_sizeof_int
#    define _d_int_t int
#  else
#   if arch_sizeof_double == arch_sizeof_long
#    define _d_int_t long
#   endif
#  endif
#  define _d_uint_t unsigned _d_int_t
#  define _d_as_int(f) *(const _d_int_t *)(&(d))
#  define _d_as_uint(f) *(const _d_uint_t *)(&(d))

#  define _ftest(v,f,n)\
     (sizeof(v)==sizeof(float)?(f):(n))
#  ifdef _d_int_t
#    define _fdtest(v,f,d,n)\
	(sizeof(v)==sizeof(float)?(f):sizeof(v)==sizeof(double)?(d):(n))
#  else
#    define _fdtest(v,f,d,n)\
	_ftest(v,f,n)
#  endif

#  undef is_fzero
#  define is_fzero(f)	/* must handle both +0 and -0 */\
     _fdtest(f, (_f_as_int(f) << 1) == 0, (_d_as_int(f) << 1) == 0,\
       (f) == 0.0)

#  undef is_fzero2
#  define is_fzero2(f1,f2)\
     (sizeof(f1) == sizeof(float) && sizeof(f2) == sizeof(float) ?\
      ((_f_as_int(f1) | _f_as_int(f2)) << 1) == 0 :\
      (f1) == 0.0 && (f2) == 0.0)

#  undef is_fneg
#  if arch_is_big_endian
#    define _is_fnegb(f) (*(const byte *)&(f) >= 0x80)
#  else
#    define _is_fnegb(f) (((const byte *)&(f))[sizeof(f) - 1] >= 0x80)
#  endif
#  if arch_sizeof_float == arch_sizeof_int
#    define is_fneg(f)\
       (sizeof(f) == sizeof(float) ? _f_as_int(f) < 0 :\
	_is_fnegb(f))
#  else
#    define is_fneg(f) _is_fnegb(f)
#  endif

#  define IEEE_expt 0x7f800000	/* IEEE exponent mask */
#  define IEEE_f1 0x3f800000	/* IEEE 1.0 */

#  undef is_fge1
#  if arch_sizeof_float == arch_sizeof_int
#    define is_fge1(f)\
       (sizeof(f) == sizeof(float) ?\
	(_f_as_int(f)) >= IEEE_f1 :\
	(f) >= 1.0)
#  else				/* arch_sizeof_float == arch_sizeof_long */
#    define is_fge1(f)\
       (sizeof(f) == sizeof(float) ?\
	(int)(_f_as_int(f) >> 16) >= (IEEE_f1 >> 16) :\
	(f) >= 1.0)
#  endif

#  undef f_fits_in_ubits
#  undef f_fits_in_bits
#  define _f_bits(n) (4.0 * (1L << ((n) - 2)))
#  define f_fits_in_ubits(f, n)\
	_ftest(f, _f_as_uint(f) < (_f_uint_t)IEEE_f1 + ((_f_uint_t)(n) << 23),\
	  (f) >= 0 && (f) < _f_bits(n))
#  define f_fits_in_bits(f, n)\
	_ftest(f, (_f_as_uint(f) & IEEE_expt) < IEEE_f1 + ((_f_uint_t)((n)-1) << 23),\
	  (f) >= -_f_bits((n)-1) && (f) < _f_bits((n)-1))

# endif				/* USE_FPU <= 0 & ... */

/*
 * Define sine and cosine functions that take angles in degrees rather than
 * radians, hit exact values at multiples of 90 degrees, and are implemented
 * efficiently on machines with slow (or no) floating point.
 */
double gs_sin_degrees(P1(double angle));
double gs_cos_degrees(P1(double angle));
typedef struct gs_sincos_s {
    double sin, cos;
    bool orthogonal;		/* angle is multiple of 90 degrees */
} gs_sincos_t;
void gs_sincos_degrees(P2(double angle, gs_sincos_t * psincos));

/*
 * Define an atan2 function that returns an angle in degrees and uses
 * the PostScript quadrant rules.  Note that it may return
 * gs_error_undefinedresult.
 */
int gs_atan2_degrees(P3(double y, double x, double *pangle));

#endif /* gxfarith_INCLUDED */
