Обсуждение: Re: [BUGS] BUG #2846: inconsistent and confusing handling of
Roman Kononov wrote: > On 12/27/2006 12:44 PM, Bruce Momjian wrote: > > The only unsolved issue is the one with underflow checks. I have added > > comments explaining the problem in case someone ever figures out how to > > address it. > > This will behave better for float4: > > Datum float4pl(PG_FUNCTION_ARGS) > { > --- float4 arg1 = PG_GETARG_FLOAT4(0); > --- float4 arg2 = PG_GETARG_FLOAT4(1); > +++ double arg1 = PG_GETARG_FLOAT4(0); > +++ double arg2 = PG_GETARG_FLOAT4(1); > double result; > > result = arg1 + arg2; > CheckFloat4Val(result,isinf(arg1) || isinf(arg2)); > PG_RETURN_FLOAT4((float4) result); > } Are you sure? As I remember, computation automatically upgrades to 'double'. See this program and output: $ cat tst1.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { float a = 1e30, b = 1e30; double c; c = a * b; printf("%e\n", c); return 0; } $ tst1 1.000000e+60 -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
On 12/27/2006 03:23 PM, Bruce Momjian wrote: > Are you sure? As I remember, computation automatically upgrades to > 'double'. See this program and output: This is platform- and compiler- dependent: ~>uname -a Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux ~>gcc --version gcc (GCC) 4.3.0 20061213 (experimental) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ~>cat test.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { float a = 1e30, b = 1e30; double c; c = a * b; printf("%e\n", c); return 0; } ~>gcc test.c ~>./a.out inf ~>gcc -march=i386 -m32 test.c ~>./a.out 1.000000e+60 Roman
Roman Kononov wrote: > On 12/27/2006 03:23 PM, Bruce Momjian wrote: > > Are you sure? As I remember, computation automatically upgrades to > > 'double'. See this program and output: > > This is platform- and compiler- dependent: > > ~>uname -a > Linux rklinux 2.6.15-27-amd64-generic #1 SMP PREEMPT Fri Dec 8 17:50:54 UTC 2006 x86_64 GNU/Linux > ~>gcc --version > gcc (GCC) 4.3.0 20061213 (experimental) > Copyright (C) 2006 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There is NO > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > > ~>cat test.c > #include <stdio.h> > #include <stdlib.h> > > int > main(int argc, char *argv[]) > { > float a = 1e30, b = 1e30; > double c; > > c = a * b; > > printf("%e\n", c); > return 0; > } > ~>gcc test.c > ~>./a.out > inf > ~>gcc -march=i386 -m32 test.c > ~>./a.out > 1.000000e+60 Interesting. I didn't know that, but in the float4pl() function, because the overflow tests and result is float4, what value is there to doing things as double --- as soon as the float4 maximum is exceeded, we throw an error? -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
On 12/27/2006 04:04 PM, Bruce Momjian wrote: > Interesting. I didn't know that, but in the float4pl() function, > because the overflow tests and result is float4, what value is there to > doing things as double --- as soon as the float4 maximum is exceeded, we > throw an error? > This is useful for underflows. float a=1e-30; float b=1e-30; double r1=a*b; double r2=(double)a*b; r1 is zero and underflow is lost. r2 is not zero and underflow is detected. In float4mul() and float4div(), the computation should be double precision. In float4pl() and float4mi(), it depends on the ability of the hardware to generate denormalized numbers. If denormalized numbers are generated, float vs double makes no difference. If denormalized numbers are not generated (zero is generated), then double computation is safer. Another way to detect underflows, overflows and other junk is to use FPU status flags after each computation. Performance will likely suffer. #include <fenv.h> Datum float4mul(PG_FUNCTION_ARGS) { float4 arg1 = PG_GETARG_FLOAT4(0); float4 arg2 = PG_GETARG_FLOAT4(1); float4 result; int fe_exceptions; feclearexcept(FE_ALL_EXCEPT); result = arg1 * arg2; fe_exceptions=fetestexcept(FE_DIVBYZERO,FE_INVALID,FE_OVERFLOW,FE_UNDERFLOW); if (fe_exceptions) handle_exceptions(fe_exceptions); //?? PG_RETURN_FLOAT4(result); } Yet another way to detect exceptions is to remove all CheckFloat4Val(), CheckFloat8Val(), isnan(), unmask FPU exceptions and install an exception handler. Might have portability difficulties. Comparisons of NaNs must be done in non-IEEE way (FPU does not compare NaNs, it generates exceptions). Roman
Roman Kononov <kononov195-pgsql@yahoo.com> writes: > On 12/27/2006 03:23 PM, Bruce Momjian wrote: >> Are you sure? As I remember, computation automatically upgrades to >> 'double'. See this program and output: > This is platform- and compiler- dependent: ... and probably irrelevant, too. We should store the result into a float4 variable and then test for isinf() on that; that eliminates the question of whether the compiler did the multiply in a wider format or not. regards, tom lane
Roman Kononov <kononov195-pgsql@yahoo.com> writes: > In float4mul() and float4div(), the computation should be double precision. Why? It's going to have to fit in a float4 eventually anyway. regards, tom lane
On 12/27/2006 05:19 PM, Tom Lane wrote: > Roman Kononov <kononov195-pgsql@yahoo.com> writes: >> On 12/27/2006 03:23 PM, Bruce Momjian wrote: >>> Are you sure? As I remember, computation automatically upgrades to >>> 'double'. See this program and output: > >> This is platform- and compiler- dependent: > > ... and probably irrelevant, too. We should store the result into a > float4 variable and then test for isinf() on that; that eliminates the > question of whether the compiler did the multiply in a wider format or > not. You are right provided that you want to ignore underflows and silently produce zeros instead. If you go this way, I recommend to ignore overflows as well, and silently produce infinities and NaNs. Roman
Tom Lane wrote: > Roman Kononov <kononov195-pgsql@yahoo.com> writes: > > In float4mul() and float4div(), the computation should be double precision. > > Why? It's going to have to fit in a float4 eventually anyway. One issue is in the patch comment: ! * Computations that slightly exceed FLOAT8_MAX are non-Infinity, ! * but those that greatly exceed FLOAT8_MAX become Infinity. Therefore ! * it is difficult to tell if a value is really infinity or the result ! * of an overflow. The solution is to use a boolean indicating if ! * the input arguments were infiity, meaning an infinite result is ! * probably not the result of an overflow. This allows various ! * computations like SELECT 'Inf'::float8 + 5. + * Underflow has similar issues to overflow, i.e. if a computation is + * slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is + * much smaller than FLOAT8_MIN, the value becomes zero. However, + * unlike overflow, zero is not a special value and can be the result + * of a computation, so there is no easy way to pass a boolean + * indicating whether a zero result is reasonable or not. It might + * be possible for multiplication and division, but because of rounding, + * such tests would probably not be reliable. For overflow, it doesn't matter, but by using float8, you have a much larger range until you underflow to zero. I will make adjustments to the patch to use this, and add comments explaining its purpose. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
Tom Lane wrote: > Roman Kononov <kononov195-pgsql@yahoo.com> writes: > > On 12/27/2006 03:23 PM, Bruce Momjian wrote: > >> Are you sure? As I remember, computation automatically upgrades to > >> 'double'. See this program and output: > > > This is platform- and compiler- dependent: > > ... and probably irrelevant, too. We should store the result into a > float4 variable and then test for isinf() on that; that eliminates the > question of whether the compiler did the multiply in a wider format or > not. True for overflow to Infinity, but underflow checking is better for float4 using float8. See previous email for details. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
Roman Kononov wrote: > On 12/27/2006 05:19 PM, Tom Lane wrote: > > Roman Kononov <kononov195-pgsql@yahoo.com> writes: > >> On 12/27/2006 03:23 PM, Bruce Momjian wrote: > >>> Are you sure? As I remember, computation automatically upgrades to > >>> 'double'. See this program and output: > > > >> This is platform- and compiler- dependent: > > > > ... and probably irrelevant, too. We should store the result into a > > float4 variable and then test for isinf() on that; that eliminates the > > question of whether the compiler did the multiply in a wider format or > > not. > > You are right provided that you want to ignore underflows and silently > produce zeros instead. > > If you go this way, I recommend to ignore overflows as well, and silently > produce infinities and NaNs. While IEEE seems fine with that, I don't think this is good for SQL. It is best to produce a meaningful error. The major issue is that our current code is buggy because it doesn't have consistent behavior, as Roman outlined. -- Bruce Momjian bruce@momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. +