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

📄 float.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * float.c *	  Functions for the built-in floating-point types. * * Portions Copyright (c) 1996-2008, 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.153 2008/01/01 19:45:52 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include <float.h>#include <math.h>#include <limits.h>#include "catalog/pg_type.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/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp */#if defined(WIN32) && !defined(NAN)static const uint32 nan[2] = {0xffffffff, 0x7fffffff};#define NAN (*(const double *) nan)#endif/* not sure what the following should be, but better to make it over-sufficient */#define MAXFLOATWIDTH	64#define MAXDOUBLEWIDTH	128/* * check to see if a float4/8 val has underflowed or overflowed */#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\do {															\	if (isinf(val) && !(inf_is_valid))							\		ereport(ERROR,											\				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\		  errmsg("value out of range: overflow")));				\																\	if ((val) == 0.0 && !(zero_is_valid))						\		ereport(ERROR,											\				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\		 errmsg("value out of range: underflow")));				\} while(0)/* ========== USER I/O ROUTINES ========== *//* Configurable GUC parameter */int			extra_float_digits = 0;		/* Added to DBL_DIG or FLT_DIG */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;	else if (val > 0)		return 1;	else		return -1;}/* *		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 */#ifdef HAVE_BUGGY_IRIX_STRTOD	/*	 * In some IRIX versions, strtod() recognizes only "inf", so if the input	 * is "infinity" we have to skip over "inity".	Also, it may return	 * positive infinity for "-inf".	 */	if (isinf(val))	{		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 (pg_strncasecmp(num, "-inf", 4) == 0)		{			val = -get_float4_infinity();			endptr = num + 4;		}	}#endif   /* HAVE_BUGGY_IRIX_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	 */	CHECKFLOATVAL((float4) val, isinf(val), val == 0);	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 */#ifdef HAVE_BUGGY_IRIX_STRTOD	/*	 * In some IRIX versions, strtod() recognizes only "inf", so if the input	 * is "infinity" we have to skip over "inity".	Also, it may return	 * positive infinity for "-inf".	 */	if (isinf(val))	{		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 (pg_strncasecmp(num, "-inf", 4) == 0)		{			val = -get_float8_infinity();			endptr = num + 4;		}	}#endif   /* HAVE_BUGGY_IRIX_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)));	CHECKFLOATVAL(val, true, true);	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) */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);	float4		result;	result = ((arg1 != 0) ? -(arg1) : arg1);	CHECKFLOATVAL(result, isinf(arg1), true);	PG_RETURN_FLOAT4(result);}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);	PG_RETURN_FLOAT8(fabs(arg1));}/* *		float8um		- returns -arg1 (unary minus) */Datumfloat8um(PG_FUNCTION_ARGS){	float8		arg1 = PG_GETARG_FLOAT8(0);	float8		result;	result = ((arg1 != 0) ? -(arg1) : arg1);	CHECKFLOATVAL(result, isinf(arg1), true);	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);}

⌨️ 快捷键说明

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