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

1970 lines
33 KiB
C

/*-------------------------------------------------------------------------
*
* float.c
* Functions for the built-in floating-point types.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.61 2000/06/14 18:17:42 petere 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, i4tod, dtoi4, 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 <ctype.h>
#include <errno.h>
#include <float.h> /* faked on sunos4 */
#include <math.h>
#include "postgres.h"
#ifdef HAVE_LIMITS_H
#include <limits.h>
#ifndef MAXINT
#define MAXINT INT_MAX
#endif
#else
#ifdef HAVE_VALUES_H
#include <values.h>
#endif
#endif
/* for finite() on Solaris */
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h>
#endif
#include "fmgr.h"
#include "utils/builtins.h"
static void CheckFloat8Val(double val);
#ifndef NAN
#define NAN (0.0/0.0)
#endif
#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
#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
/*
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(ERROR, "Bad float4 input format -- overflow");
if (val != 0.0 && fabs(val) < FLOAT4_MIN)
elog(ERROR, "Bad float4 input format -- underflow");
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
*/
static 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(ERROR, "Bad float8 input format -- overflow");
if (val != 0.0 && fabs(val) < FLOAT8_MIN)
elog(ERROR, "Bad float8 input format -- underflow");
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')
{
/* Should we accept "NaN" or "Infinity" for float4? */
elog(ERROR, "Bad float4 input format '%s'", num);
}
else
{
if (errno == ERANGE)
elog(ERROR, "Input '%s' is out of range for float4", num);
}
/*
* 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')
{
if (strcasecmp(num, "NaN") == 0)
val = NAN;
else if (strcasecmp(num, "Infinity") == 0)
val = HUGE_VAL;
else
elog(ERROR, "Bad float8 input format '%s'", num);
}
else
{
if (errno == ERANGE)
elog(ERROR, "Input '%s' is out of range for float8", num);
}
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(ERROR, "float4div: divide by zero error");
val = *arg1 / *arg2;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return result;
}
float32
float4inc(float32 arg1)
{
float32 result;
double val;
if (!arg1)
return (float32) NULL;
val = *arg1 + (float32data) 1.0;
CheckFloat4Val(val);
result = (float32) palloc(sizeof(float32data));
*result = val;
return result;
}
/*
* 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(ERROR, "float8div: divide by zero error");
val = *arg1 / *arg2;
CheckFloat8Val(val);
*result = val;
return result;
}
float64
float8inc(float64 arg1)
{
float64 result;
double val;
if (!arg1)
return (float64) NULL;
val = *arg1 + (float64data) 1.0;
CheckFloat8Val(val);
result = (float64) palloc(sizeof(float64data));
*result = val;
return result;
}
/*
* ====================
* 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;
}
/*
* dtoi4 - converts a float8 number to an int4 number
*/
int32
dtoi4(float64 num)
{
int32 result;
if (!num)
return 0; /* fmgr will return NULL anyway */
if ((*num < INT_MIN) || (*num > INT_MAX))
elog(ERROR, "dtoi4: integer out of range");
result = rint(*num);
return result;
}
/*
* dtoi2 - converts a float8 number to an int2 number
*/
Datum
dtoi2(PG_FUNCTION_ARGS)
{
float8 num = PG_GETARG_FLOAT8(0);
int16 result;
if ((num < SHRT_MIN) || (num > SHRT_MAX))
elog(ERROR, "dtoi2: integer out of range");
result = (int16) rint(num);
PG_RETURN_INT16(result);
}
/*
* i4tod - converts an int4 number to a float8 number
*/
Datum
i4tod(PG_FUNCTION_ARGS)
{
int32 num = PG_GETARG_INT32(0);
float8 result;
result = num;
PG_RETURN_FLOAT8(result);
}
/*
* i2tod - converts an int2 number to a float8 number
*/
Datum
i2tod(PG_FUNCTION_ARGS)
{
int16 num = PG_GETARG_INT16(0);
float8 result;
result = num;
PG_RETURN_FLOAT8(result);
}
/*
* ftoi4 - converts a float8 number to an int4 number
*/
int32
ftoi4(float32 num)
{
int32 result;
if (!num)
return 0; /* fmgr will return NULL anyway */
if ((*num < INT_MIN) || (*num > INT_MAX))
elog(ERROR, "ftoi4: integer out of range");
result = rint(*num);
return result;
}
/*
* ftoi2 - converts a float4 number to an int2 number
*/
Datum
ftoi2(PG_FUNCTION_ARGS)
{
float4 num = PG_GETARG_FLOAT4(0);
int16 result;
if ((num < SHRT_MIN) || (num > SHRT_MAX))
elog(ERROR, "ftoi2: integer out of range");
result = (int16) rint(num);
PG_RETURN_INT16(result);
}
/*
* i4tof - converts an int4 number to a float8 number
*/
Datum
i4tof(PG_FUNCTION_ARGS)
{
int32 num = PG_GETARG_INT32(0);
float4 result;
result = num;
PG_RETURN_FLOAT4(result);
}
/*
* i2tof - converts an int2 number to a float4 number
*/
Datum
i2tof(PG_FUNCTION_ARGS)
{
int16 num = PG_GETARG_INT16(0);
float4 result;
result = num;
PG_RETURN_FLOAT4(result);
}
/*
* float8_text - converts a float8 number to a text string
*/
text *
float8_text(float64 num)
{
text *result;
int len;
char *str;
str = float8out(num);
len = (strlen(str) + VARHDRSZ);
result = palloc(len);
VARSIZE(result) = len;
memmove(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
return result;
} /* float8_text() */
/*
* text_float8 - converts a text string to a float8 number
*/
float64
text_float8(text *string)
{
float64 result;
int len;
char *str;
len = (VARSIZE(string) - VARHDRSZ);
str = palloc(len + 1);
memmove(str, VARDATA(string), len);
*(str + len) = '\0';
result = float8in(str);
pfree(str);
return result;
} /* text_float8() */
/*
* float4_text - converts a float4 number to a text string
*/
text *
float4_text(float32 num)
{
text *result;
int len;
char *str;
str = float4out(num);
len = (strlen(str) + VARHDRSZ);
result = palloc(len);
VARSIZE(result) = len;
memmove(VARDATA(result), str, (len - VARHDRSZ));
pfree(str);
return result;
} /* float4_text() */
/*
* text_float4 - converts a text string to a float4 number
*/
float32
text_float4(text *string)
{
float32 result;
int len;
char *str;
len = (VARSIZE(string) - VARHDRSZ);
str = palloc(len + 1);
memmove(str, VARDATA(string), len);
*(str + len) = '\0';
result = float4in(str);
pfree(str);
return result;
} /* text_float4() */
/*
* =======================
* 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;
/*
* We must check both for errno getting set and for a NaN result, in
* order to deal with the vagaries of different platforms...
*/
errno = 0;
*result = (float64data) pow(tmp1, tmp2);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "pow() result is out of range");
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;
/*
* We must check both for errno getting set and for a NaN result, in
* order to deal with the vagaries of different platforms. Also, a
* zero result implies unreported underflow.
*/
errno = 0;
*result = (float64data) exp(tmp);
if (errno != 0 || *result == 0.0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "exp() result is out of range");
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 (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
if (tmp == 0.0)
elog(ERROR, "can't take log of zero");
if (tmp < 0)
elog(ERROR, "can't take log of a negative number");
*result = (float64data) log(tmp);
CheckFloat8Val(*result);
return result;
} /* dlog1() */
/*
* dlog10 - returns a pointer to the base 10 logarithm of arg1
*/
float64
dlog10(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
if (tmp == 0.0)
elog(ERROR, "can't take log of zero");
if (tmp < 0)
elog(ERROR, "can't take log of a negative number");
*result = (float64data) log10(tmp);
CheckFloat8Val(*result);
return result;
} /* dlog10() */
/*
* dacos - returns a pointer to the arccos of arg1 (radians)
*/
float64
dacos(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) acos(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dacos(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* dacos() */
/*
* dasin - returns a pointer to the arcsin of arg1 (radians)
*/
float64
dasin(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) asin(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dasin(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* dasin() */
/*
* datan - returns a pointer to the arctan of arg1 (radians)
*/
float64
datan(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) atan(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "atan(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* datan() */
/*
* atan2 - returns a pointer to the arctan2 of arg1 (radians)
*/
float64
datan2(float64 arg1, float64 arg2)
{
float64 result;
if (!PointerIsValid(arg1) || !PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
errno = 0;
*result = (float64data) atan2(*arg1, *arg2);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "atan2(%f,%f) input is out of range", *arg1, *arg2);
CheckFloat8Val(*result);
return result;
} /* datan2() */
/*
* dcos - returns a pointer to the cosine of arg1 (radians)
*/
float64
dcos(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) cos(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dcos(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* dcos() */
/*
* dcot - returns a pointer to the cotangent of arg1 (radians)
*/
float64
dcot(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) tan(tmp);
if ((errno != 0) || (*result == 0.0)
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dcot(%f) input is out of range", *arg1);
*result = 1.0 / (*result);
CheckFloat8Val(*result);
return result;
} /* dcot() */
/*
* dsin - returns a pointer to the sine of arg1 (radians)
*/
float64
dsin(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) sin(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dsin(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* dsin() */
/*
* dtan - returns a pointer to the tangent of arg1 (radians)
*/
float64
dtan(float64 arg1)
{
float64 result;
double tmp;
if (!PointerIsValid(arg1))
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
tmp = *arg1;
errno = 0;
*result = (float64data) tan(tmp);
if (errno != 0
#ifdef HAVE_FINITE
|| !finite(*result)
#endif
)
elog(ERROR, "dtan(%f) input is out of range", *arg1);
CheckFloat8Val(*result);
return result;
} /* dtan() */
#ifndef M_PI
/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
#define M_PI 3.14159265358979323846
#endif
/*
* degrees - returns a pointer to degrees converted from radians
*/
float64
degrees(float64 arg1)
{
float64 result;
if (!arg1)
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
*result = ((*arg1) * (180.0 / M_PI));
CheckFloat8Val(*result);
return result;
} /* degrees() */
/*
* dpi - returns a pointer to degrees converted to radians
*/
float64
dpi(void)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = (M_PI);
return result;
} /* dpi() */
/*
* radians - returns a pointer to radians converted from degrees
*/
float64
radians(float64 arg1)
{
float64 result;
if (!arg1)
return (float64) NULL;
result = (float64) palloc(sizeof(float64data));
*result = ((*arg1) * (M_PI / 180.0));
CheckFloat8Val(*result);
return result;
} /* radians() */
/*
* drandom - returns a random number
*/
float64
drandom(void)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
/* result 0.0-1.0 */
*result = (((double) random()) / RAND_MAX);
CheckFloat8Val(*result);
return result;
} /* drandom() */
/*
* setseed - set seed for the random number generator
*/
int32
setseed(float64 seed)
{
int iseed = ((*seed) * RAND_MAX);
srandom((unsigned int) ((*seed) * RAND_MAX));
return iseed;
} /* setseed() */
/*
* ====================
* 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(ERROR, "float48div: divide by zero");
*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(ERROR, "float48div: divide by zero");
*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 == *arg2;
}
bool
float48ne(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 != *arg2;
}
bool
float48lt(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 < *arg2;
}
bool
float48le(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 <= *arg2;
}
bool
float48gt(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 > *arg2;
}
bool
float48ge(float32 arg1, float64 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 >= *arg2;
}
/*
* float84{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
*/
bool
float84eq(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 == *arg2;
}
bool
float84ne(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 != *arg2;
}
bool
float84lt(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 < *arg2;
}
bool
float84le(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 <= *arg2;
}
bool
float84gt(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *arg1 > *arg2;
}
bool
float84ge(float64 arg1, float32 arg2)
{
if (!arg1 || !arg2)
return 0;
return *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 */