⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 float.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * float.c *	  Functions for the built-in floating-point types. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.115.2.1 2006/04/24 20:36:41 tgl 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>#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 M_PI/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */#define M_PI 3.14159265358979323846#endif#ifndef SHRT_MAX#define SHRT_MAX 32767#endif#ifndef SHRT_MIN#define SHRT_MIN (-32768)#endif/* Recent HPUXen have isfinite() macro in place of more standard finite() */#if !defined(HAVE_FINITE) && defined(isfinite)#define finite(x) isfinite(x)#define HAVE_FINITE 1#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);#ifndef HAVE_CBRTstatic double cbrt(double x);#endif   /* HAVE_CBRT *//* * Routines to provide reasonably platform-independent handling of * infinity and NaN.  We assume that isinf() and isnan() are available * and work per spec.  (On some platforms, we have to supply our own; * see src/port.)  However, generating an Infinity or NaN in the first * place is less well standardized; pre-C99 systems tend not to have C99's * INFINITY and NAN macros.  We centralize our workarounds for this here. */doubleget_float8_infinity(void){#ifdef INFINITY	/* C99 standard way */	return (double) INFINITY;#else	/*	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the	 * largest normal double.  We assume forcing an overflow will get us a	 * true infinity.	 */	return (double) (HUGE_VAL * HUGE_VAL);#endif}floatget_float4_infinity(void){#ifdef INFINITY	/* C99 standard way */	return (float) INFINITY;#else	/*	 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the	 * largest normal double.  We assume forcing an overflow will get us a	 * true infinity.	 */	return (float) (HUGE_VAL * HUGE_VAL);#endif}doubleget_float8_nan(void){#ifdef NAN	/* C99 standard way */	return (double) NAN;#else	/* Assume we can get a NAN via zero divide */	return (double) (0.0 / 0.0);#endif}floatget_float4_nan(void){#ifdef NAN	/* C99 standard way */	return (float) NAN;#else	/* Assume we can get a NAN via zero divide */	return (float) (0.0 / 0.0);#endif}/* * Returns -1 if 'val' represents negative infinity, 1 if 'val' * represents (positive) infinity, and 0 otherwise. On some platforms, * this is equivalent to the isinf() macro, but not everywhere: C99 * does not specify that isinf() needs to distinguish between positive * and negative infinity. */intis_infinite(double val){	int			inf = isinf(val);	if (inf == 0)		return 0;	if (val > 0)		return 1;	return -1;}/* * check to see if a float4 val is outside of the FLOAT4_MIN, * FLOAT4_MAX bounds. * * raise an ereport() error if it is */static voidCheckFloat4Val(double val){	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")));}/* * 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){	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")));}/* *		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);	char	   *orig_num;	double		val;	char	   *endptr;	/*	 * endptr points to the first character _after_ the sequence we recognized	 * as a valid floating point number. orig_num points to the original input	 * string.	 */	orig_num = num;	/*	 * Check for an empty-string input to begin with, to avoid the vagaries of	 * strtod() on different platforms.	 */	if (*num == '\0')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("invalid input syntax for type real: \"%s\"",						orig_num)));	/* skip leading whitespace */	while (*num != '\0' && isspace((unsigned char) *num))		num++;	errno = 0;	val = strtod(num, &endptr);	/* did we not see anything that looks like a double? */	if (endptr == num || errno != 0)	{		/*		 * C99 requires that strtod() accept NaN and [-]Infinity, but not all		 * platforms support that yet (and some accept them but set ERANGE		 * anyway...)  Therefore, we check for these inputs ourselves.		 */		if (pg_strncasecmp(num, "NaN", 3) == 0)		{			val = get_float4_nan();			endptr = num + 3;		}		else if (pg_strncasecmp(num, "Infinity", 8) == 0)		{			val = get_float4_infinity();			endptr = num + 8;		}		else if (pg_strncasecmp(num, "-Infinity", 9) == 0)		{			val = -get_float4_infinity();			endptr = num + 9;		}		else if (errno == ERANGE)			ereport(ERROR,					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),					 errmsg("\"%s\" is out of range for type real",							orig_num)));		else			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("invalid input syntax for type real: \"%s\"",							orig_num)));	}#ifdef HAVE_BUGGY_SOLARIS_STRTOD	else	{		/*		 * Many versions of Solaris have a bug wherein strtod sets endptr to		 * point one byte beyond the end of the string when given "inf" or		 * "infinity".		 */		if (endptr != num && endptr[-1] == '\0')			endptr--;	}#endif   /* HAVE_BUGGY_SOLARIS_STRTOD */	/* skip trailing whitespace */	while (*endptr != '\0' && isspace((unsigned char) *endptr))		endptr++;	/* if there is any junk left at the end of the string, bail out */	if (*endptr != '\0')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("invalid input syntax for type real: \"%s\"",						orig_num)));	/*	 * if we get here, we have a legal double, still need to check to see if	 * it's a legal float4	 */	if (!isinf(val))		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);	if (isnan(num))		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));	switch (is_infinite(num))	{		case 1:			strcpy(ascii, "Infinity");			break;		case -1:			strcpy(ascii, "-Infinity");			break;		default:			{				int			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);	char	   *orig_num;	double		val;	char	   *endptr;	/*	 * endptr points to the first character _after_ the sequence we recognized	 * as a valid floating point number. orig_num points to the original input	 * string.	 */	orig_num = num;	/*	 * Check for an empty-string input to begin with, to avoid the vagaries of	 * strtod() on different platforms.	 */	if (*num == '\0')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),			 errmsg("invalid input syntax for type double precision: \"%s\"",					orig_num)));	/* skip leading whitespace */	while (*num != '\0' && isspace((unsigned char) *num))		num++;	errno = 0;	val = strtod(num, &endptr);	/* did we not see anything that looks like a double? */	if (endptr == num || errno != 0)	{		/*		 * C99 requires that strtod() accept NaN and [-]Infinity, but not all		 * platforms support that yet (and some accept them but set ERANGE		 * anyway...)  Therefore, we check for these inputs ourselves.		 */		if (pg_strncasecmp(num, "NaN", 3) == 0)		{			val = get_float8_nan();			endptr = num + 3;		}		else if (pg_strncasecmp(num, "Infinity", 8) == 0)		{			val = get_float8_infinity();			endptr = num + 8;		}		else if (pg_strncasecmp(num, "-Infinity", 9) == 0)		{			val = -get_float8_infinity();			endptr = num + 9;		}		else if (errno == ERANGE)			ereport(ERROR,					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),				   errmsg("\"%s\" is out of range for type double precision",						  orig_num)));		else			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),			 errmsg("invalid input syntax for type double precision: \"%s\"",					orig_num)));	}#ifdef HAVE_BUGGY_SOLARIS_STRTOD	else	{		/*		 * Many versions of Solaris have a bug wherein strtod sets endptr to		 * point one byte beyond the end of the string when given "inf" or		 * "infinity".		 */		if (endptr != num && endptr[-1] == '\0')			endptr--;	}#endif   /* HAVE_BUGGY_SOLARIS_STRTOD */	/* skip trailing whitespace */	while (*endptr != '\0' && isspace((unsigned char) *endptr))		endptr++;	/* if there is any junk left at the end of the string, bail out */	if (*endptr != '\0')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),			 errmsg("invalid input syntax for type double precision: \"%s\"",					orig_num)));	if (!isinf(val))		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);	if (isnan(num))		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));	switch (is_infinite(num))	{		case 1:			strcpy(ascii, "Infinity");			break;		case -1:			strcpy(ascii, "-Infinity");			break;		default:			{				int			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) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -