Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jw9Zr-00020n-U4 for pgsql-hackers@arkaria.postgresql.org; Thu, 16 Jul 2020 19:29:55 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1jw9Zp-0006bx-Cr for pgsql-hackers@arkaria.postgresql.org; Thu, 16 Jul 2020 19:29:53 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jw9Zp-0006bq-6O for pgsql-hackers@lists.postgresql.org; Thu, 16 Jul 2020 19:29:53 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jw9Zm-00057Z-Q3 for pgsql-hackers@lists.postgresql.org; Thu, 16 Jul 2020 19:29:52 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 06GJTjNj3421747; Thu, 16 Jul 2020 15:29:45 -0400 From: Tom Lane To: pgsql-hackers@lists.postgresql.org cc: Dean Rasheed , Andres Freund Subject: NaN divided by zero should yield NaN MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <3421683.1594927686.0@sss.pgh.pa.us> Date: Thu, 16 Jul 2020 15:29:45 -0400 Message-ID: <3421746.1594927785@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <3421683.1594927686.1@sss.pgh.pa.us> Dean Rasheed questioned this longstanding behavior: regression=# SELECT 'nan'::float8 / '0'::float8; ERROR: division by zero After a bit of research I think he's right: per IEEE 754 this should yield NaN, not an error. Accordingly I propose the attached patch. This is probably not something to back-patch, though. One thing that's not very clear to me is which of these spellings is preferable: if (unlikely(val2 == 0.0) && !isnan(val1)) if (unlikely(val2 == 0.0 && !isnan(val1))) I think we can reject this variant: if (unlikely(val2 == 0.0) && unlikely(!isnan(val1))) since actually the second condition *is* pretty likely. But I don't know which of the first two would give better code. Andres, any thoughts? regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="nan-over-zero-is-nan.patch"; charset="us-ascii" Content-ID: <3421683.1594927686.2@sss.pgh.pa.us> Content-Description: nan-over-zero-is-nan.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 8d4bbc51a6..e2aae8ef17 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -222,7 +222,7 @@ float4_div(const float4 val1, const float4 val2) { float4 result; = - if (unlikely(val2 =3D=3D 0.0f)) + if (unlikely(val2 =3D=3D 0.0f) && !isnan(val1)) float_zero_divide_error(); result =3D val1 / val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) @@ -238,7 +238,7 @@ float8_div(const float8 val1, const float8 val2) { float8 result; = - if (unlikely(val2 =3D=3D 0.0)) + if (unlikely(val2 =3D=3D 0.0) && !isnan(val1)) float_zero_divide_error(); result =3D val1 / val2; if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/t= est/regress/expected/float4-misrounded-input.out index 6c89af6394..38b847a1ad 100644 --- a/src/test/regress/expected/float4-misrounded-input.out +++ b/src/test/regress/expected/float4-misrounded-input.out @@ -143,6 +143,12 @@ SELECT 'nan'::float4 / 'nan'::float4; NaN (1 row) = +SELECT 'nan'::float4 / '0'::float4; + ?column? = +---------- + NaN +(1 row) + SELECT 'nan'::numeric::float4; float4 = -------- diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expec= ted/float4.out index d6c22c1752..310402b6ee 100644 --- a/src/test/regress/expected/float4.out +++ b/src/test/regress/expected/float4.out @@ -143,6 +143,12 @@ SELECT 'nan'::float4 / 'nan'::float4; NaN (1 row) = +SELECT 'nan'::float4 / '0'::float4; + ?column? = +---------- + NaN +(1 row) + SELECT 'nan'::numeric::float4; float4 = -------- diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expec= ted/float8.out index c635dd7dcb..2304b579d2 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -126,6 +126,12 @@ SELECT 'nan'::float8 / 'nan'::float8; NaN (1 row) = +SELECT 'nan'::float8 / '0'::float8; + ?column? = +---------- + NaN +(1 row) + SELECT 'nan'::numeric::float8; float8 = -------- diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4= .sql index 393d98fb14..1fcf823c21 100644 --- a/src/test/regress/sql/float4.sql +++ b/src/test/regress/sql/float4.sql @@ -50,6 +50,7 @@ SELECT ' INFINITY x'::float4; SELECT 'Infinity'::float4 + 100.0; SELECT 'Infinity'::float4 / 'Infinity'::float4; SELECT 'nan'::float4 / 'nan'::float4; +SELECT 'nan'::float4 / '0'::float4; SELECT 'nan'::numeric::float4; = SELECT '' AS five, * FROM FLOAT4_TBL; diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8= .sql index 288969aed6..f103871cdb 100644 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -43,6 +43,7 @@ SELECT ' INFINITY x'::float8; SELECT 'Infinity'::float8 + 100.0; SELECT 'Infinity'::float8 / 'Infinity'::float8; SELECT 'nan'::float8 / 'nan'::float8; +SELECT 'nan'::float8 / '0'::float8; SELECT 'nan'::numeric::float8; = SELECT '' AS five, * FROM FLOAT8_TBL; ------- =_aaaaaaaaaa0--