pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feedRe: [BUGS] BUG #2846: inconsistent and confusing
10+ messages / 4 participants
[nested] [flat]
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-27 21:35 Bruce Momjian <bruce@momjian.us>
0 siblings, 1 reply; 10+ messages in thread
From: Bruce Momjian @ 2006-12-27 21:35 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
Tom Lane wrote:
> Bruce Momjian <bruce@momjian.us> writes:
> > I have made some more progress on this patch.
>
> I'm not convinced that you're fixing things so much as doing your best
> to destroy IEEE-compliant float arithmetic behavior.
>
> I think what we should probably consider is removing CheckFloat4Val
> and CheckFloat8Val altogether, and just letting the float arithmetic
> have its head. Most modern hardware gets float arithmetic right per
> spec, and we shouldn't be second-guessing it.
Well, I am on an Xeon and can confirm that our computations of large
non-infinite doubles who's result greatly exceed the max double are
indeed returning infinity, as the poster reported, so something isn't
working, if it supposed to. What do people get for this computation?
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
double a = 1e300, b = 1e300;
double c;
c = a * b;
printf("%e\n", c);
return 0;
}
I get 'inf'. I am on BSD and just tested it on Fedora Core 2 and got
'inf' too.
> A slightly less radical proposal is to reject only the case where
> isinf(result) and neither input isinf(); and perhaps likewise with
> respect to NaNs.
Uh, that's what the patch does for 'Inf':
result = arg1 + arg2;
CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
I didn't touch 'Nan' because that is passed around as a value just fine
--- it isn't created or tested as part of an overflow.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-27 21:43 Joshua D. Drake <jd@commandprompt.com>
parent: Bruce Momjian <bruce@momjian.us>
0 siblings, 0 replies; 10+ messages in thread
From: Joshua D. Drake @ 2006-12-27 21:43 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
> I get 'inf'. I am on BSD and just tested it on Fedora Core 2 and got
> 'inf' too.
Ubuntu Edgy 64bit on Athlon 64X2 returns inf.
Joshua D. Drake
>
> > A slightly less radical proposal is to reject only the case where
> > isinf(result) and neither input isinf(); and perhaps likewise with
> > respect to NaNs.
>
> Uh, that's what the patch does for 'Inf':
>
> result = arg1 + arg2;
> CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
>
> I didn't touch 'Nan' because that is passed around as a value just fine
> --- it isn't created or tested as part of an overflow.
>
--
=== The PostgreSQL Company: Command Prompt, Inc. ===
Sales/Support: +1.503.667.4564 || 24x7/Emergency: +1.800.492.2240
Providing the most comprehensive PostgreSQL solutions since 1997
http://www.commandprompt.com/
Donate to the PostgreSQL Project: http://www.postgresql.org/about/donate
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-28 01:41 Bruce Momjian <bruce@momjian.us>
0 siblings, 0 replies; 10+ messages in thread
From: Bruce Momjian @ 2006-12-28 01:41 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-hackers@postgresql.org, Roman Kononov <kononov195-pgsql@yahoo.com>; PostgreSQL-patches <pgsql-patches@postgresql.org>
Tom Lane wrote:
> Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> > In float4mul() and float4div(), the computation should be double precision.
>
> Why? It's going to have to fit in a float4 eventually anyway.
One issue is in the patch comment:
! * Computations that slightly exceed FLOAT8_MAX are non-Infinity,
! * but those that greatly exceed FLOAT8_MAX become Infinity. Therefore
! * it is difficult to tell if a value is really infinity or the result
! * of an overflow. The solution is to use a boolean indicating if
! * the input arguments were infiity, meaning an infinite result is
! * probably not the result of an overflow. This allows various
! * computations like SELECT 'Inf'::float8 + 5.
+ * Underflow has similar issues to overflow, i.e. if a computation is
+ * slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is
+ * much smaller than FLOAT8_MIN, the value becomes zero. However,
+ * unlike overflow, zero is not a special value and can be the result
+ * of a computation, so there is no easy way to pass a boolean
+ * indicating whether a zero result is reasonable or not. It might
+ * be possible for multiplication and division, but because of rounding,
+ * such tests would probably not be reliable.
For overflow, it doesn't matter, but by using float8, you have a much
larger range until you underflow to zero. I will make adjustments to
the patch to use this, and add comments explaining its purpose.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-28 01:42 Bruce Momjian <bruce@momjian.us>
0 siblings, 0 replies; 10+ messages in thread
From: Bruce Momjian @ 2006-12-28 01:42 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-hackers@postgresql.org, Roman Kononov <kononov195-pgsql@yahoo.com>; PostgreSQL-patches <pgsql-patches@postgresql.org>
Tom Lane wrote:
> Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> > On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> >> Are you sure? As I remember, computation automatically upgrades to
> >> 'double'. See this program and output:
>
> > This is platform- and compiler- dependent:
>
> ... and probably irrelevant, too. We should store the result into a
> float4 variable and then test for isinf() on that; that eliminates the
> question of whether the compiler did the multiply in a wider format or
> not.
True for overflow to Infinity, but underflow checking is better for
float4 using float8. See previous email for details.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-28 01:45 Bruce Momjian <bruce@momjian.us>
0 siblings, 0 replies; 10+ messages in thread
From: Bruce Momjian @ 2006-12-28 01:45 UTC (permalink / raw)
To: Roman Kononov <kononov195-pgsql@yahoo.com>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>
Roman Kononov wrote:
> On 12/27/2006 05:19 PM, Tom Lane wrote:
> > Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> >> On 12/27/2006 03:23 PM, Bruce Momjian wrote:
> >>> Are you sure? As I remember, computation automatically upgrades to
> >>> 'double'. See this program and output:
> >
> >> This is platform- and compiler- dependent:
> >
> > ... and probably irrelevant, too. We should store the result into a
> > float4 variable and then test for isinf() on that; that eliminates the
> > question of whether the compiler did the multiply in a wider format or
> > not.
>
> You are right provided that you want to ignore underflows and silently
> produce zeros instead.
>
> If you go this way, I recommend to ignore overflows as well, and silently
> produce infinities and NaNs.
While IEEE seems fine with that, I don't think this is good for SQL. It
is best to produce a meaningful error. The major issue is that our
current code is buggy because it doesn't have consistent behavior, as
Roman outlined.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-28 20:33 Bruce Momjian <bruce@momjian.us>
0 siblings, 1 reply; 10+ messages in thread
From: Bruce Momjian @ 2006-12-28 20:33 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
Tom Lane wrote:
> No, because you are still comparing against FLOAT4_MAX. I'm suggesting
> that only an actual infinity should be rejected. Even that is contrary
> to IEEE spec, though.
>
> The other problem with this coding technique is that it must invoke
> isinf three times when the typical case really only requires one (if the
> output isn't inf there is no need to perform isinf on the inputs).
> If we're going to check for overflow at all, I think we should lose the
> subroutine and just do
>
> if (isinf(result) &&
> !(isinf(arg1) || isinf(arg2)))
> ereport(...OVERFLOW...);
I wasn't excited about doing one isinf() call to avoid three, so I just
made a fast isinf() macro:
/* We call isinf() a lot, so we use a fast version in this file */
#define fast_isinf(val) (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val))
and used that instead of the direct isinf() call. (We do call fabs() in
the Check* routines. Should we be using our own Abs()?) The new patch
also uses float8 for float4 computations, and adds a comment about why
(avoid underflow in some cases).
In looking at the idea of checking for zero as an underflow, I found
most transcendental functions already had such a check, so I moved the check
into the Check*() routines, and added checks for multiplication/division
underflow to zero. The only outstanding uncaught underflow is from
addition/subtraction.
--
Bruce Momjian bruce@momjian.us
EnterpriseDB http://www.enterprisedb.com
+ If your life is a hard drive, Christ can be your backup. +
Attachments:
/pgpatches/float (text/x-diff, 35.7K) download
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/float.c,v
retrieving revision 1.131
diff -c -c -r1.131 float.c
*** src/backend/utils/adt/float.c 23 Dec 2006 02:13:24 -0000 1.131
--- src/backend/utils/adt/float.c 28 Dec 2006 20:32:32 -0000
***************
*** 87,92 ****
--- 87,95 ----
#define NAN (*(const double *) nan)
#endif
+ /* We call isinf() a lot, so we use a fast version in this file */
+ #define fast_isinf(val) (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val))
+
/* not sure what the following should be, but better to make it over-sufficient */
#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
***************
*** 104,111 ****
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);
--- 107,114 ----
int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
! static void CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid);
! static void CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid);
static int float4_cmp_internal(float4 a, float4 b);
static int float8_cmp_internal(float8 a, float8 b);
***************
*** 211,219 ****
* raise an ereport() error if it is
*/
static void
! CheckFloat4Val(double val)
{
! if (fabs(val) > FLOAT4_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"real\" value out of range: overflow")));
--- 214,223 ----
* raise an ereport() error if it is
*/
static void
! CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid)
{
! /* If one of the input arguments was infinity, allow an infinite result */
! if (fabs(val) > FLOAT4_MAX && (!fast_isinf(val) || !has_inf_args))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"real\" value out of range: overflow")));
***************
*** 230,242 ****
* raise an ereport() error if it is
*/
static void
! CheckFloat8Val(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")));
--- 234,263 ----
* raise an ereport() error if it is
*/
static void
! CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid)
{
! /*
! * Computations that slightly exceed FLOAT8_MAX are non-Infinity,
! * but those that greatly exceed FLOAT8_MAX become Infinity. Therefore
! * it is difficult to tell if a value is really infinity or the result
! * of an overflow. The solution is to use a boolean indicating if
! * the input arguments were infiity, meaning an infinite result is
! * probably not the result of an overflow. This allows various
! * computations like SELECT 'Inf'::float8 + 5.
! */
! if (fabs(val) > FLOAT8_MAX && (!fast_isinf(val) || !has_inf_args))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"double precision\" value out of range: overflow")));
! /*
! * Underflow has similar issues to overflow, i.e. if a computation is
! * slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is
! * much smaller than FLOAT8_MIN, the value becomes zero. However,
! * unlike overflow, zero is not a special value and can be the result
! * of a computation, so we pass in a boolean indicating if zero is
! * a valid result.
! */
! if ((val != 0.0 && fabs(val) < FLOAT8_MIN) || (val == 0 && !zero_is_valid))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"double precision\" value out of range: underflow")));
***************
*** 334,340 ****
* 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)
{
--- 355,361 ----
* input is "infinity" we have to skip over "inity". Also, it may
* return positive infinity for "-inf".
*/
! if (fast_isinf(val))
{
if (pg_strncasecmp(num, "Infinity", 8) == 0)
{
***************
*** 369,376 ****
* 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);
}
--- 390,396 ----
* if we get here, we have a legal double, still need to check to see if
* it's a legal float4
*/
! CheckFloat4Val(val, true, true);
PG_RETURN_FLOAT4((float4) val);
}
***************
*** 527,533 ****
* 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)
{
--- 547,553 ----
* input is "infinity" we have to skip over "inity". Also, it may
* return positive infinity for "-inf".
*/
! if (fast_isinf(val))
{
if (pg_strncasecmp(num, "Infinity", 8) == 0)
{
***************
*** 558,565 ****
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
! if (!isinf(val))
! CheckFloat8Val(val);
PG_RETURN_FLOAT8(val);
}
--- 578,584 ----
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
! CheckFloat8Val(val, true, true);
PG_RETURN_FLOAT8(val);
}
***************
*** 652,659 ****
float4um(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
! PG_RETURN_FLOAT4((float4) -arg1);
}
Datum
--- 671,682 ----
float4um(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
+ float4 result;
+
+ result = ((arg1 != 0) ? -(arg1) : arg1);
! CheckFloat4Val(result, fast_isinf(arg1), true);
! PG_RETURN_FLOAT4(result);
}
Datum
***************
*** 705,716 ****
float8abs(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
- float8 result;
! result = fabs(arg1);
!
! CheckFloat8Val(result);
! PG_RETURN_FLOAT8(result);
}
--- 728,735 ----
float8abs(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! PG_RETURN_FLOAT8(fabs(arg1));
}
***************
*** 725,731 ****
result = ((arg1 != 0) ? -(arg1) : arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 744,750 ----
result = ((arg1 != 0) ? -(arg1) : arg1);
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 781,824 ****
Datum
float4pl(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);
}
Datum
float4mi(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);
}
Datum
float4mul(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);
}
Datum
float4div(PG_FUNCTION_ARGS)
{
! float4 arg1 = PG_GETARG_FLOAT4(0);
! float4 arg2 = PG_GETARG_FLOAT4(1);
double result;
if (arg2 == 0.0)
--- 800,849 ----
Datum
float4pl(PG_FUNCTION_ARGS)
{
! /*
! * Use float8 so that we have a larger underflow range.
! * Some compilers do not promote float to double in
! * computations.
! */
! float8 arg1 = PG_GETARG_FLOAT4(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
double result;
result = arg1 + arg2;
! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT4((float4) result);
}
Datum
float4mi(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
double result;
result = arg1 - arg2;
! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT4((float4) result);
}
Datum
float4mul(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
double result;
result = arg1 * arg2;
! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2),
! arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT4((float4) result);
}
Datum
float4div(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
double result;
if (arg2 == 0.0)
***************
*** 827,835 ****
errmsg("division by zero")));
/* Do division in float8, then check for overflow */
! result = (float8) arg1 / (float8) arg2;
! CheckFloat4Val(result);
PG_RETURN_FLOAT4((float4) result);
}
--- 852,860 ----
errmsg("division by zero")));
/* Do division in float8, then check for overflow */
! result = arg1 / arg2;
! CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT4((float4) result);
}
***************
*** 848,854 ****
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 873,879 ----
result = arg1 + arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 861,867 ****
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 886,892 ----
result = arg1 - arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 874,880 ****
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 899,906 ----
result = arg1 * arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2),
! arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 892,898 ****
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 918,924 ----
result = arg1 / arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1142,1148 ****
{
float8 num = PG_GETARG_FLOAT8(0);
! CheckFloat4Val(num);
PG_RETURN_FLOAT4((float4) num);
}
--- 1168,1174 ----
{
float8 num = PG_GETARG_FLOAT8(0);
! CheckFloat4Val(num, fast_isinf(num), true);
PG_RETURN_FLOAT4((float4) num);
}
***************
*** 1157,1163 ****
float8 num = PG_GETARG_FLOAT8(0);
int32 result;
! if (num < INT_MIN || num > INT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
--- 1183,1190 ----
float8 num = PG_GETARG_FLOAT8(0);
int32 result;
! /* 'Inf' is handled by INT_MAX */
! if (num < INT_MIN || num > INT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
***************
*** 1176,1182 ****
float8 num = PG_GETARG_FLOAT8(0);
int16 result;
! if (num < SHRT_MIN || num > SHRT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
--- 1203,1209 ----
float8 num = PG_GETARG_FLOAT8(0);
int16 result;
! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
***************
*** 1223,1229 ****
float4 num = PG_GETARG_FLOAT4(0);
int32 result;
! if (num < INT_MIN || num > INT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
--- 1250,1256 ----
float4 num = PG_GETARG_FLOAT4(0);
int32 result;
! if (num < INT_MIN || num > INT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
***************
*** 1242,1248 ****
float4 num = PG_GETARG_FLOAT4(0);
int16 result;
! if (num < SHRT_MIN || num > SHRT_MAX)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
--- 1269,1275 ----
float4 num = PG_GETARG_FLOAT4(0);
int16 result;
! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
***************
*** 1485,1491 ****
result = sqrt(arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1512,1518 ----
result = sqrt(arg1);
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1500,1505 ****
--- 1527,1533 ----
float8 result;
result = cbrt(arg1);
+ CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1539,1545 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1567,1573 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1555,1575 ****
/*
* We must check both for errno getting set and for a NaN result, in order
! * to deal with the vagaries of different platforms. Also, a zero result
! * implies unreported underflow.
*/
errno = 0;
result = exp(arg1);
! if (errno != 0 || result == 0.0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1583,1598 ----
/*
* We must check both for errno getting set and for a NaN result, in order
! * to deal with the vagaries of different platforms.
*/
errno = 0;
result = exp(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), false);
PG_RETURN_FLOAT8(result);
}
***************
*** 1598,1604 ****
result = log(arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1621,1627 ----
result = log(arg1);
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
***************
*** 1628,1634 ****
result = log10(arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1651,1657 ----
result = log10(arg1);
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
***************
*** 1644,1659 ****
errno = 0;
result = acos(arg1);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1667,1678 ----
errno = 0;
result = acos(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 1669,1684 ****
errno = 0;
result = asin(arg1);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1688,1699 ----
errno = 0;
result = asin(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 1694,1709 ****
errno = 0;
result = atan(arg1);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1709,1720 ----
errno = 0;
result = atan(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1720,1735 ****
errno = 0;
result = atan2(arg1, arg2);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1731,1742 ----
errno = 0;
result = atan2(arg1, arg2);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg2 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1745,1760 ****
errno = 0;
result = cos(arg1);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1752,1763 ----
errno = 0;
result = cos(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 1770,1786 ****
errno = 0;
result = tan(arg1);
! if (errno != 0 || result == 0.0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
result = 1.0 / result;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1773,1785 ----
errno = 0;
result = tan(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
result = 1.0 / result;
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 1796,1811 ****
errno = 0;
result = sin(arg1);
! if (errno != 0
! #ifdef HAVE_FINITE
! || !finite(result)
! #endif
! )
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1795,1806 ----
errno = 0;
result = sin(arg1);
! if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 1830,1836 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1825,1831 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1846,1852 ****
result = arg1 * (180.0 / M_PI);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1841,1847 ----
result = arg1 * (180.0 / M_PI);
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1872,1878 ****
result = arg1 * (M_PI / 180.0);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1867,1873 ----
result = arg1 * (M_PI / 180.0);
! CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 1963,1970 ****
N += 1.0;
sumX += newval;
sumX2 += newval * newval;
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 1958,1967 ----
N += 1.0;
sumX += newval;
+ CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true);
sumX2 += newval * newval;
! CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true);
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 1999,2023 ****
float4_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! float4 newval4 = PG_GETARG_FLOAT4(1);
float8 *transvalues;
float8 N,
sumX,
! sumX2,
! newval;
transvalues = check_float8_array(transarray, "float4_accum", 3);
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
- /* Do arithmetic in float8 for best accuracy */
- newval = newval4;
-
N += 1.0;
sumX += newval;
sumX2 += newval * newval;
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 1996,2023 ----
float4_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
! /*
! * Use float8 so that we have a larger underflow range.
! * Some compilers do not promote float to double in
! * computations.
! */
! float8 newval = PG_GETARG_FLOAT4(1);
float8 *transvalues;
float8 N,
sumX,
! sumX2;
transvalues = check_float8_array(transarray, "float4_accum", 3);
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
N += 1.0;
sumX += newval;
+ CheckFloat4Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true);
sumX2 += newval * newval;
! CheckFloat4Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true);
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 2088,2093 ****
--- 2088,2094 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2116,2121 ****
--- 2117,2123 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2144,2149 ****
--- 2146,2152 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2172,2177 ****
--- 2175,2181 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2220,2230 ****
N += 1.0;
sumX += newvalX;
sumX2 += newvalX * newvalX;
sumY += newvalY;
sumY2 += newvalY * newvalY;
sumXY += newvalX * newvalY;
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 2224,2240 ----
N += 1.0;
sumX += newvalX;
+ CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newvalX), true);
sumX2 += newvalX * newvalX;
+ CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newvalX), true);
sumY += newvalY;
+ CheckFloat8Val(sumY, fast_isinf(transvalues[3]) || fast_isinf(newvalY), true);
sumY2 += newvalY * newvalY;
+ CheckFloat8Val(sumY2, fast_isinf(transvalues[4]) || fast_isinf(newvalY), true);
sumXY += newvalX * newvalY;
! CheckFloat8Val(sumXY, fast_isinf(transvalues[5]) || fast_isinf(newvalX) ||
! fast_isinf(newvalY), true);
!
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 2282,2287 ****
--- 2292,2298 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2310,2315 ****
--- 2321,2327 ----
PG_RETURN_NULL();
numerator = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numerator, fast_isinf(sumY2) || fast_isinf(sumY), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2340,2345 ****
--- 2352,2359 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
/* A negative result is valid here */
***************
*** 2406,2411 ****
--- 2420,2427 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
PG_RETURN_FLOAT8(numerator / (N * N));
}
***************
*** 2432,2437 ****
--- 2448,2455 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
}
***************
*** 2464,2471 ****
--- 2482,2493 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
numeratorY = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
if (numeratorX <= 0 || numeratorY <= 0)
PG_RETURN_NULL();
***************
*** 2501,2508 ****
--- 2523,2534 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
numeratorY = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
/* per spec, horizontal line produces 1.0 */
***************
*** 2538,2544 ****
--- 2564,2573 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+ fast_isinf(sumY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
***************
*** 2570,2576 ****
--- 2599,2608 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
numeratorXXY = sumY * sumX2 - sumX * sumXY;
+ CheckFloat8Val(numeratorXXY, fast_isinf(sumY) || fast_isinf(sumX2) ||
+ fast_isinf(sumX) || fast_isinf(sumXY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
***************
*** 2593,2635 ****
Datum
float48pl(PG_FUNCTION_ARGS)
{
! float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
Datum
float48mi(PG_FUNCTION_ARGS)
{
! float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
Datum
float48mul(PG_FUNCTION_ARGS)
{
! float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
Datum
float48div(PG_FUNCTION_ARGS)
{
! float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
--- 2625,2673 ----
Datum
float48pl(PG_FUNCTION_ARGS)
{
! /*
! * Use float8 so that we have a larger underflow range.
! * Some compilers do not promote float to double in
! * computations.
! */
! float8 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
Datum
float48mi(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
Datum
float48mul(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2),
! arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
Datum
float48div(PG_FUNCTION_ARGS)
{
! float8 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
***************
*** 2639,2645 ****
errmsg("division by zero")));
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2677,2683 ----
errmsg("division by zero")));
result = arg1 / arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 2653,2664 ****
float84pl(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float4 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2691,2702 ----
float84pl(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 2666,2677 ****
float84mi(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float4 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2704,2715 ----
float84mi(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
***************
*** 2679,2690 ****
float84mul(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float4 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2717,2729 ----
float84mul(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2),
! arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
***************
*** 2692,2698 ****
float84div(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float4 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
if (arg2 == 0.0)
--- 2731,2737 ----
float84div(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
! float8 arg2 = PG_GETARG_FLOAT4(1);
float8 result;
if (arg2 == 0.0)
***************
*** 2702,2708 ****
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2741,2747 ----
result = arg1 / arg2;
! CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
Index: src/backend/utils/adt/int.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/int.c,v
retrieving revision 1.75
diff -c -c -r1.75 int.c
*** src/backend/utils/adt/int.c 4 Oct 2006 00:29:59 -0000 1.75
--- src/backend/utils/adt/int.c 28 Dec 2006 20:32:33 -0000
***************
*** 1124,1129 ****
--- 1124,1134 ----
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
+
+ /* SELECT ((-2147483648)::int4) % (-1); causes a floating point exception */
+ if (arg1 == INT_MIN && arg2 == -1)
+ PG_RETURN_INT32(0);
+
/* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2);
Index: src/test/regress/expected/float4.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/float4.out,v
retrieving revision 1.13
diff -c -c -r1.13 float4.out
*** src/test/regress/expected/float4.out 7 Apr 2005 01:51:40 -0000 1.13
--- src/test/regress/expected/float4.out 28 Dec 2006 20:32:35 -0000
***************
*** 72,78 ****
SELECT ' INFINITY x'::float4;
ERROR: invalid input syntax for type real: " INFINITY x"
SELECT 'Infinity'::float4 + 100.0;
! ERROR: type "double precision" value out of range: overflow
SELECT 'Infinity'::float4 / 'Infinity'::float4;
?column?
----------
--- 72,82 ----
SELECT ' INFINITY x'::float4;
ERROR: invalid input syntax for type real: " INFINITY x"
SELECT 'Infinity'::float4 + 100.0;
! ?column?
! ----------
! Infinity
! (1 row)
!
SELECT 'Infinity'::float4 / 'Infinity'::float4;
?column?
----------
Index: src/test/regress/expected/float8.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/float8.out,v
retrieving revision 1.24
diff -c -c -r1.24 float8.out
*** src/test/regress/expected/float8.out 8 Jun 2005 21:15:29 -0000 1.24
--- src/test/regress/expected/float8.out 28 Dec 2006 20:32:35 -0000
***************
*** 72,78 ****
SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0;
! ERROR: type "double precision" value out of range: overflow
SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column?
----------
--- 72,82 ----
SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0;
! ?column?
! ----------
! Infinity
! (1 row)
!
SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column?
----------
***************
*** 350,356 ****
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
! ERROR: result is out of range
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL;
--- 354,360 ----
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
! ERROR: type "double precision" value out of range: underflow
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL;
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-29 05:20 Tom Lane <tgl@sss.pgh.pa.us>
parent: Bruce Momjian <bruce@momjian.us>
0 siblings, 0 replies; 10+ messages in thread
From: Tom Lane @ 2006-12-29 05:20 UTC (permalink / raw)
To: pgsql-hackers@postgresql.org, Bruce Momjian <bruce@momjian.us>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
Bruce Momjian <bruce@momjian.us> writes:
> I wasn't excited about doing one isinf() call to avoid three, so I just
> made a fast isinf() macro:
> /* We call isinf() a lot, so we use a fast version in this file */
> #define fast_isinf(val) (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val))
This is *not* going in the right direction :-(
regards, tom lane
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [HACKERS] [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-29 17:11 Roman Kononov <kononov195-pgsql@yahoo.com>
0 siblings, 1 reply; 10+ messages in thread
From: Roman Kononov @ 2006-12-29 17:11 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
On 12/29/2006 12:23 AM, Bruce Momjian wrote:
> Well, then show me what direction you think is better.
Think about this idea please. This has no INF, NaN or range
checks and detects all "bad" cases with any floating point
math.
The only issue is that a bad case is detected only once.
You need to restart the postmaster. It can be fixed by
re-enabling FP exceptions in the FP exception handler.
Roman
-----------------------------
~/postgresql-8.2.0/src/backend/utils/adt>diff -U3 -p float.orig.c float.c
inline patch 1: float.c (+18/-20 lines) download inline-1.patch
--- float.orig.c 2006-12-29 10:49:51.000000000 -0600
+++ float.c 2006-12-29 10:58:19.000000000 -0600
@@ -60,12 +60,21 @@
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
+#include <fenv.h>
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
+static void __attribute__((__constructor__))
+enable_fp_exceptions()
+{
+ feclearexcept(FE_ALL_EXCEPT);
+ feenableexcept(FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);
+ printf("FP exceptions enabled\n");
+}
+
#ifndef M_PI
/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
@@ -783,11 +792,10 @@ float4pl(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
result = arg1 + arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ PG_RETURN_FLOAT4(result);
}
Datum
@@ -795,11 +803,10 @@ float4mi(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
result = arg1 - arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ PG_RETURN_FLOAT4(result);
}
Datum
@@ -807,11 +814,10 @@ float4mul(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
result = arg1 * arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ PG_RETURN_FLOAT4(result);
}
Datum
@@ -819,18 +825,10 @@ float4div(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;
+ float4 result;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ result = arg1 / arg2;
+ PG_RETURN_FLOAT4(result);
}
/*
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [HACKERS] [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-29 17:27 Tom Lane <tgl@sss.pgh.pa.us>
parent: Roman Kononov <kononov195-pgsql@yahoo.com>
0 siblings, 1 reply; 10+ messages in thread
From: Tom Lane @ 2006-12-29 17:27 UTC (permalink / raw)
To: Roman Kononov <kononov195-pgsql@yahoo.com>; +Cc: Bruce Momjian <bruce@momjian.us>; pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>
Roman Kononov <kononov195-pgsql@yahoo.com> writes:
> Think about this idea please. This has no INF, NaN or range
> checks and detects all "bad" cases with any floating point
> math.
Doesn't even compile here (no <fenv.h>).
regards, tom lane
^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: [HACKERS] [BUGS] BUG #2846: inconsistent and confusing
@ 2006-12-29 19:54 Roman Kononov <kononov195-pgsql@yahoo.com>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 0 replies; 10+ messages in thread
From: Roman Kononov @ 2006-12-29 19:54 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Roman Kononov <kononov195-pgsql@yahoo.com>; Bruce Momjian <bruce@momjian.us>; pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>
On 12/29/2006 11:27 AM, Tom Lane wrote:
> Doesn't even compile here (no <fenv.h>).
Where do you compile?
Roman
^ permalink raw reply [nested|flat] 10+ messages in thread
end of thread, other threads:[~2006-12-29 19:54 UTC | newest]
Thread overview: 10+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2006-12-27 21:35 Re: [BUGS] BUG #2846: inconsistent and confusing Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Joshua D. Drake <jd@commandprompt.com>
2006-12-28 01:41 Re: [BUGS] BUG #2846: inconsistent and confusing Bruce Momjian <bruce@momjian.us>
2006-12-28 01:42 Re: [BUGS] BUG #2846: inconsistent and confusing Bruce Momjian <bruce@momjian.us>
2006-12-28 01:45 Re: [BUGS] BUG #2846: inconsistent and confusing Bruce Momjian <bruce@momjian.us>
2006-12-28 20:33 Re: [BUGS] BUG #2846: inconsistent and confusing Bruce Momjian <bruce@momjian.us>
2006-12-29 05:20 ` Tom Lane <tgl@sss.pgh.pa.us>
2006-12-29 17:11 Re: [HACKERS] [BUGS] BUG #2846: inconsistent and confusing Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-29 17:27 ` Tom Lane <tgl@sss.pgh.pa.us>
2006-12-29 19:54 ` Roman Kononov <kononov195-pgsql@yahoo.com>
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox