test-rscale.sql
application/sql
Filename: test-rscale.sql
Type: application/sql
Part: 0
-- Create 2 random numeric values whose product has
--
-- 1. n random decimal digits, followed by
-- 2. '5' followed by z '0' decimal digits, followed by
-- 3. m more random decimal digits
-- 4. a decimal weight w
CREATE OR REPLACE FUNCTION mul_var_rscale_test_vals(IN n int,
IN z int,
IN m int,
IN w int,
OUT x numeric,
OUT y numeric)
AS
$$
DECLARE
len int;
res_str text;
res numeric;
xlen int;
ylen int;
rw int;
xweight int;
yweight int;
BEGIN
len := n + z + m + 1;
res_str := random(('1e'||(n-1))::numeric, ('1e'||n)::numeric-1)::text
|| '5' || repeat('0', z)
|| random(('1e'||(m-1))::numeric, ('1e'||m)::numeric-1)::text
|| repeat('0', len);
res := res_str::numeric;
xlen := len + random(-m/2, m/2);
ylen := 2*len - xlen;
x := random(('1e'||(xlen-1))::numeric, ('1e'||xlen)::numeric-1);
y := trunc(ceil(res / x));
rw := greatest(20, abs(w));
xweight := w/2 + random(-rw, rw);
x := x * ('1e'||(xweight-xlen))::numeric;
yweight := w - xweight + 1;
y := y * ('1e'||(yweight-ylen))::numeric;
END
$$
LANGUAGE plpgsql;
SELECT setseed(0);
CREATE TEMP TABLE results AS
WITH t1(n, z, m, w) AS (
SELECT random(1,20), 5, random(1,8), random(-20,0)
FROM generate_series(1,1000000)
), t2 AS (
SELECT t1.*, x, y, x*y AS prod
FROM t1, LATERAL mul_var_rscale_test_vals(n, z, m, w)
)
SELECT n, z, m, w, x, y,
round(prod, n-w-1) AS expected,
numeric_mul_rscale(x, y, n-w-1-scale(prod)) FROM t2;
CREATE TEMP TABLE diffs AS
SELECT * FROM results WHERE numeric_mul_rscale != expected;
SELECT count(*) FROM diffs;
SELECT DISTINCT expected - numeric_mul_rscale FROM diffs;
\copy diffs to diffs.dump