postgresql/src/backend/utils/adt/float.c

1480 lines
28 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* float.c--
* Functions for the built-in floating-point types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.14 1997/05/11 15:11:38 thomas Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
* Basic float4 ops:
* float4in, float4out, float4abs, float4um
* Basic float8 ops:
* float8in, float8inAd, float8out, float8outAd, float8abs, float8um
* Arithmetic operators:
* float4pl, float4mi, float4mul, float4div
* float8pl, float8mi, float8mul, float8div
* Comparison operators:
* float4eq, float4ne, float4lt, float4le, float4gt, float4ge
* float8eq, float8ne, float8lt, float8le, float8gt, float8ge
* Conversion routines:
* ftod, dtof, itod, dtoi, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
*
* Random float8 ops:
* dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
* Arithmetic operators:
* float48pl, float48mi, float48mul, float48div
* float84pl, float84mi, float84mul, float84div
* Comparison operators:
* float48eq, float48ne, float48lt, float48le, float48gt, float48ge
* float84eq, float84ne, float84lt, float84le, float84gt, float84ge
*
* (You can do the arithmetic and comparison stuff using conversion
* routines, but then you pay the overhead of converting...)
*
* XXX GLUESOME STUFF. FIX IT! -AY '94
*
* Added some additional conversion routines and cleaned up
* a bit of the existing code. Need to change the error checking
* for calls to pow(), exp() since on some machines (my Linux box
* included) these routines do not set errno. - tgl 97/05/10
*/
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h> /* faked on sunos4 */
#include <math.h>
#include "postgres.h"
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include "fmgr.h"
#include "utils/builtins.h" /* for ftod() prototype */
#include "utils/palloc.h"
#ifndef SHRT_MAX
#define SHRT_MAX 32767
#endif
#ifndef SHRT_MIN
#define SHRT_MIN (-32768)
#endif
#define FORMAT 'g' /* use "g" output format as standard format */
/* not sure what the following should be, but better to make it over-sufficient */
#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
#if !(NeXT && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_2)
/* NS3.3 has conflicting declarations of these in <math.h> */
#ifndef atof
extern double atof(const char *p);
#endif
#ifndef HAVE_CBRT
# define cbrt my_cbrt
static double cbrt(double x);
#else
# if !defined(nextstep)
extern double cbrt(double x);
# endif
#endif
#ifndef HAVE_RINT
# define rint my_rint
static double rint(double x);
#else
extern double rint(double x);
#endif
#ifndef HAVE_ISINF
# define isinf my_isinf
static int isinf(double x);
#else
extern int isinf(double x);
#endif
#endif
/* ========== USER I/O ROUTINES ========== */
#define FLOAT4_MAX FLT_MAX
#define FLOAT4_MIN FLT_MIN
#define FLOAT8_MAX DBL_MAX
#define FLOAT8_MIN DBL_MIN
/*
* if FLOAT8_MIN and FLOAT8_MAX are the limits of the range a
* double can store, then how are we ever going to wind up
* with something stored in a double that is outside those
* limits? (and similarly for FLOAT4_{MIN,MAX}/float.)
* doesn't make sense to me, and it causes a
* floating point exception on linuxalpha, so UNSAFE_FLOATS
* it is.
* (maybe someone wanted to allow for values other than DBL_MIN/
* DBL_MAX for FLOAT8_MIN/FLOAT8_MAX?)
* --djm 12/12/96
* according to Richard Henderson this is a known bug in gcc on
* the Alpha. might as well leave the workaround in
* until the distributions are updated.
* --djm 12/16/96
*/
#if defined(linuxalpha) && !defined(UNSAFE_FLOATS)
#define UNSAFE_FLOATS
#endif
/*
check to see if a float4 val is outside of
the FLOAT4_MIN, FLOAT4_MAX bounds.
raise an elog warning if it is
*/
static void CheckFloat4Val(double val)
{
/* defining unsafe floats's will make float4 and float8 ops faster
at the cost of safety, of course! */
#ifdef UNSAFE_FLOATS
return;
#else
if (fabs(val) > FLOAT4_MAX)
elog(WARN,"\tBad float4 input format -- overflow\n");
if (val != 0.0 && fabs(val) < FLOAT4_MIN)
elog(WARN,"\tBad float4 input format -- underflow\n");
return;
#endif /* UNSAFE_FLOATS */
}
/*
check to see if a float8 val is outside of
the FLOAT8_MIN, FLOAT8_MAX bounds.
raise an elog warning if it is
*/
void CheckFloat8Val(double val)
{
/* defining unsafe floats's will make float4 and float8 ops faster
at the cost of safety, of course! */
#ifdef UNSAFE_FLOATS
return;
#else
if (fabs(val) > FLOAT8_MAX)
elog(WARN,"\tBad float8 input format -- overflow\n");
if (val != 0.0 && fabs(val) < FLOAT8_MIN)
elog(WARN,"\tBad float8 input format -- underflow\n");
return;
#endif /* UNSAFE_FLOATS */
}
/*
* float4in - converts "num" to float
* restricted syntax:
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
* where <sp> is a space, digit is 0-9,
* <exp> is "e" or "E" followed by an integer.
*/
float32 float4in(char *num)
{
float32 result = (float32) palloc(sizeof(float32data));
double val;
char* endptr;
errno = 0;
val = strtod(num,&endptr);
if (*endptr != '\0' || errno == ERANGE)
elog(WARN,"\tBad float4 input format\n");
/* if we get here, we have a legal double, still need to check to see
if it's a legal float */
CheckFloat4Val(val);
*result = val;
return result;
}
/*
* float4out - converts a float4 number to a string
* using a standard output format
*/
char *float4out(float32 num)
{
char *ascii = (char *)palloc(MAXFLOATWIDTH+1);
if (!num)
return strcpy(ascii, "(null)");
sprintf(ascii, "%.*g", FLT_DIG, *num);
return(ascii);
}
/*
* float8in - converts "num" to float8
* restricted syntax:
* {<sp>} [+|-] {digit} [.{digit}] [<exp>]
* where <sp> is a space, digit is 0-9,
* <exp> is "e" or "E" followed by an integer.
*/
float64 float8in(char *num)
{
float64 result = (float64) palloc(sizeof(float64data));
double val;
char* endptr;
errno = 0;
val = strtod(num,&endptr);
if (*endptr != '\0' || errno == ERANGE)
elog(WARN,"\tBad float8 input format\n");
CheckFloat8Val(val);
*result = val;
return(result);
}
/*
* float8out - converts float8 number to a string
* using a standard output format
*/
char *float8out(float64 num)
{
char *ascii = (char *)palloc(MAXDOUBLEWIDTH+1);
if (!num)
return strcpy(ascii, "(null)");
if (isnan(*num))
return strcpy(ascii, "NaN");
if (isinf(*num))
return strcpy(ascii, "Infinity");
sprintf(ascii, "%.*g", DBL_DIG, *num);
return(ascii);
}
/* ========== PUBLIC ROUTINES ========== */
/*
* ======================
* FLOAT4 BASE OPERATIONS
* ======================
*/
/*
* float4abs - returns a pointer to |arg1| (absolute value)
*/
float32 float4abs(float32 arg1)
{
float32 result;
double val;
if (!arg1)
return (float32)NULL;
val = fabs(*arg1);
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return(result);
}
/*
* float4um - returns a pointer to -arg1 (unary minus)
*/
float32 float4um(float32 arg1)
{
float32 result;
double val;
if (!arg1)
return (float32)NULL;
val = ((*arg1 != 0) ? -(*arg1): *arg1);
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return(result);
}
float32 float4larger(float32 arg1, float32 arg2)
{
float32 result;
if (!arg1 || !arg2)
return (float32)NULL;
result = (float32) palloc(sizeof(float32data));
*result = ((*arg1 > *arg2) ? *arg1 : *arg2);
return result;
}
float32 float4smaller(float32 arg1, float32 arg2)
{
float32 result;
if (!arg1 || !arg2)
return (float32)NULL;
result = (float32) palloc(sizeof(float32data));
*result = ((*arg1 > *arg2) ? *arg2 : *arg1);
return result;
}
/*
* ======================
* FLOAT8 BASE OPERATIONS
* ======================
*/
/*
* float8abs - returns a pointer to |arg1| (absolute value)
*/
float64 float8abs(float64 arg1)
{
float64 result;
double val;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
val = fabs(*arg1);
CheckFloat8Val(val);
*result = val;
return(result);
}
/*
* float8um - returns a pointer to -arg1 (unary minus)
*/
float64 float8um(float64 arg1)
{
float64 result;
double val;
if (!arg1)
return (float64)NULL;
val = ((*arg1 != 0)? -(*arg1): *arg1);
CheckFloat8Val(val);
result = (float64) palloc(sizeof(float64data));
*result = val;
return(result);
}
float64 float8larger(float64 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = ((*arg1 > *arg2) ? *arg1 : *arg2);
return result;
}
float64 float8smaller(float64 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = ((*arg1 > *arg2) ? *arg2 : *arg1);
return result;
}
/*
* ====================
* ARITHMETIC OPERATORS
* ====================
*/
/*
* float4pl - returns a pointer to arg1 + arg2
* float4mi - returns a pointer to arg1 - arg2
* float4mul - returns a pointer to arg1 * arg2
* float4div - returns a pointer to arg1 / arg2
* float4inc - returns a poniter to arg1 + 1.0
*/
float32 float4pl(float32 arg1, float32 arg2)
{
float32 result;
double val;
if (!arg1 || !arg2)
return (float32)NULL;
val = *arg1 + *arg2;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return(result);
}
float32 float4mi(float32 arg1, float32 arg2)
{
float32 result;
double val;
if (!arg1 || !arg2)
return (float32)NULL;
val = *arg1 - *arg2;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return(result);
}
float32 float4mul(float32 arg1, float32 arg2)
{
float32 result;
double val;
if (!arg1 || !arg2)
return (float32)NULL;
val = *arg1 * *arg2;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return(result);
}
float32 float4div(float32 arg1, float32 arg2)
{
float32 result;
double val;
if (!arg1 || !arg2)
return (float32)NULL;
if (*arg2 == 0.0)
elog(WARN,"float4div: divide by 0.0 error");
val = *arg1 / *arg2;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = *arg1 / *arg2;
return(result);
}
float32 float4inc(float32 arg1)
{
double val;
if (!arg1)
return (float32)NULL;
val = *arg1 + (float32data)1.0;
CheckFloat4Val(val);
*arg1 = val;
return arg1;
}
/*
* float8pl - returns a pointer to arg1 + arg2
* float8mi - returns a pointer to arg1 - arg2
* float8mul - returns a pointer to arg1 * arg2
* float8div - returns a pointer to arg1 / arg2
* float8inc - returns a pointer to arg1 + 1.0
*/
float64 float8pl(float64 arg1, float64 arg2)
{
float64 result;
double val;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
val = *arg1 + *arg2;
CheckFloat8Val(val);
*result = val;
return(result);
}
float64 float8mi(float64 arg1, float64 arg2)
{
float64 result;
double val;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
val = *arg1 - *arg2;
CheckFloat8Val(val);
*result = val;
return(result);
}
float64 float8mul(float64 arg1, float64 arg2)
{
float64 result;
double val;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
val = *arg1 * *arg2;
CheckFloat8Val(val);
*result = val;
return(result);
}
float64 float8div(float64 arg1, float64 arg2)
{
float64 result;
double val;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
if (*arg2 == 0.0)
elog(WARN,"float8div: divide by 0.0 error");
val = *arg1 / *arg2;
CheckFloat8Val(val);
*result = val;
return(result);
}
float64 float8inc(float64 arg1)
{
double val;
if (!arg1)
return (float64)NULL;
val = *arg1 + (float64data)1.0;
CheckFloat8Val(val);
*arg1 = val;
return(arg1);
}
/*
* ====================
* COMPARISON OPERATORS
* ====================
*/
/*
* float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
*/
bool float4eq(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 == *arg2);
}
bool float4ne(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 != *arg2);
}
bool float4lt(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 < *arg2);
}
bool float4le(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 <= *arg2);
}
bool float4gt(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 > *arg2);
}
bool float4ge(float32 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 >= *arg2);
}
/*
* float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
*/
bool float8eq(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 == *arg2);
}
bool float8ne(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 != *arg2);
}
bool float8lt(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 < *arg2);
}
bool float8le(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 <= *arg2);
}
bool float8gt(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 > *arg2);
}
bool float8ge(float64 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 >= *arg2);
}
/*
* ===================
* CONVERSION ROUTINES
* ===================
*/
/*
* ftod - converts a float4 number to a float8 number
*/
float64 ftod(float32 num)
{
float64 result;
if (!num)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *num;
return(result);
}
/*
* dtof - converts a float8 number to a float4 number
*/
float32 dtof(float64 num)
{
float32 result;
if (!num)
return (float32)NULL;
CheckFloat4Val(*num);
result = (float32) palloc(sizeof(float32data));
*result = *num;
return(result);
}
/*
* dtoi - converts a float8 number to an int4 number
*/
int32 dtoi(float64 num)
{
int32 result;
if (!num)
elog(WARN,"dtoi: unable to convert null",NULL);
if ((*num < INT_MIN) || (*num > INT_MAX))
elog(WARN,"dtoi: integer out of range",NULL);
result = rint(*num);
return(result);
}
/*
* dtoi2 - converts a float8 number to an int2 number
*/
int16 dtoi2(float64 num)
{
int16 result;
if (!num)
elog(WARN,"dtoi2: unable to convert null",NULL);
if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
elog(WARN,"dtoi2: integer out of range",NULL);
result = rint(*num);
return(result);
}
/*
* itod - converts an int4 number to a float8 number
*/
float64 itod(int32 num)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = num;
return(result);
}
/*
* i2tod - converts an int2 number to a float8 number
*/
float64 i2tod(int16 num)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = num;
return(result);
}
/*
* ftoi - converts a float8 number to an int4 number
*/
int32 ftoi(float32 num)
{
int32 result;
if (!num)
elog(WARN,"ftoi: unable to convert null",NULL);
if ((*num < INT_MIN) || (*num > INT_MAX))
elog(WARN,"ftoi: integer out of range",NULL);
result = rint(*num);
return(result);
}
/*
* ftoi2 - converts a float8 number to an int2 number
*/
int16 ftoi2(float32 num)
{
int16 result;
if (!num)
elog(WARN,"ftoi2: unable to convert null",NULL);
if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
elog(WARN,"ftoi2: integer out of range",NULL);
result = rint(*num);
return(result);
}
/*
* itof - converts an int4 number to a float8 number
*/
float32 itof(int32 num)
{
float32 result;
result = (float32) palloc(sizeof(float32data));
*result = num;
return(result);
}
/*
* i2tof - converts an int2 number to a float8 number
*/
float32 i2tof(int16 num)
{
float32 result;
result = (float32) palloc(sizeof(float32data));
*result = num;
return(result);
}
/*
* =======================
* RANDOM FLOAT8 OPERATORS
* =======================
*/
/*
* dround - returns a pointer to ROUND(arg1)
*/
float64 dround(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
*result = (float64data) rint(tmp);
return(result);
}
/*
* dtrunc - returns a pointer to truncation of arg1,
* arg1 >= 0 ... the greatest integer as float8 less
* than or equal to arg1
* arg1 < 0 ... the greatest integer as float8 greater
* than or equal to arg1
*/
float64 dtrunc(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
if (*arg1 >= 0)
*result = (float64data) floor(tmp);
else
*result = (float64data) -(floor(-tmp));
return(result);
}
/*
* dsqrt - returns a pointer to square root of arg1
*/
float64 dsqrt(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
*result = (float64data) sqrt(tmp);
return (result);
}
/*
* dcbrt - returns a pointer to cube root of arg1
*/
float64 dcbrt(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
*result = (float64data) cbrt(tmp);
return(result);
}
/*
* dpow - returns a pointer to pow(arg1,arg2)
*/
float64 dpow(float64 arg1, float64 arg2)
{
float64 result;
double tmp1, tmp2;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp1 = *arg1;
tmp2 = *arg2;
errno = 0;
*result = (float64data) pow(tmp1, tmp2);
if (errno == ERANGE)
elog(WARN, "pow() returned a floating point out of the range\n");
CheckFloat8Val(*result);
return(result);
}
/*
* dexp - returns a pointer to the exponential function of arg1
*/
float64 dexp(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) exp(tmp);
if (errno == ERANGE)
elog(WARN, "exp() returned a floating point out of range\n");
CheckFloat8Val(*result);
return(result);
}
/*
* dlog1 - returns a pointer to the natural logarithm of arg1
* ("dlog" is already a logging routine...)
*/
float64 dlog1(float64 arg1)
{
float64 result;
double tmp;
if (!arg1)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
if (tmp == 0.0)
elog(WARN, "can't take log of 0!");
if (tmp < 0)
elog(WARN, "can't take log of a negative number");
*result = (float64data) log(tmp);
CheckFloat8Val(*result);
return(result);
}
/*
* ====================
* ARITHMETIC OPERATORS
* ====================
*/
/*
* float48pl - returns a pointer to arg1 + arg2
* float48mi - returns a pointer to arg1 - arg2
* float48mul - returns a pointer to arg1 * arg2
* float48div - returns a pointer to arg1 / arg2
*/
float64 float48pl(float32 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 + *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float48mi(float32 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 - *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float48mul(float32 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 * *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float48div(float32 arg1, float64 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
if (*arg2 == 0.0)
elog(WARN, "float48div: divide by 0.0 error!");
*result = *arg1 / *arg2;
CheckFloat8Val(*result);
return(result);
}
/*
* float84pl - returns a pointer to arg1 + arg2
* float84mi - returns a pointer to arg1 - arg2
* float84mul - returns a pointer to arg1 * arg2
* float84div - returns a pointer to arg1 / arg2
*/
float64 float84pl(float64 arg1, float32 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 + *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float84mi(float64 arg1, float32 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 - *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float84mul(float64 arg1, float32 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
*result = *arg1 * *arg2;
CheckFloat8Val(*result);
return(result);
}
float64 float84div(float64 arg1, float32 arg2)
{
float64 result;
if (!arg1 || !arg2)
return (float64)NULL;
result = (float64) palloc(sizeof(float64data));
if (*arg2 == 0.0)
elog(WARN, "float48div: divide by 0.0 error!");
*result = *arg1 / *arg2;
CheckFloat8Val(*result);
return(result);
}
/*
* ====================
* COMPARISON OPERATORS
* ====================
*/
/*
* float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
*/
bool float48eq(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 == (float)*arg2);
}
bool float48ne(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 != (float)*arg2);
}
bool float48lt(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 < (float)*arg2);
}
bool float48le(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 <= (float)*arg2);
}
bool float48gt(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 > (float)*arg2);
}
bool float48ge(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return(*arg1 >= (float)*arg2);
}
/*
* float84{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
*/
bool float84eq(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 == *arg2);
}
bool float84ne(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 != *arg2);
}
bool float84lt(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 < *arg2);
}
bool float84le(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 <= *arg2);
}
bool float84gt(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 > *arg2);
}
bool float84ge(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return((float)*arg1 >= *arg2);
}
/* ========== PRIVATE ROUTINES ========== */
/* From "fdlibm" @ netlib.att.com */
#ifndef HAVE_RINT
/* @(#)s_rint.c 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/*
* rint(x)
* Return x rounded to integral value according to the prevailing
* rounding mode.
* Method:
* Using floating addition.
* Exception:
* Inexact flag raised if x not equal to rint(x).
*/
#ifdef __STDC__
static const double
#else
static double
#endif
one = 1.0,
TWO52[2]={
4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
-4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
};
#ifdef __STDC__
static double rint(double x)
#else
static double rint(x)
double x;
#endif
{
int i0,n0,j0,sx;
unsigned i,i1;
double w,t;
n0 = (*((int *)&one)>>29)^1;
i0 = *(n0+(int*)&x);
sx = (i0>>31)&1;
i1 = *(1-n0+(int*)&x);
j0 = ((i0>>20)&0x7ff)-0x3ff;
if(j0<20) {
if(j0<0) {
if(((i0&0x7fffffff)|i1)==0) return x;
i1 |= (i0&0x0fffff);
i0 &= 0xfffe0000;
i0 |= ((i1|-i1)>>12)&0x80000;
*(n0+(int*)&x)=i0;
w = TWO52[sx]+x;
t = w-TWO52[sx];
i0 = *(n0+(int*)&t);
*(n0+(int*)&t) = (i0&0x7fffffff)|(sx<<31);
return t;
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */
i>>=1;
if(((i0&i)|i1)!=0) {
if(j0==19) i1 = 0x40000000; else
i0 = (i0&(~i))|((0x20000)>>j0);
}
}
} else if (j0>51) {
if(j0==0x400) return x+x; /* inf or NaN */
else return x; /* x is integral */
} else {
i = ((unsigned)(0xffffffff))>>(j0-20);
if((i1&i)==0) return x; /* x is integral */
i>>=1;
if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
}
*(n0+(int*)&x) = i0;
*(1-n0+(int*)&x) = i1;
w = TWO52[sx]+x;
return w-TWO52[sx];
}
#endif /* !HAVE_RINT */
#ifndef HAVE_CBRT
static
double
cbrt(x)
double x;
{
int isneg = (x < 0.0);
double tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
return(isneg ? -tmpres : tmpres);
}
#endif /* !HAVE_CBRT */
#ifndef HAVE_ISINF
1996-10-31 11:23:28 +01:00
#if defined(aix)
#ifdef CLASS_CONFLICT
/* we want the math symbol */
#undef class
#endif /* CLASS_CONFICT */
static int isinf(x)
double x;
{
int fpclass = class(x);
if (fpclass == FP_PLUS_INF)
return(1);
if (fpclass == FP_MINUS_INF)
return(-1);
return(0);
}
1996-10-31 11:23:28 +01:00
#endif /* aix */
1996-10-31 11:23:28 +01:00
#if defined(ultrix4)
#include <fp_class.h>
static int isinf(x)
double x;
{
int fpclass = fp_class_d(x);
if (fpclass == FP_POS_INF)
return(1);
if (fpclass == FP_NEG_INF)
return(-1);
return(0);
}
1996-10-31 11:23:28 +01:00
#endif /* ultrix4 */
1996-10-31 11:23:28 +01:00
#if defined(alpha)
#include <fp_class.h>
static int isinf(x)
double x;
{
int fpclass = fp_class(x);
if (fpclass == FP_POS_INF)
return(1);
if (fpclass == FP_NEG_INF)
return(-1);
return(0);
}
1996-10-31 11:23:28 +01:00
#endif /* alpha */
1996-10-31 11:23:28 +01:00
#if defined(sparc_solaris) || defined(i386_solaris) || defined(svr4)
#include <ieeefp.h>
static int
isinf(d)
double d;
{
fpclass_t type = fpclass(d);
switch (type) {
case FP_SNAN:
case FP_QNAN:
case FP_NINF:
case FP_PINF:
return (1);
default:
break;
}
return (0);
}
1996-10-31 11:23:28 +01:00
#endif /* sparc_solaris */
1996-10-31 11:23:28 +01:00
#if defined(irix5)
#include <ieeefp.h>
static int
isinf(d)
double d;
{
fpclass_t type = fpclass(d);
switch (type) {
case FP_SNAN:
case FP_QNAN:
case FP_NINF:
case FP_PINF:
return (1);
default:
break;
}
return (0);
}
1996-10-31 11:23:28 +01:00
#endif /* irix5 */
#endif /* !HAVE_ISINF */