/*-------------------------------------------------------------------------
*
* float.c
* Functions for the built-in floating-point types.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.76 2001/10/28 06:25:52 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*----------
* OLD COMMENTS
* Basic float4 ops:
* float4in, float4out, float4abs, float4um, float4up
* Basic float8 ops:
* float8in, float8out, float8abs, float8um, float8up
* Arithmetic operators:
* float4pl, float4mi, float4mul, float4div
* float8pl, float8mi, float8mul, float8div
* Comparison operators:
* float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
* float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
* 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 invoking a separate
* conversion function...)
*
* 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 "postgres.h"
#include <ctype.h>
#include <errno.h>
#include <float.h> /* faked on sunos4 */
#include <math.h>
#include <limits.h>
/* for finite() on Solaris */
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#include "fmgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#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 /* HAVE_CBRT */
#ifndef HAVE_RINT
#define rint my_rint
static double rint(double x);
#else
extern double rint(double x);
#endif /* HAVE_RINT */
#endif /* NeXT check */
static void CheckFloat4Val(double val);
static void CheckFloat8Val(double val);
#ifndef M_PI
/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
#define M_PI 3.14159265358979323846
#endif
#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
/* ========== 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.
*/
Datum
float4in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
double val;
char *endptr;
errno = 0;
val = strtod(num, &endptr);
if (*endptr != '\0')
{
/*
* XXX we should accept "Infinity" and "-Infinity" too, but what
* are the correct values to assign? HUGE_VAL will provoke an
* error from CheckFloat4Val.
*/
if (strcasecmp(num, "NaN") == 0)
val = NAN;
else
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);
PG_RETURN_FLOAT4((float4) val);
}
/*
* float4out - converts a float4 number to a string
* using a standard output format
*/
Datum
float4out(PG_FUNCTION_ARGS)
{
float4 num = PG_GETARG_FLOAT4(0);
char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
int infflag;
if (isnan(num))
PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
infflag = isinf(num);
if (infflag > 0)
PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
if (infflag < 0)
PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
sprintf(ascii, "%.*g", FLT_DIG, num);
PG_RETURN_CSTRING(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.
*/
Datum
float8in(PG_FUNCTION_ARGS)
{
char *
|