mirror of
https://github.com/postgres/postgres.git
synced 2025-12-19 17:02:53 +03:00
Extend int128.h to support more numeric code.
This adds a few more functions to int128.h, allowing more of numeric.c to use 128-bit integers on all platforms. Specifically, int64_div_fast_to_numeric() and the following aggregate functions can now use 128-bit integers for improved performance on all platforms, rather than just platforms with native support for int128: - SUM(int8) - AVG(int8) - STDDEV_POP(int2 or int4) - STDDEV_SAMP(int2 or int4) - VAR_POP(int2 or int4) - VAR_SAMP(int2 or int4) In addition to improved performance on platforms lacking native 128-bit integer support, this significantly simplifies this numeric code by allowing a lot of conditionally compiled code to be deleted. A couple of numeric functions (div_var_int64() and sqrt_var()) still contain conditionally compiled 128-bit integer code that only works on platforms with native 128-bit integer support. Making those work more generally would require rolling our own higher precision 128-bit division, which isn't supported for now. Author: Dean Rasheed <dean.a.rasheed@gmail.com> Reviewed-by: John Naylor <johncnaylorls@gmail.com> Discussion: https://postgr.es/m/CAEZATCWgBMc9ZwKMYqQpaQz2X6gaamYRB+RnMsUNcdMcL2Mj_w@mail.gmail.com
This commit is contained in:
@@ -93,8 +93,13 @@ main(int argc, char **argv)
|
||||
int64 x = pg_prng_uint64(&pg_global_prng_state);
|
||||
int64 y = pg_prng_uint64(&pg_global_prng_state);
|
||||
int64 z = pg_prng_uint64(&pg_global_prng_state);
|
||||
int64 w = pg_prng_uint64(&pg_global_prng_state);
|
||||
int32 z32 = (int32) z;
|
||||
test128 t1;
|
||||
test128 t2;
|
||||
test128 t3;
|
||||
int32 r1;
|
||||
int32 r2;
|
||||
|
||||
/* check unsigned addition */
|
||||
t1.hl.hi = x;
|
||||
@@ -126,25 +131,111 @@ main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check multiplication */
|
||||
t1.i128 = (int128) x * (int128) y;
|
||||
|
||||
t2.hl.hi = t2.hl.lo = 0;
|
||||
int128_add_int64_mul_int64(&t2.I128, x, y);
|
||||
/* check 128-bit signed addition */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2 = t1;
|
||||
t3.hl.hi = z;
|
||||
t3.hl.lo = w;
|
||||
t1.i128 += t3.i128;
|
||||
int128_add_int128(&t2.I128, t3.I128);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf("%016" PRIx64 " * %016" PRIx64 "\n", x, y);
|
||||
printf(INT128_HEX_FORMAT " + " INT128_HEX_FORMAT "\n", x, y, z, w);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check unsigned subtraction */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2 = t1;
|
||||
t1.i128 -= (int128) (uint64) z;
|
||||
int128_sub_uint64(&t2.I128, (uint64) z);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " - unsigned %016" PRIx64 "\n", x, y, z);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check signed subtraction */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2 = t1;
|
||||
t1.i128 -= (int128) z;
|
||||
int128_sub_int64(&t2.I128, z);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " - signed %016" PRIx64 "\n", x, y, z);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check 64x64-bit multiply-add */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2 = t1;
|
||||
t1.i128 += (int128) z * (int128) w;
|
||||
int128_add_int64_mul_int64(&t2.I128, z, w);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " + %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check 64x64-bit multiply-subtract */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2 = t1;
|
||||
t1.i128 -= (int128) z * (int128) w;
|
||||
int128_sub_int64_mul_int64(&t2.I128, z, w);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " - %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check 128/32-bit division */
|
||||
t3.hl.hi = x;
|
||||
t3.hl.lo = y;
|
||||
t1.i128 = t3.i128 / z32;
|
||||
r1 = (int32) (t3.i128 % z32);
|
||||
t2 = t3;
|
||||
int128_div_mod_int32(&t2.I128, z32, &r2);
|
||||
|
||||
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " / signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
|
||||
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
|
||||
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
|
||||
return 1;
|
||||
}
|
||||
if (r1 != r2)
|
||||
{
|
||||
printf(INT128_HEX_FORMAT " %% signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
|
||||
printf("native = %08X\n", r1);
|
||||
printf("result = %08X\n", r2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check comparison */
|
||||
t1.hl.hi = x;
|
||||
t1.hl.lo = y;
|
||||
t2.hl.hi = z;
|
||||
t2.hl.lo = pg_prng_uint64(&pg_global_prng_state);
|
||||
t2.hl.lo = w;
|
||||
|
||||
if (my_int128_compare(t1.i128, t2.i128) !=
|
||||
int128_compare(t1.I128, t2.I128))
|
||||
|
||||
@@ -680,6 +680,25 @@ SELECT sum2(q1,q2) FROM int8_tbl;
|
||||
18271560493827981
|
||||
(1 row)
|
||||
|
||||
-- sanity checks
|
||||
SELECT sum(q1+q2), sum(q1)+sum(q2) FROM int8_tbl;
|
||||
sum | ?column?
|
||||
-------------------+-------------------
|
||||
18271560493827981 | 18271560493827981
|
||||
(1 row)
|
||||
|
||||
SELECT sum(q1-q2), sum(q2-q1), sum(q1)-sum(q2) FROM int8_tbl;
|
||||
sum | sum | ?column?
|
||||
------------------+-------------------+------------------
|
||||
9135780246913245 | -9135780246913245 | 9135780246913245
|
||||
(1 row)
|
||||
|
||||
SELECT sum(q1*2000), sum(-q1*2000), 2000*sum(q1) FROM int8_tbl;
|
||||
sum | sum | ?column?
|
||||
----------------------+-----------------------+----------------------
|
||||
27407340740741226000 | -27407340740741226000 | 27407340740741226000
|
||||
(1 row)
|
||||
|
||||
-- test for outer-level aggregates
|
||||
-- this should work
|
||||
select ten, sum(distinct four) from onek a
|
||||
|
||||
@@ -182,6 +182,11 @@ SELECT newcnt(*) AS cnt_1000 FROM onek;
|
||||
SELECT oldcnt(*) AS cnt_1000 FROM onek;
|
||||
SELECT sum2(q1,q2) FROM int8_tbl;
|
||||
|
||||
-- sanity checks
|
||||
SELECT sum(q1+q2), sum(q1)+sum(q2) FROM int8_tbl;
|
||||
SELECT sum(q1-q2), sum(q2-q1), sum(q1)-sum(q2) FROM int8_tbl;
|
||||
SELECT sum(q1*2000), sum(-q1*2000), 2000*sum(q1) FROM int8_tbl;
|
||||
|
||||
-- test for outer-level aggregates
|
||||
|
||||
-- this should work
|
||||
|
||||
Reference in New Issue
Block a user