📄 float.c
字号:
/*------------------------------------------------------------------------- * * float.c * Functions for the built-in floating-point types. * * Portions Copyright (c) 1996-2003, 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.94 2003/09/25 06:58:03 petere Exp $ * *------------------------------------------------------------------------- *//*---------- * OLD COMMENTS * Basic float4 ops: * float4in, float4out, float4recv, float4send * float4abs, float4um, float4up * Basic float8 ops: * float8in, float8out, float8recv, float8send * 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 "catalog/pg_type.h"#include "fmgr.h"#include "libpq/pqformat.h"#include "utils/array.h"#include "utils/builtins.h"#ifndef HAVE_CBRTstatic double cbrt(double x);#endif /* HAVE_CBRT */#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/* 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/* Configurable GUC parameter */int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */static void CheckFloat4Val(double val);static void CheckFloat8Val(double val);static int float4_cmp_internal(float4 a, float4 b);static int float8_cmp_internal(float8 a, float8 b);/* * check to see if a float4 val is outside of * the FLOAT4_MIN, FLOAT4_MAX bounds. * * raise an ereport 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) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"real\" value out of range: overflow"))); if (val != 0.0 && fabs(val) < FLOAT4_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"real\" value out of range: underflow"))); return;#endif /* UNSAFE_FLOATS */}/* * check to see if a float8 val is outside of * the FLOAT8_MIN, FLOAT8_MAX bounds. * * raise an ereport error if it is */static 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) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: overflow"))); if (val != 0.0 && fabs(val) < FLOAT8_MIN) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("type \"double precision\" value out of range: underflow")));#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. */Datumfloat4in(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 ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type real: \"%s\"", num))); } else { if (errno == ERANGE) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("\"%s\" is out of range for type real", 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 */Datumfloat4out(PG_FUNCTION_ARGS){ float4 num = PG_GETARG_FLOAT4(0); char *ascii = (char *) palloc(MAXFLOATWIDTH + 1); int infflag; int ndig; 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")); ndig = FLT_DIG + extra_float_digits; if (ndig < 1) ndig = 1; sprintf(ascii, "%.*g", ndig, num); PG_RETURN_CSTRING(ascii);}/* * float4recv - converts external binary format to float4 */Datumfloat4recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));}/* * float4send - converts float4 to binary format */Datumfloat4send(PG_FUNCTION_ARGS){ float4 num = PG_GETARG_FLOAT4(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendfloat4(&buf, num); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* * 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. */Datumfloat8in(PG_FUNCTION_ARGS){ char *num = PG_GETARG_CSTRING(0); 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 if (strcasecmp(num, "-Infinity") == 0) val = -HUGE_VAL; else ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type double precision: \"%s\"", num))); } else { if (errno == ERANGE) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("\"%s\" is out of range for type double precision", num))); } CheckFloat8Val(val); PG_RETURN_FLOAT8(val);}/* * float8out - converts float8 number to a string * using a standard output format */Datumfloat8out(PG_FUNCTION_ARGS){ float8 num = PG_GETARG_FLOAT8(0); char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1); int infflag; int ndig; 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")); ndig = DBL_DIG + extra_float_digits; if (ndig < 1) ndig = 1; sprintf(ascii, "%.*g", ndig, num); PG_RETURN_CSTRING(ascii);}/* * float8recv - converts external binary format to float8 */Datumfloat8recv(PG_FUNCTION_ARGS){ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));}/* * float8send - converts float8 to binary format */Datumfloat8send(PG_FUNCTION_ARGS){ float8 num = PG_GETARG_FLOAT8(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendfloat8(&buf, num); PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}/* ========== PUBLIC ROUTINES ========== *//* * ====================== * FLOAT4 BASE OPERATIONS * ====================== *//* * float4abs - returns |arg1| (absolute value) */Datumfloat4abs(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); PG_RETURN_FLOAT4((float4) fabs(arg1));}/* * float4um - returns -arg1 (unary minus) */Datumfloat4um(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); PG_RETURN_FLOAT4((float4) -arg1);}Datumfloat4up(PG_FUNCTION_ARGS){ float4 arg = PG_GETARG_FLOAT4(0); PG_RETURN_FLOAT4(arg);}Datumfloat4larger(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); float4 result; if (float4_cmp_internal(arg1, arg2) > 0) result = arg1; else result = arg2; PG_RETURN_FLOAT4(result);}Datumfloat4smaller(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); float4 result; if (float4_cmp_internal(arg1, arg2) < 0) result = arg1; else result = arg2; PG_RETURN_FLOAT4(result);}/* * ====================== * FLOAT8 BASE OPERATIONS * ====================== *//* * float8abs - returns |arg1| (absolute value) */Datumfloat8abs(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; result = fabs(arg1); CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}/* * float8um - returns -arg1 (unary minus) */Datumfloat8um(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 result; result = ((arg1 != 0) ? -(arg1) : arg1); CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}Datumfloat8up(PG_FUNCTION_ARGS){ float8 arg = PG_GETARG_FLOAT8(0); PG_RETURN_FLOAT8(arg);}Datumfloat8larger(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; if (float8_cmp_internal(arg1, arg2) > 0) result = arg1; else result = arg2; PG_RETURN_FLOAT8(result);}Datumfloat8smaller(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; if (float8_cmp_internal(arg1, arg2) < 0) result = arg1; else result = arg2; PG_RETURN_FLOAT8(result);}/* * ==================== * ARITHMETIC OPERATORS * ==================== *//* * float4pl - returns arg1 + arg2 * float4mi - returns arg1 - arg2 * float4mul - returns arg1 * arg2 * float4div - returns arg1 / arg2 */Datumfloat4pl(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 + arg2; CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result);}Datumfloat4mi(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 - arg2; CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result);}Datumfloat4mul(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); double result; result = arg1 * arg2; CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result);}Datumfloat4div(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); double result; if (arg2 == 0.0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); /* Do division in float8, then check for overflow */ result = (float8) arg1 / (float8) arg2; CheckFloat4Val(result); PG_RETURN_FLOAT4((float4) result);}/* * float8pl - returns arg1 + arg2 * float8mi - returns arg1 - arg2 * float8mul - returns arg1 * arg2 * float8div - returns arg1 / arg2 */Datumfloat8pl(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 + arg2; CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}Datumfloat8mi(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 - arg2; CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}Datumfloat8mul(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; result = arg1 * arg2; CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}Datumfloat8div(PG_FUNCTION_ARGS){ float8 arg1 = PG_GETARG_FLOAT8(0); float8 arg2 = PG_GETARG_FLOAT8(1); float8 result; if (arg2 == 0.0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); result = arg1 / arg2; CheckFloat8Val(result); PG_RETURN_FLOAT8(result);}/* * ==================== * COMPARISON OPERATORS * ==================== *//* * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations */static intfloat4_cmp_internal(float4 a, float4 b){ /* * We consider all NANs to be equal and larger than any non-NAN. This * is somewhat arbitrary; the important thing is to have a consistent * sort order. */ if (isnan(a)) { if (isnan(b)) return 0; /* NAN = NAN */ else return 1; /* NAN > non-NAN */ } else if (isnan(b)) { return -1; /* non-NAN < NAN */ } else { if (a > b) return 1; else if (a < b) return -1; else return 0; }}Datumfloat4eq(PG_FUNCTION_ARGS){ float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -