Thread: Re: [BUGS] BUG #2846: inconsistent and confusing handling of
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. + 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? ----------
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
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. +
> 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
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
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. + 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;
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
Tom Lane wrote: > 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 :-( Well, then show me what direction you think is better. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
Bruce Momjian <bruce@momjian.us> writes: > Tom Lane wrote: >> This is *not* going in the right direction :-( > Well, then show me what direction you think is better. Fewer restrictions, not more. The thrust of what I've been saying (and I think Roman too) is to trust in the hardware float-arithmetic implementation to be right. Every time you add an additional "error check" you are going in the wrong direction. regards, tom lane
Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > Tom Lane wrote: > >> This is *not* going in the right direction :-( > > > Well, then show me what direction you think is better. > > Fewer restrictions, not more. The thrust of what I've been saying > (and I think Roman too) is to trust in the hardware float-arithmetic > implementation to be right. Every time you add an additional "error > check" you are going in the wrong direction. OK, are you saying that there is a signal we are ignoring for overflow/underflow, or that we should just silently overflow/underflow and not 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. +
Bruce Momjian <bruce@momjian.us> writes: > OK, are you saying that there is a signal we are ignoring for > overflow/underflow, or that we should just silently overflow/underflow > and not throw an error? Silent underflow is fine with me; it's the norm in most all float implementations and won't surprise anyone. For overflow I'm OK with either returning infinity or throwing an error --- but if an error, it should only be about inf-out-with-non-inf-in, not comparisons to any artificial MAX/MIN values. Anyone else have an opinion about this? regards, tom lane
Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: >> OK, are you saying that there is a signal we are ignoring for >> overflow/underflow, or that we should just silently overflow/underflow >> and not throw an error? > > Silent underflow is fine with me; it's the norm in most all float > implementations and won't surprise anyone. For overflow I'm OK with > either returning infinity or throwing an error --- but if an error, > it should only be about inf-out-with-non-inf-in, not comparisons to any > artificial MAX/MIN values. > > Anyone else have an opinion about this? If an underflow is not reported (And thus silently treated as zero), then it'd make sense for me to deal with overflows in a similar way, and just return infinity. The most correct solution would IMHO be to provide a guc variable "strict_float_semantics" that defaults to "off", meaning that neather overflow nor underflow reports an error. If the variable was set to on, _both_ overflow and underflow would be reported. Just my €0.02 greetings, Florian Pflug
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 --- 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); } /*
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
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
On 12/29/2006 11:27 AM, Tom Lane wrote: > Doesn't even compile here (no <fenv.h>). Where do you compile? Roman
Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > OK, are you saying that there is a signal we are ignoring for > > overflow/underflow, or that we should just silently overflow/underflow > > and not throw an error? > > Silent underflow is fine with me; it's the norm in most all float > implementations and won't surprise anyone. For overflow I'm OK with > either returning infinity or throwing an error --- but if an error, > it should only be about inf-out-with-non-inf-in, not comparisons to any > artificial MAX/MIN values. OK, I am happy to remove the MIN/MAX comparisons. Those were in the original code. The attached, updated patch creates a single CHECKFLOATVAL() macro that does the overflow/underflow comparisons and throws an error. This also reduces the isinf() calls. Should I be concerned we are now duplicating the error text in all call sites? Regression wording modified now that float4/float8 checks are merged. I haven't update the platform-specific float* expected files yet, but will on commit. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. + 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 30 Dec 2006 18:19:57 -0000 *************** *** 12,59 **** * *------------------------------------------------------------------------- */ - /*---------- - * OLD COMMENTS - * Basic float4 ops: - * float4in, float4out, float4recv, float4send - * float4abs, float4um, float4up - * Basic float8 ops: - * float8in, float8out, float8recv, float8send - * float8abs, float8um, float8up - * Arithmetic operators: - * float4pl, float4mi, float4mul, float4div - * float8pl, float8mi, float8mul, float8div - * Comparison operators: - * float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp - * float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp - * Conversion routines: - * ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2 - * - * Random float8 ops: - * dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1 - * Arithmetic operators: - * float48pl, float48mi, float48mul, float48div - * float84pl, float84mi, float84mul, float84div - * Comparison operators: - * float48eq, float48ne, float48lt, float48le, float48gt, float48ge - * float84eq, float84ne, float84lt, float84le, float84gt, float84ge - * - * (You can do the arithmetic and comparison stuff using conversion - * routines, but then you pay the overhead of invoking a separate - * conversion function...) - * - * XXX GLUESOME STUFF. FIX IT! -AY '94 - * - * Added some additional conversion routines and cleaned up - * a bit of the existing code. Need to change the error checking - * for calls to pow(), exp() since on some machines (my Linux box - * included) these routines do not set errno. - tgl 97/05/10 - *---------- - */ #include "postgres.h" #include <ctype.h> - #include <float.h> #include <math.h> #include <limits.h> /* for finite() on Solaris */ --- 12,20 ---- *************** *** 91,111 **** #define MAXFLOATWIDTH 64 #define MAXDOUBLEWIDTH 128 ! /* ========== USER I/O ROUTINES ========== */ ! #define FLOAT4_MAX FLT_MAX ! #define FLOAT4_MIN FLT_MIN ! #define FLOAT8_MAX DBL_MAX ! #define FLOAT8_MIN DBL_MIN /* Configurable GUC parameter */ int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */ - static void CheckFloat4Val(double val); - static void CheckFloat8Val(double val); static int float4_cmp_internal(float4 a, float4 b); static int float8_cmp_internal(float8 a, float8 b); --- 52,81 ---- #define MAXFLOATWIDTH 64 #define MAXDOUBLEWIDTH 128 ! /* ! * check to see if a float4/8 val has underflowed or overflowed ! */ ! #define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid) \ ! do { \ ! if (isinf(val) && !(inf_is_valid)) \ ! ereport(ERROR, \ ! (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \ ! errmsg("value out of range: overflow"))); \ ! \ ! if ((val) == 0.0 && !(zero_is_valid)) \ ! ereport(ERROR, \ ! (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \ ! errmsg("value out of range: underflow"))); \ ! } while(0) ! /* ========== USER I/O ROUTINES ========== */ /* Configurable GUC parameter */ int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */ static int float4_cmp_internal(float4 a, float4 b); static int float8_cmp_internal(float8 a, float8 b); *************** *** 205,248 **** /* - * check to see if a float4 val is outside of the FLOAT4_MIN, - * FLOAT4_MAX bounds. - * - * 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"))); - if (val != 0.0 && fabs(val) < FLOAT4_MIN) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("type \"real\" value out of range: underflow"))); - } - - /* - * check to see if a float8 val is outside of the FLOAT8_MIN, - * FLOAT8_MAX bounds. - * - * raise an ereport() error if it is - */ - static 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"))); - } - - /* * float4in - converts "num" to float * restricted syntax: * {<sp>} [+|-] {digit} [.{digit}] [<exp>] --- 175,180 ---- *************** *** 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); } --- 301,307 ---- * if we get here, we have a legal double, still need to check to see if * it's a legal float4 */ ! CHECKFLOATVAL((float4) val, isinf(val), val == 0); PG_RETURN_FLOAT4((float4) val); } *************** *** 558,565 **** errmsg("invalid input syntax for type double precision: \"%s\"", orig_num))); ! if (!isinf(val)) ! CheckFloat8Val(val); PG_RETURN_FLOAT8(val); } --- 489,495 ---- errmsg("invalid input syntax for type double precision: \"%s\"", orig_num))); ! CHECKFLOATVAL(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 --- 582,593 ---- float4um(PG_FUNCTION_ARGS) { float4 arg1 = PG_GETARG_FLOAT4(0); + float4 result; + + result = ((arg1 != 0) ? -(arg1) : arg1); ! CHECKFLOATVAL(result, isinf(arg1), true); ! PG_RETURN_FLOAT4(result); } Datum *************** *** 705,716 **** float8abs(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); - float8 result; - - result = fabs(arg1); ! CheckFloat8Val(result); ! PG_RETURN_FLOAT8(result); } --- 639,646 ---- 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); } --- 655,661 ---- result = ((arg1 != 0) ? -(arg1) : arg1); ! CHECKFLOATVAL(result, isinf(arg1), true); PG_RETURN_FLOAT8(result); } *************** *** 783,793 **** { 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 --- 713,723 ---- { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); ! float4 result; result = arg1 + arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); ! PG_RETURN_FLOAT4(result); } Datum *************** *** 795,805 **** { 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 --- 725,735 ---- { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); ! float4 result; result = arg1 - arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); ! PG_RETURN_FLOAT4(result); } Datum *************** *** 807,817 **** { 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 --- 737,748 ---- { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); ! float4 result; result = arg1 * arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), ! arg1 == 0 || arg2 == 0); ! PG_RETURN_FLOAT4(result); } Datum *************** *** 819,825 **** { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); ! double result; if (arg2 == 0.0) ereport(ERROR, --- 750,756 ---- { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); ! float4 result; if (arg2 == 0.0) ereport(ERROR, *************** *** 827,836 **** errmsg("division by zero"))); /* Do division in float8, then check for overflow */ ! result = (float8) arg1 / (float8) arg2; ! CheckFloat4Val(result); ! PG_RETURN_FLOAT4((float4) result); } /* --- 758,767 ---- errmsg("division by zero"))); /* Do division in float8, then check for overflow */ ! result = arg1 / arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0); ! PG_RETURN_FLOAT4(result); } /* *************** *** 848,854 **** result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 779,785 ---- result = arg1 + arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 861,867 **** result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 792,798 ---- result = arg1 - arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 874,880 **** result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 805,812 ---- result = arg1 * arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 892,898 **** result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 824,830 ---- result = arg1 / arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1142,1148 **** { float8 num = PG_GETARG_FLOAT8(0); ! CheckFloat4Val(num); PG_RETURN_FLOAT4((float4) num); } --- 1074,1080 ---- { float8 num = PG_GETARG_FLOAT8(0); ! CHECKFLOATVAL((float4) num, 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"))); --- 1089,1096 ---- 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"))); *************** *** 1174,1188 **** dtoi2(PG_FUNCTION_ARGS) { 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"))); ! result = (int16) rint(num); ! PG_RETURN_INT16(result); } --- 1107,1119 ---- dtoi2(PG_FUNCTION_ARGS) { float8 num = PG_GETARG_FLOAT8(0); ! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); ! PG_RETURN_INT16((int16) rint(num)); } *************** *** 1193,1202 **** i4tod(PG_FUNCTION_ARGS) { int32 num = PG_GETARG_INT32(0); - float8 result; ! result = num; ! PG_RETURN_FLOAT8(result); } --- 1124,1131 ---- i4tod(PG_FUNCTION_ARGS) { int32 num = PG_GETARG_INT32(0); ! PG_RETURN_FLOAT8((float8) num); } *************** *** 1207,1216 **** i2tod(PG_FUNCTION_ARGS) { int16 num = PG_GETARG_INT16(0); - float8 result; ! result = num; ! PG_RETURN_FLOAT8(result); } --- 1136,1143 ---- i2tod(PG_FUNCTION_ARGS) { int16 num = PG_GETARG_INT16(0); ! PG_RETURN_FLOAT8((float8) num); } *************** *** 1221,1235 **** ftoi4(PG_FUNCTION_ARGS) { 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"))); ! result = (int32) rint(num); ! PG_RETURN_INT32(result); } --- 1148,1160 ---- ftoi4(PG_FUNCTION_ARGS) { float4 num = PG_GETARG_FLOAT4(0); ! if (num < INT_MIN || num > INT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); ! PG_RETURN_INT32((int32) rint(num)); } *************** *** 1240,1268 **** ftoi2(PG_FUNCTION_ARGS) { 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"))); ! result = (int16) rint(num); ! PG_RETURN_INT16(result); } /* ! * i4tof - converts an int4 number to a float8 number */ Datum i4tof(PG_FUNCTION_ARGS) { int32 num = PG_GETARG_INT32(0); - float4 result; ! result = num; ! PG_RETURN_FLOAT4(result); } --- 1165,1189 ---- ftoi2(PG_FUNCTION_ARGS) { float4 num = PG_GETARG_FLOAT4(0); ! if (num < SHRT_MIN || num > SHRT_MAX || isnan(num)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("smallint out of range"))); ! PG_RETURN_INT16((int16) rint(num)); } /* ! * i4tof - converts an int4 number to a float4 number */ Datum i4tof(PG_FUNCTION_ARGS) { int32 num = PG_GETARG_INT32(0); ! PG_RETURN_FLOAT4((float4) num); } *************** *** 1273,1282 **** i2tof(PG_FUNCTION_ARGS) { int16 num = PG_GETARG_INT16(0); - float4 result; ! result = num; ! PG_RETURN_FLOAT4(result); } --- 1194,1201 ---- i2tof(PG_FUNCTION_ARGS) { int16 num = PG_GETARG_INT16(0); ! PG_RETURN_FLOAT4((float4) num); } *************** *** 1395,1405 **** dround(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); - float8 result; - - result = rint(arg1); ! PG_RETURN_FLOAT8(result); } /* --- 1314,1321 ---- dround(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); ! PG_RETURN_FLOAT8(rint(arg1)); } /* *************** *** 1485,1491 **** result = sqrt(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1401,1407 ---- result = sqrt(arg1); ! CHECKFLOATVAL(result, isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1500,1505 **** --- 1416,1422 ---- float8 result; result = cbrt(arg1); + CHECKFLOATVAL(result, isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1530,1545 **** */ errno = 0; result = pow(arg1, arg2); ! if (errno != 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); } --- 1447,1458 ---- */ errno = 0; result = pow(arg1, arg2); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1) || 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); } --- 1468,1483 ---- /* * 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"))); ! CHECKFLOATVAL(result, isinf(arg1), false); PG_RETURN_FLOAT8(result); } *************** *** 1598,1604 **** result = log(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1506,1512 ---- result = log(arg1); ! CHECKFLOATVAL(result, isinf(arg1), arg1 == 1); PG_RETURN_FLOAT8(result); } *************** *** 1628,1634 **** result = log10(arg1); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1536,1542 ---- result = log10(arg1); ! CHECKFLOATVAL(result, 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); } --- 1552,1563 ---- errno = 0; result = acos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, 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); } --- 1573,1584 ---- errno = 0; result = asin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, 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); } --- 1594,1605 ---- errno = 0; result = atan(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1), true); 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); } --- 1616,1627 ---- errno = 0; result = atan2(arg1, arg2); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); 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); } --- 1637,1648 ---- errno = 0; result = cos(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, 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); } --- 1658,1670 ---- 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; ! CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */, 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); } --- 1680,1691 ---- errno = 0; result = sin(arg1); ! if (errno != 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, 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); } --- 1710,1716 ---- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); ! CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */, true); PG_RETURN_FLOAT8(result); } *************** *** 1846,1852 **** result = arg1 * (180.0 / M_PI); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1726,1732 ---- result = arg1 * (180.0 / M_PI); ! CHECKFLOATVAL(result, isinf(arg1), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 1872,1878 **** result = arg1 * (M_PI / 180.0); ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 1752,1758 ---- result = arg1 * (M_PI / 180.0); ! CHECKFLOATVAL(result, 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 --- 1843,1852 ---- N += 1.0; sumX += newval; + CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true); sumX2 += newval * newval; ! CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || 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 --- 1881,1904 ---- float4_accum(PG_FUNCTION_ARGS) { ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); ! /* do computations as float8 */ ! 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; + CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true); sumX2 += newval * newval; ! CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || 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 **** --- 1969,1975 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2116,2121 **** --- 1998,2004 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2144,2149 **** --- 2027,2033 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2172,2177 **** --- 2056,2062 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numerator, isinf(sumX2) || 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 --- 2105,2121 ---- N += 1.0; sumX += newvalX; + CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true); sumX2 += newvalX * newvalX; + CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true); sumY += newvalY; + CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true); sumY2 += newvalY * newvalY; + CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true); sumXY += newvalX * newvalY; ! CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) || ! 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 **** --- 2173,2179 ---- PG_RETURN_NULL(); numerator = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2310,2315 **** --- 2202,2208 ---- PG_RETURN_NULL(); numerator = N * sumY2 - sumY * sumY; + CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true); /* Watch out for roundoff error producing a negative numerator */ if (numerator <= 0.0) *************** *** 2340,2345 **** --- 2233,2240 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); /* A negative result is valid here */ *************** *** 2406,2411 **** --- 2301,2308 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); PG_RETURN_FLOAT8(numerator / (N * N)); } *************** *** 2432,2437 **** --- 2329,2336 ---- PG_RETURN_NULL(); numerator = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); PG_RETURN_FLOAT8(numerator / (N * (N - 1.0))); } *************** *** 2464,2471 **** --- 2363,2374 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true); numeratorY = N * sumY2 - sumY * sumY; + CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true); numeratorXY = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); if (numeratorX <= 0 || numeratorY <= 0) PG_RETURN_NULL(); *************** *** 2501,2508 **** --- 2404,2415 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true); numeratorY = N * sumY2 - sumY * sumY; + CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true); numeratorXY = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); if (numeratorX <= 0) PG_RETURN_NULL(); /* per spec, horizontal line produces 1.0 */ *************** *** 2538,2544 **** --- 2445,2454 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true); numeratorXY = N * sumXY - sumX * sumY; + CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) || + isinf(sumY), true); if (numeratorX <= 0) PG_RETURN_NULL(); *************** *** 2570,2576 **** --- 2480,2489 ---- PG_RETURN_NULL(); numeratorX = N * sumX2 - sumX * sumX; + CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true); numeratorXXY = sumY * sumX2 - sumX * sumXY; + CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) || + isinf(sumX) || isinf(sumXY), true); if (numeratorX <= 0) PG_RETURN_NULL(); *************** *** 2598,2604 **** float8 result; result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2511,2517 ---- float8 result; result = arg1 + arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2610,2616 **** float8 result; result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2523,2529 ---- float8 result; result = arg1 - arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2622,2628 **** float8 result; result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2535,2542 ---- float8 result; result = arg1 * arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 2639,2645 **** errmsg("division by zero"))); result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2553,2559 ---- errmsg("division by zero"))); result = arg1 / arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0); PG_RETURN_FLOAT8(result); } *************** *** 2658,2664 **** result = arg1 + arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2572,2578 ---- result = arg1 + arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2671,2677 **** result = arg1 - arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2585,2591 ---- result = arg1 - arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); PG_RETURN_FLOAT8(result); } *************** *** 2684,2690 **** result = arg1 * arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2598,2605 ---- result = arg1 * arg2; ! CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), ! arg1 == 0 || arg2 == 0); PG_RETURN_FLOAT8(result); } *************** *** 2702,2708 **** result = arg1 / arg2; ! CheckFloat8Val(result); PG_RETURN_FLOAT8(result); } --- 2617,2623 ---- result = arg1 / arg2; ! CHECKFLOATVAL(result, isinf(arg1) || 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 30 Dec 2006 18:19:57 -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-exp-three-digits.out =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/expected/float4-exp-three-digits.out,v retrieving revision 1.7 diff -c -c -r1.7 float4-exp-three-digits.out *** src/test/regress/expected/float4-exp-three-digits.out 7 Apr 2005 01:51:40 -0000 1.7 --- src/test/regress/expected/float4-exp-three-digits.out 30 Dec 2006 18:19:59 -0000 *************** *** 8,20 **** INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); ERROR: type "real" value out of range: underflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); ERROR: type "real" value out of range: underflow -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES (''); --- 8,20 ---- INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e50'); ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e50'); ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-50'); ERROR: type "real" value out of range: underflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-50'); ERROR: type "real" value out of range: underflow -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES (''); 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 30 Dec 2006 18:19:59 -0000 *************** *** 8,21 **** INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); ! ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); ! ERROR: type "real" value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); ! ERROR: type "real" value out of range: underflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); ! ERROR: type "real" value out of range: underflow -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES (''); ERROR: invalid input syntax for type real: "" --- 8,21 ---- INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e50'); ! ERROR: value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e50'); ! ERROR: value out of range: overflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-50'); ! ERROR: value out of range: underflow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-50'); ! ERROR: value out of range: underflow -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES (''); ERROR: invalid input syntax for type real: "" *************** *** 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 30 Dec 2006 18:19:59 -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? ---------- *************** *** 342,356 **** SET f1 = FLOAT8_TBL.f1 * '-1' WHERE FLOAT8_TBL.f1 > '0.0'; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; ! ERROR: type "double precision" value out of range: overflow SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; ! ERROR: result is out of range SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; ERROR: cannot take logarithm of zero 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; --- 346,360 ---- SET f1 = FLOAT8_TBL.f1 * '-1' WHERE FLOAT8_TBL.f1 > '0.0'; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; ! ERROR: value out of range: overflow SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; ! ERROR: value out of range: overflow SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; ERROR: cannot take logarithm of zero 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: 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; Index: src/test/regress/sql/float4.sql =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/sql/float4.sql,v retrieving revision 1.8 diff -c -c -r1.8 float4.sql *** src/test/regress/sql/float4.sql 7 Apr 2005 01:51:41 -0000 1.8 --- src/test/regress/sql/float4.sql 30 Dec 2006 18:19:59 -0000 *************** *** 11,20 **** INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES (''); --- 11,20 ---- INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); -- test for over and under flow ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e50'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e50'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-50'); ! INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-50'); -- bad input INSERT INTO FLOAT4_TBL(f1) VALUES ('');
Applied. --------------------------------------------------------------------------- Bruce Momjian wrote: > Tom Lane wrote: > > Bruce Momjian <bruce@momjian.us> writes: > > > OK, are you saying that there is a signal we are ignoring for > > > overflow/underflow, or that we should just silently overflow/underflow > > > and not throw an error? > > > > Silent underflow is fine with me; it's the norm in most all float > > implementations and won't surprise anyone. For overflow I'm OK with > > either returning infinity or throwing an error --- but if an error, > > it should only be about inf-out-with-non-inf-in, not comparisons to any > > artificial MAX/MIN values. > > OK, I am happy to remove the MIN/MAX comparisons. Those were in the > original code. > > The attached, updated patch creates a single CHECKFLOATVAL() macro that > does the overflow/underflow comparisons and throws an error. This also > reduces the isinf() calls. Should I be concerned we are now duplicating > the error text in all call sites? > > Regression wording modified now that float4/float8 checks are merged. I > haven't update the platform-specific float* expected files yet, but will > on commit. > > -- > Bruce Momjian bruce@momjian.us > EnterpriseDB http://www.enterprisedb.com > > + If your life is a hard drive, Christ can be your backup. + > > ---------------------------(end of broadcast)--------------------------- > TIP 2: Don't 'kill -9' the postmaster -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
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.