📄 float.c
字号:
/*------------------------------------------------------------------------- * * float.c * Functions for the built-in floating-point types. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.42.2.1 1999/08/02 05:24:52 scrappy 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>#endif#include "fmgr.h"#include "utils/builtins.h"#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 atofextern double atof(const char *p);#endif#ifndef HAVE_CBRT#define cbrt my_cbrtstatic double cbrt(double x);#else#if !defined(nextstep)extern double cbrt(double x);#endif#endif#ifndef HAVE_RINT#define rint my_rintstatic double rint(double x);#elseextern 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/* * 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(linux) && defined(__alpha__) ) && !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 voidCheckFloat4Val(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*/voidCheckFloat8Val(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. */float32float4in(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. */float64float8in(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) */float32float4abs(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) */float32float4um(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;}float32float4larger(float32 arg1, float32 arg2){ float32 result; if (!arg1 || !arg2) return (float32) NULL; result = (float32) palloc(sizeof(float32data)); *result = ((*arg1 > *arg2) ? *arg1 : *arg2); return result;}float32float4smaller(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) */float64float8abs(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) */float64float8um(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;}float64float8larger(float64 arg1, float64 arg2){ float64 result; if (!arg1 || !arg2) return (float64) NULL; result = (float64) palloc(sizeof(float64data)); *result = ((*arg1 > *arg2) ? *arg1 : *arg2); return result;}float64float8smaller(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 */float32float4pl(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;}float32float4mi(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;}float32float4mul(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;}float32float4div(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 = *arg1 / *arg2; return result;}float32float4inc(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 */float64float8pl(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;}float64float8mi(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;}float64float8mul(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;}float64float8div(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;}float64float8inc(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 */boolfloat4eq(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 == *arg2;}boolfloat4ne(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 != *arg2;}boolfloat4lt(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 < *arg2;}boolfloat4le(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 <= *arg2;}boolfloat4gt(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 > *arg2;}boolfloat4ge(float32 arg1, float32 arg2){ if (!arg1 || !arg2) return 0; return *arg1 >= *arg2;}/* * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations */boolfloat8eq(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 == *arg2;}boolfloat8ne(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 != *arg2;}boolfloat8lt(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 < *arg2;}boolfloat8le(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 <= *arg2;}boolfloat8gt(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 > *arg2;}boolfloat8ge(float64 arg1, float64 arg2){ if (!arg1 || !arg2) return 0; return *arg1 >= *arg2;}/* * =================== * CONVERSION ROUTINES * =================== *//* * ftod - converts a float4 number to a float8 number */float64ftod(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 */float32dtof(float64 num){ float32 result; if (!num) return (float32) NULL; CheckFloat4Val(*num); result = (float32) palloc(sizeof(float32data)); *result = *num; return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -