pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feedRe: [BUGS] BUG #2846: inconsistent and confusing handling of
12+ messages / 4 participants
[nested] [flat]
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of
@ 2006-12-27 18:44 Bruce Momjian <bruce@momjian.us>
2006-12-27 19:15 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
0 siblings, 2 replies; 12+ messages in thread
From: Bruce Momjian @ 2006-12-27 18:44 UTC (permalink / raw)
To: PostgreSQL-patches <pgsql-patches@postgresql.org>; +Cc: Roman Kononov <kononov195-pgsql@yahoo.com>
I have made some more progress on this patch. I have fixed the issue
with aggregates:
test=> select avg(ff) from tt;
ERROR: type "double precision" value out of range: overflow
and tested the performance overhead of the new CheckFloat8Val() calls
the fix requires using:
EXPLAIN ANALYZE SELECT AVG(x.COL)
FROM (SELECT 323.2 AS COL FROM generate_series(1,1000000)) AS x;
and could not measure any overhead.
I also found a few more bugs, this one with float4 negation:
test=> SELECT -('0'::float4);
?column?
----------
-0
(1 row)
test=> SELECT -('0'::float8);
?column?
----------
0
(1 row)
and this one with casting 'Nan' to an integer:
test=> SELECT 'Nan'::float8::int4;
int4
-------------
-2147483648
(1 row)
I have fixed these as well:
test=> SELECT -('0'::float4);
?column?
----------
0
(1 row)
test=> SELECT 'Nan'::float8::int4;
ERROR: integer out of range
The only unsolved issue is the one with underflow checks. I have added
comments explaining the problem in case someone ever figures out how to
address it.
If I don't receive further comments, I will apply the new attached patch
shortly.
---------------------------------------------------------------------------
bruce wrote:
> Roman Kononov wrote:
> >
> > The following bug has been logged online:
> >
> > Bug reference: 2846
> > Logged by: Roman Kononov
> > Email address: kononov195-pgsql@yahoo.com
> > PostgreSQL version: 8.2.0 and older
> > Operating system: linux 2.6.15-27-amd64 ubuntu
> > Description: inconsistent and confusing handling of underflows, NaNs
> > and INFs
> > Details:
>
> This is a very interesting bug report. It seems you have done some good
> analysis of PostgreSQL and how it handles certain corner cases,
> infinity, and NaN.
>
> I have researched your findings and will show some fixes below:
>
> > Please compare the results of the simple queries.
> > ==============================================
> > test=# select ('NaN'::float4)::int2;
> > int2
> > ------
> > 0
> > (1 row)
>
> There certainly should be an isnan() test when converting to int2
> because while float can represent NaN, int2 cannot. The fix shows:
>
> test=> select ('NaN'::float4)::int2;
> ERROR: smallint out of range
>
> > test=# select ('NaN'::float4)::int4;
> > int4
> > -------------
> > -2147483648
> > (1 row)
>
> Same for int4:
>
> test=> select ('NaN'::float4)::int4;
> ERROR: integer out of range
>
> > test=# select ('NaN'::float4)::int8;
> > ERROR: bigint out of range
>
> This one was correct because it uses rint() internally.
>
> > test=# select ('nan'::numeric)::int4;
> > ERROR: cannot convert NaN to integer
> > ==============================================
> > test=# select abs('INF'::float4);
> > abs
> > ----------
> > Infinity
> > (1 row)
>
> Correct.
>
> > test=# select abs('INF'::float8);
> > ERROR: type "double precision" value out of range: overflow
>
> This one was more complicated. float4/8 operations test for
> results > FLOAT[84]_MAX. This is because if you do this:
>
> test=> select (1e201::float8)*(1e200::float8);
>
> the result internally is Infinity, so they check for Inf as a check for
> overflow. The bottom line is that while the current code allows
> infinity to be entered, it does not allow the value to operate in many
> context because it is assumes Inf to be an overflow indicator. I have
> fixed this by passing a boolean to indicate if any of the operands were
> infinity, and if so, allow an infinite result, so this now works:
>
> test=> select abs('INF'::float8);
> abs
> ----------
> Infinity
> (1 row)
>
> > ==============================================
> > test=# select -('INF'::float4);
> > ?column?
> > -----------
> > -Infinity
> > (1 row)
> >
> > test=# select -('INF'::float8);
> > ERROR: type "double precision" value out of range: overflow
>
> And this now works too:
>
> test=> select -('INF'::float8);
> ?column?
> -----------
> -Infinity
> (1 row)
>
> > ==============================================
> > test=# select (1e-37::float4)*(1e-22::float4);
> > ?column?
> > ----------
> > 0
> > (1 row)
>
> This one is quite complex. For overflow, there is a range of values
> that is represented as > FLOAT8_MAX, but for values very large, the
> result becomes Inf. The old code assumed an Inf result was an overflow,
> and threw an error, as I outlined above. The new code does a better
> job.
>
> Now, for underflow. For underflow, we again have a range slightly
> smaller than DBL_MIN where we can detect an underflow, and throw an
> error, but just like overflow, if the underflow is too small, the result
> becomes zero. The bad news is that unlike Inf, zero isn't a special
> value. With Inf, we could say if we got an infinite result from
> non-infinite arguments, we had an overflow, but for underflow, how do we
> know if zero is an underflow or just the correct result? For
> multiplication, we could say that a zero result for non-zero arguments
> is almost certainly an underflow, but I don't see how we can handle the
> other operations as simply.
>
> I was not able to fix the underflow problems you reported.
>
> > test=# select (1e-37::float4)*(1e-2::float4);
> > ERROR: type "real" value out of range: underflow
> > ==============================================
> > test=# select (1e-300::float8)*(1e-30::float8);
> > ?column?
> > ----------
> > 0
> > (1 row)
> >
> > test=# select (1e-300::float8)*(1e-20::float8);
> > ERROR: type "double precision" value out of range: underflow
> > ==============================================
> > test=# select ('INF'::float8-'INF'::float8);
> > ?column?
> > ----------
> > NaN
> > (1 row)
> >
> > test=# select ('INF'::float8+'INF'::float8);
> > ERROR: type "double precision" value out of range: overflow
>
> This works fine now:
>
> test=> select ('INF'::float8+'INF'::float8);
> ?column?
> ----------
> Infinity
> (1 row)
>
> > ==============================================
> > test=# select ('INF'::float4)::float8;
> > float8
> > ----------
> > Infinity
> > (1 row)
> >
> > test=# select ('INF'::float8)::float4;
> > ERROR: type "real" value out of range: overflow
> > ==============================================
> > test=# select cbrt('INF'::float4);
> > cbrt
> > ----------
> > Infinity
> > (1 row)
> >
> > test=# select sqrt('INF'::float4);
> > ERROR: type "double precision" value out of range: overflow
>
> This works fine too:
>
> test=> select ('INF'::float8)::float4;
> float4
> ----------
> Infinity
> (1 row)
>
> > ==============================================
> > test=# select ((-32768::int8)::int2)%(-1::int2);
> > ?column?
> > ----------
> > 0
> > (1 row)
> >
> > test=# select ((-2147483648::int8)::int4)%(-1::int4);
> > ERROR: floating-point exception
> > DETAIL: An invalid floating-point operation was signaled. This probably
> > means an out-of-range result or an invalid operation, such
> > as division by zero.
>
> This was an interesting case. It turns out the value has to be INT_MIN,
> and the second value has to be -1. The exception happens, I think,
> because the CPU does the division first before getting the remainder,
> and INT_MIN / -1 is > INT_MAX, hence the error. I just special-cased it
> to return zero in the int4mod() code:
>
> test=> select ((-2147483648::int8)::int4)%(-1::int4);
> ?column?
> ----------
> 0
> (1 row)
>
> You can actually show the error without using int8:
>
> test=> select ((-2147483648)::int4) % (-1);
> ?column?
> ----------
> 0
> (1 row)
>
> The parentheses are required to make the value negative before the cast
> to int4.
>
> > ==============================================
> > test=# create table tt (ff float8);
> > CREATE TABLE
> > test=# insert into tt values (1e308),(1e308),(1e308);
> > INSERT 0 3
> > test=# select * from tt;
> > ff
> > --------
> > 1e+308
> > 1e+308
> > 1e+308
> > (3 rows)
> >
> > test=# select avg(ff) from tt;
> > avg
> > ----------
> > Infinity
> > (1 row)
> >
> > test=# select stddev(ff) from tt;
> > stddev
> > --------
> > NaN
> > (1 row)
>
> I didn't study the aggregate cases. Does someone want to look those
> over?
>
> The attached patch fixes all the items I mentioned above.
--
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, 26.2K) 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 27 Dec 2006 18:43:26 -0000
***************
*** 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);
--- 104,111 ----
int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
! static void CheckFloat4Val(double val, bool has_inf_args);
! static void CheckFloat8Val(double val, bool has_inf_args);
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")));
--- 211,220 ----
* raise an ereport() error if it is
*/
static void
! CheckFloat4Val(double val, bool has_inf_args)
{
! /* If one of the input arguments was infinity, allow an infinite result */
! if (fabs(val) > FLOAT4_MAX && (!isinf(val) || !has_inf_args))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("type \"real\" value out of range: overflow")));
***************
*** 230,241 ****
* 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),
--- 231,261 ----
* raise an ereport() error if it is
*/
static void
! CheckFloat8Val(double val, bool has_inf_args)
{
! /*
! * 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 && (!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 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.
+ */
if (val != 0.0 && fabs(val) < FLOAT8_MIN)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
***************
*** 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);
}
--- 389,395 ----
* if we get here, we have a legal double, still need to check to see if
* it's a legal float4
*/
! CheckFloat4Val(val, true /* allow Inf */);
PG_RETURN_FLOAT4((float4) val);
}
***************
*** 558,565 ****
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
! if (!isinf(val))
! CheckFloat8Val(val);
PG_RETURN_FLOAT8(val);
}
--- 577,583 ----
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
! CheckFloat8Val(val, true /* allow Inf */);
PG_RETURN_FLOAT8(val);
}
***************
*** 652,659 ****
float4um(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
! PG_RETURN_FLOAT4((float4) -arg1);
}
Datum
--- 670,681 ----
float4um(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
+ float4 result;
+
+ result = ((arg1 != 0) ? -(arg1) : arg1);
! CheckFloat4Val(result, isinf(arg1));
! 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);
}
--- 727,734 ----
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);
}
--- 743,749 ----
result = ((arg1 != 0) ? -(arg1) : arg1);
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 786,792 ****
double result;
result = arg1 + arg2;
! CheckFloat4Val(result);
PG_RETURN_FLOAT4((float4) result);
}
--- 804,810 ----
double result;
result = arg1 + arg2;
! CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT4((float4) result);
}
***************
*** 798,804 ****
double result;
result = arg1 - arg2;
! CheckFloat4Val(result);
PG_RETURN_FLOAT4((float4) result);
}
--- 816,822 ----
double result;
result = arg1 - arg2;
! CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT4((float4) result);
}
***************
*** 810,816 ****
double result;
result = arg1 * arg2;
! CheckFloat4Val(result);
PG_RETURN_FLOAT4((float4) result);
}
--- 828,834 ----
double result;
result = arg1 * arg2;
! CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT4((float4) result);
}
***************
*** 829,835 ****
/* Do division in float8, then check for overflow */
result = (float8) arg1 / (float8) arg2;
! CheckFloat4Val(result);
PG_RETURN_FLOAT4((float4) result);
}
--- 847,853 ----
/* Do division in float8, then check for overflow */
result = (float8) arg1 / (float8) arg2;
! CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT4((float4) result);
}
***************
*** 848,854 ****
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 866,872 ----
result = arg1 + arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 861,867 ****
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 879,885 ----
result = arg1 - arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 874,880 ****
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 892,898 ----
result = arg1 * arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 892,898 ****
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 910,916 ----
result = arg1 / arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 1142,1148 ****
{
float8 num = PG_GETARG_FLOAT8(0);
! CheckFloat4Val(num);
PG_RETURN_FLOAT4((float4) num);
}
--- 1160,1166 ----
{
float8 num = PG_GETARG_FLOAT8(0);
! CheckFloat4Val(num, isinf(num));
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")));
--- 1175,1182 ----
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")));
--- 1195,1201 ----
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")));
--- 1242,1248 ----
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")));
--- 1261,1267 ----
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);
}
--- 1504,1510 ----
result = sqrt(arg1);
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1500,1505 ****
--- 1519,1525 ----
float8 result;
result = cbrt(arg1);
+ CheckFloat8Val(result, isinf(arg1));
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);
}
--- 1559,1565 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 1569,1575 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1589,1595 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1598,1604 ****
result = log(arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1618,1624 ----
result = log(arg1);
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1628,1634 ****
result = log10(arg1);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1648,1654 ----
result = log10(arg1);
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1653,1659 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1673,1679 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1678,1684 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1698,1704 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1703,1709 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1723,1729 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1729,1735 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1749,1755 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 1754,1760 ****
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1774,1780 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1780,1786 ****
errmsg("input is out of range")));
result = 1.0 / result;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1800,1806 ----
errmsg("input is out of range")));
result = 1.0 / result;
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1805,1811 ****
(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, isinf(arg1));
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);
}
--- 1850,1856 ----
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1846,1852 ****
result = arg1 * (180.0 / M_PI);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1866,1872 ----
result = arg1 * (180.0 / M_PI);
! CheckFloat8Val(result, isinf(arg1));
PG_RETURN_FLOAT8(result);
}
***************
*** 1872,1878 ****
result = arg1 * (M_PI / 180.0);
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 1892,1898 ----
result = arg1 * (M_PI / 180.0);
! CheckFloat8Val(result, isinf(arg1));
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
--- 1983,1992 ----
N += 1.0;
sumX += newval;
+ CheckFloat8Val(sumX, isinf(transvalues[1]) || isinf(newval));
sumX2 += newval * newval;
! CheckFloat8Val(sumX2, isinf(transvalues[2]) || isinf(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
***************
*** 2016,2023 ****
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
--- 2038,2047 ----
N += 1.0;
sumX += newval;
+ CheckFloat4Val(sumX, isinf(transvalues[1]) || isinf(newval));
sumX2 += newval * newval;
! CheckFloat4Val(sumX2, isinf(transvalues[2]) || isinf(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
***************
*** 2088,2093 ****
--- 2112,2118 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, isinf(sumX2) || isinf(sumX));
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2116,2121 ****
--- 2141,2147 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, isinf(sumX2) || isinf(sumX));
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2144,2149 ****
--- 2170,2176 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, isinf(sumX2) || isinf(sumX));
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2172,2177 ****
--- 2199,2205 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, isinf(sumX2) || isinf(sumX));
/* 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
--- 2248,2263 ----
N += 1.0;
sumX += newvalX;
+ CheckFloat8Val(sumX, isinf(transvalues[1]) || isinf(newvalX));
sumX2 += newvalX * newvalX;
+ CheckFloat8Val(sumX2, isinf(transvalues[2]) || isinf(newvalX));
sumY += newvalY;
+ CheckFloat8Val(sumY, isinf(transvalues[3]) || isinf(newvalY));
sumY2 += newvalY * newvalY;
+ CheckFloat8Val(sumY2, isinf(transvalues[4]) || isinf(newvalY));
sumXY += newvalX * newvalY;
! CheckFloat8Val(sumXY, isinf(transvalues[5]) || isinf(newvalX) || isinf(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
***************
*** 2282,2287 ****
--- 2315,2321 ----
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numerator, isinf(sumX2) || isinf(sumX));
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2310,2315 ****
--- 2344,2350 ----
PG_RETURN_NULL();
numerator = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numerator, isinf(sumY2) || isinf(sumY));
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
***************
*** 2340,2345 ****
--- 2375,2381 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, isinf(sumXY) || isinf(sumX) || isinf(sumY));
/* A negative result is valid here */
***************
*** 2406,2411 ****
--- 2442,2448 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, isinf(sumXY) || isinf(sumX) || isinf(sumY));
PG_RETURN_FLOAT8(numerator / (N * N));
}
***************
*** 2432,2437 ****
--- 2469,2475 ----
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numerator, isinf(sumXY) || isinf(sumX) || isinf(sumY));
PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
}
***************
*** 2464,2471 ****
--- 2502,2512 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, isinf(sumX2) || isinf(sumX));
numeratorY = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numeratorY, isinf(sumY2) || isinf(sumY));
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, isinf(sumXY) || isinf(sumX) || isinf(sumY));
if (numeratorX <= 0 || numeratorY <= 0)
PG_RETURN_NULL();
***************
*** 2501,2508 ****
--- 2542,2552 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, isinf(sumX2) || isinf(sumX));
numeratorY = N * sumY2 - sumY * sumY;
+ CheckFloat8Val(numeratorY, isinf(sumY2) || isinf(sumY));
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, isinf(sumXY) || isinf(sumX) || isinf(sumY));
if (numeratorX <= 0)
PG_RETURN_NULL();
/* per spec, horizontal line produces 1.0 */
***************
*** 2538,2544 ****
--- 2582,2590 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, isinf(sumX2) || isinf(sumX));
numeratorXY = N * sumXY - sumX * sumY;
+ CheckFloat8Val(numeratorXY, isinf(sumXY) || isinf(sumX) || isinf(sumY));
if (numeratorX <= 0)
PG_RETURN_NULL();
***************
*** 2570,2576 ****
--- 2616,2624 ----
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CheckFloat8Val(numeratorX, isinf(sumX2) || isinf(sumX));
numeratorXXY = sumY * sumX2 - sumX * sumXY;
+ CheckFloat8Val(numeratorXXY, isinf(sumY) || isinf(sumX2) || isinf(sumX) || isinf(sumXY));
if (numeratorX <= 0)
PG_RETURN_NULL();
***************
*** 2598,2604 ****
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2646,2652 ----
float8 result;
result = arg1 + arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2610,2616 ****
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2658,2664 ----
float8 result;
result = arg1 - arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2622,2628 ****
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2670,2676 ----
float8 result;
result = arg1 * arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2639,2645 ****
errmsg("division by zero")));
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2687,2693 ----
errmsg("division by zero")));
result = arg1 / arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2658,2664 ****
result = arg1 + arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2706,2712 ----
result = arg1 + arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2671,2677 ****
result = arg1 - arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2719,2725 ----
result = arg1 - arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2684,2690 ****
result = arg1 * arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2732,2738 ----
result = arg1 * arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT8(result);
}
***************
*** 2702,2708 ****
result = arg1 / arg2;
! CheckFloat8Val(result);
PG_RETURN_FLOAT8(result);
}
--- 2750,2756 ----
result = arg1 / arg2;
! CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
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 27 Dec 2006 18:43:26 -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 27 Dec 2006 18:43:28 -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 27 Dec 2006 18:43:28 -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?
----------
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
@ 2006-12-27 19:15 ` Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 20:27 ` Re: [PATCHES] [BUGS] BUG #2846: inconsistent and confusing handling Roman Kononov <kononov195-pgsql@yahoo.com>
1 sibling, 1 reply; 12+ messages in thread
From: Tom Lane @ 2006-12-27 19:15 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 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.
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.
regards, tom lane
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [PATCHES] [BUGS] BUG #2846: inconsistent and confusing handling
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 19:15 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Tom Lane <tgl@sss.pgh.pa.us>
@ 2006-12-27 20:27 ` Roman Kononov <kononov195-pgsql@yahoo.com>
0 siblings, 0 replies; 12+ messages in thread
From: Roman Kononov @ 2006-12-27 20:27 UTC (permalink / raw)
To: pgsql-hackers; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Bruce Momjian <bruce@momjian.us>; PostgreSQL-patches <pgsql-patches@postgresql.org>
On 12/27/2006 01:15 PM, Tom Lane wrote:
> 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.
I vote for complete IEEE-compliance. No exceptions with pure floating
point math. Float -> int conversions should reject overflow, INF and
NaN. Float -> numeric conversions should reject INF.
> 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.
This might look like another possibility for confusion. For example
INF-INF=NaN.
Regards,
Roman.
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
@ 2006-12-27 20:43 ` Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
1 sibling, 1 reply; 12+ messages in thread
From: Roman Kononov @ 2006-12-27 20:43 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; PostgreSQL-patches <pgsql-patches@postgresql.org>
On 12/27/2006 12:44 PM, Bruce Momjian wrote:
> The only unsolved issue is the one with underflow checks. I have added
> comments explaining the problem in case someone ever figures out how to
> address it.
This will behave better for float4:
Datum float4pl(PG_FUNCTION_ARGS)
{
--- float4 arg1 = PG_GETARG_FLOAT4(0);
--- float4 arg2 = PG_GETARG_FLOAT4(1);
+++ double arg1 = PG_GETARG_FLOAT4(0);
+++ double arg2 = PG_GETARG_FLOAT4(1);
double result;
result = arg1 + arg2;
CheckFloat4Val(result,isinf(arg1) || isinf(arg2));
PG_RETURN_FLOAT4((float4) result);
}
Roman
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
@ 2006-12-27 21:23 ` Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
0 siblings, 1 reply; 12+ messages in thread
From: Bruce Momjian @ 2006-12-27 21:23 UTC (permalink / raw)
To: Roman Kononov <roman@xtremedatainc.com>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>
Roman Kononov wrote:
> On 12/27/2006 12:44 PM, Bruce Momjian wrote:
> > The only unsolved issue is the one with underflow checks. I have added
> > comments explaining the problem in case someone ever figures out how to
> > address it.
>
> This will behave better for float4:
>
> Datum float4pl(PG_FUNCTION_ARGS)
> {
> --- float4 arg1 = PG_GETARG_FLOAT4(0);
> --- float4 arg2 = PG_GETARG_FLOAT4(1);
> +++ double arg1 = PG_GETARG_FLOAT4(0);
> +++ double arg2 = PG_GETARG_FLOAT4(1);
> double result;
>
> result = arg1 + arg2;
> CheckFloat4Val(result,isinf(arg1) || isinf(arg2));
> PG_RETURN_FLOAT4((float4) result);
> }
Are you sure? As I remember, computation automatically upgrades to
'double'. See this program and output:
$ cat tst1.c
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
float a = 1e30, b = 1e30;
double c;
c = a * b;
printf("%e\n", c);
return 0;
}
$ tst1
1.000000e+60
--
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] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
@ 2006-12-27 21:43 ` Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 22:04 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 23:19 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 2 replies; 12+ messages in thread
From: Roman Kononov @ 2006-12-27 21:43 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>
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:
~>uname -a
Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux
~>gcc --version
gcc (GCC) 4.3.0 20061213 (experimental)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
~>cat test.c
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
float a = 1e30, b = 1e30;
double c;
c = a * b;
printf("%e\n", c);
return 0;
}
~>gcc test.c
~>./a.out
inf
~>gcc -march=i386 -m32 test.c
~>./a.out
1.000000e+60
Roman
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
@ 2006-12-27 22:04 ` Bruce Momjian <bruce@momjian.us>
2006-12-27 22:48 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
1 sibling, 1 reply; 12+ messages in thread
From: Bruce Momjian @ 2006-12-27 22:04 UTC (permalink / raw)
To: Roman Kononov <kononov195-pgsql@yahoo.com>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>
Roman Kononov wrote:
> 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:
>
> ~>uname -a
> Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux
> ~>gcc --version
> gcc (GCC) 4.3.0 20061213 (experimental)
> Copyright (C) 2006 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> ~>cat test.c
> #include <stdio.h>
> #include <stdlib.h>
>
> int
> main(int argc, char *argv[])
> {
> float a = 1e30, b = 1e30;
> double c;
>
> c = a * b;
>
> printf("%e\n", c);
> return 0;
> }
> ~>gcc test.c
> ~>./a.out
> inf
> ~>gcc -march=i386 -m32 test.c
> ~>./a.out
> 1.000000e+60
Interesting. I didn't know that, but in the float4pl() function,
because the overflow tests and result is float4, what value is there to
doing things as double --- as soon as the float4 maximum is exceeded, we
throw an error?
--
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] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 22:04 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
@ 2006-12-27 22:48 ` Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 23:26 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 12+ messages in thread
From: Roman Kononov @ 2006-12-27 22:48 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: PostgreSQL-patches <pgsql-patches@postgresql.org>
On 12/27/2006 04:04 PM, Bruce Momjian wrote:
> Interesting. I didn't know that, but in the float4pl() function,
> because the overflow tests and result is float4, what value is there to
> doing things as double --- as soon as the float4 maximum is exceeded, we
> throw an error?
>
This is useful for underflows.
float a=1e-30;
float b=1e-30;
double r1=a*b;
double r2=(double)a*b;
r1 is zero and underflow is lost.
r2 is not zero and underflow is detected.
In float4mul() and float4div(), the computation should be double precision.
In float4pl() and float4mi(), it depends on the ability of the hardware
to generate denormalized numbers. If denormalized numbers are generated,
float vs double makes no difference. If denormalized numbers are not
generated (zero is generated), then double computation is safer.
Another way to detect underflows, overflows and other junk is to use FPU
status flags after each computation. Performance will likely suffer.
#include <fenv.h>
Datum
float4mul(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
float4 result;
int fe_exceptions;
feclearexcept(FE_ALL_EXCEPT);
result = arg1 * arg2;
fe_exceptions=fetestexcept(FE_DIVBYZERO,FE_INVALID,FE_OVERFLOW,FE_UNDERFLOW);
if (fe_exceptions) handle_exceptions(fe_exceptions); //??
PG_RETURN_FLOAT4(result);
}
Yet another way to detect exceptions is to remove all CheckFloat4Val(),
CheckFloat8Val(), isnan(), unmask FPU exceptions and install an exception handler.
Might have portability difficulties. Comparisons of NaNs must be done in
non-IEEE way (FPU does not compare NaNs, it generates exceptions).
Roman
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 22:04 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 22:48 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
@ 2006-12-27 23:26 ` Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 0 replies; 12+ messages in thread
From: Tom Lane @ 2006-12-27 23:26 UTC (permalink / raw)
To: pgsql-hackers@postgresql.org, Roman Kononov <kononov195-pgsql@yahoo.com>; +Cc: Bruce Momjian <bruce@momjian.us>; PostgreSQL-patches <pgsql-patches@postgresql.org>
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.
regards, tom lane
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows,
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
@ 2006-12-27 23:19 ` Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 23:47 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling Roman Kononov <kononov195-pgsql@yahoo.com>
1 sibling, 1 reply; 12+ messages in thread
From: Tom Lane @ 2006-12-27 23:19 UTC (permalink / raw)
To: pgsql-hackers@postgresql.org, Roman Kononov <kononov195-pgsql@yahoo.com>; +Cc: Bruce Momjian <bruce@momjian.us>; PostgreSQL-patches <pgsql-patches@postgresql.org>
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.
regards, tom lane
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 23:19 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Tom Lane <tgl@sss.pgh.pa.us>
@ 2006-12-27 23:47 ` Roman Kononov <kononov195-pgsql@yahoo.com>
0 siblings, 0 replies; 12+ messages in thread
From: Roman Kononov @ 2006-12-27 23:47 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: pgsql-hackers@postgresql.org, Bruce Momjian <bruce@momjian.us>; PostgreSQL-patches <pgsql-patches@postgresql.org>
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.
Roman
^ permalink raw reply [nested|flat] 12+ messages in thread
* Re: [BUGS] BUG #2846: inconsistent and confusing handling of
@ 2006-12-27 22:44 Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 0 replies; 12+ messages in thread
From: Tom Lane @ 2006-12-27 22:44 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: pgsql-hackers@postgresql.org, PostgreSQL-patches <pgsql-patches@postgresql.org>; Roman Kononov <kononov195-pgsql@yahoo.com>
Bruce Momjian <bruce@momjian.us> writes:
> Tom Lane wrote:
>> 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?
Infinity is what you are *supposed* to get, per IEEE spec.
>> 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));
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...);
regards, tom lane
^ permalink raw reply [nested|flat] 12+ messages in thread
end of thread, other threads:[~2006-12-27 23:47 UTC | newest]
Thread overview: 12+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2006-12-27 18:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Bruce Momjian <bruce@momjian.us>
2006-12-27 19:15 ` Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 20:27 ` Re: [PATCHES] [BUGS] BUG #2846: inconsistent and confusing handling Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 20:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <roman@xtremedatainc.com>
2006-12-27 21:23 ` Bruce Momjian <bruce@momjian.us>
2006-12-27 21:43 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 22:04 ` Bruce Momjian <bruce@momjian.us>
2006-12-27 22:48 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 23:26 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 23:19 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling of underflows, Tom Lane <tgl@sss.pgh.pa.us>
2006-12-27 23:47 ` Re: [BUGS] BUG #2846: inconsistent and confusing handling Roman Kononov <kononov195-pgsql@yahoo.com>
2006-12-27 22:44 Re: [BUGS] BUG #2846: inconsistent and confusing handling of Tom Lane <tgl@sss.pgh.pa.us>
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