From a0fad9762a22e739de69c85b51ff7a47e672732f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 4 Apr 2008 18:45:36 +0000 Subject: Re-implement division for numeric values using the traditional "schoolbook" algorithm. This is a good deal slower than our old roundoff-error-prone code for long inputs, so we keep the old code for use in the transcendental functions, where everything is approximate anyway. Also create a user-accessible function div(numeric, numeric) to provide access to the exact result of trunc(x/y) --- since the regular numeric / operator will round off its result, simply computing that expression in SQL doesn't reliably give the desired answer. This fixes bug #3387 and various related corner cases, and improves the usefulness of PG for high-precision integer arithmetic. --- src/test/regress/expected/numeric.out | 81 +++++++++++++++++++++++++++++++++++ src/test/regress/sql/numeric.sql | 18 ++++++++ 2 files changed, 99 insertions(+) (limited to 'src/test') diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index 7840990bf7d..1c5047455e8 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -1260,3 +1260,84 @@ SELECT * FROM num_input_test; -555.50 (5 rows) +-- +-- Test some corner cases for division +-- +select 999999999999999999999::numeric/1000000000000000000000; + ?column? +------------------------ + 1.00000000000000000000 +(1 row) + +select div(999999999999999999999::numeric,1000000000000000000000); + div +----- + 0 +(1 row) + +select mod(999999999999999999999::numeric,1000000000000000000000); + mod +----------------------- + 999999999999999999999 +(1 row) + +select div(-9999999999999999999999::numeric,1000000000000000000000); + div +----- + -9 +(1 row) + +select mod(-9999999999999999999999::numeric,1000000000000000000000); + mod +------------------------ + -999999999999999999999 +(1 row) + +select div(-9999999999999999999999::numeric,1000000000000000000000)*1000000000000000000000 + mod(-9999999999999999999999::numeric,1000000000000000000000); + ?column? +------------------------- + -9999999999999999999999 +(1 row) + +select mod (70.0,70) ; + mod +----- + 0.0 +(1 row) + +select div (70.0,70) ; + div +----- + 1 +(1 row) + +select 70.0 / 70 ; + ?column? +------------------------ + 1.00000000000000000000 +(1 row) + +select 12345678901234567890 % 123; + ?column? +---------- + 78 +(1 row) + +select 12345678901234567890 / 123; + ?column? +-------------------- + 100371373180768845 +(1 row) + +select div(12345678901234567890, 123); + div +-------------------- + 100371373180768844 +(1 row) + +select div(12345678901234567890, 123) * 123 + 12345678901234567890 % 123; + ?column? +---------------------- + 12345678901234567890 +(1 row) + diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index dc1452f9ef0..9fd6bba31ee 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -805,3 +805,21 @@ INSERT INTO num_input_test(n1) VALUES (''); INSERT INTO num_input_test(n1) VALUES (' N aN '); SELECT * FROM num_input_test; + +-- +-- Test some corner cases for division +-- + +select 999999999999999999999::numeric/1000000000000000000000; +select div(999999999999999999999::numeric,1000000000000000000000); +select mod(999999999999999999999::numeric,1000000000000000000000); +select div(-9999999999999999999999::numeric,1000000000000000000000); +select mod(-9999999999999999999999::numeric,1000000000000000000000); +select div(-9999999999999999999999::numeric,1000000000000000000000)*1000000000000000000000 + mod(-9999999999999999999999::numeric,1000000000000000000000); +select mod (70.0,70) ; +select div (70.0,70) ; +select 70.0 / 70 ; +select 12345678901234567890 % 123; +select 12345678901234567890 / 123; +select div(12345678901234567890, 123); +select div(12345678901234567890, 123) * 123 + 12345678901234567890 % 123; -- cgit v1.2.3