Hi Fabien, Thanks for the review. I've fixed the documentation and added an ipow function that handles both positive and negative ints, having 0^0 == 1 and 0^(negative) == PG_INT64_MAX since that's what my glibc math.h pow() is returning.
On Sat, Nov 4, 2017 at 12:34 PM, Fabien COELHO <coe...@cri.ensmp.fr> wrote: > > Hello Raúl, > > Sorry about the patch. Attaching it now so it can be considered as >> submitted. >> > > There is a typo in the XML doc: > > <literal>1024.0/<literal> > > Please check that the documentation compiles. > > I'm at odds with having the integer version rely on a double pow(), even > if it works. I think that there should be a specific integer version which > does use integer operations. From stack overflow, the following is > suggested: > > int ipow(int base, int exp) > { > int result = 1; > while (exp) > { > if (exp & 1) > result *= base; > exp >>= 1; > base *= base; > } > > return result; > } > > The integer version should be when x & y are integers *AND* y >= 0. > > if y is a negative integer, the double version should be used. > > -- > Fabien. -- *Raúl Marín Rodríguez*carto.com
From 09105f8108e439834510ee5fb53036473f2977d5 Mon Sep 17 00:00:00 2001 From: Raul Marin <rmrodrig...@cartodb.com> Date: Fri, 13 Oct 2017 17:42:23 +0200 Subject: [PATCH] Add pow() support to pgbench --- doc/src/sgml/ref/pgbench.sgml | 7 ++++ src/bin/pgbench/exprparse.y | 3 ++ src/bin/pgbench/pgbench.c | 54 ++++++++++++++++++++++++++++ src/bin/pgbench/pgbench.h | 3 +- src/bin/pgbench/t/001_pgbench_with_server.pl | 9 +++++ 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/pgbench.sgml b/doc/src/sgml/ref/pgbench.sgml index 1f55967e40a..4e7f75ddf87 100644 --- a/doc/src/sgml/ref/pgbench.sgml +++ b/doc/src/sgml/ref/pgbench.sgml @@ -1233,6 +1233,13 @@ pgbench <optional> <replaceable>options</replaceable> </optional> <replaceable>d <entry><literal>sqrt(2.0)</literal></entry> <entry><literal>1.414213562</literal></entry> </row> + <row> + <entry><literal><function>pow(<replaceable>x</replaceable>, <replaceable>y</replaceable>)</function></literal></entry> + <entry>double if <replaceable>x</replaceable> or <replaceable>y</replaceable> are doubles, else integer</entry> + <entry>Numeric exponentiation</entry> + <entry><literal>pow(2.0, 10)</literal></entry> + <entry><literal>1024.0</literal></entry> + </row> </tbody> </tgroup> </table> diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y index 770be981f06..290bca99d12 100644 --- a/src/bin/pgbench/exprparse.y +++ b/src/bin/pgbench/exprparse.y @@ -334,6 +334,9 @@ static const struct { "!case_end", -2, PGBENCH_CASE }, + { + "pow", 2, PGBENCH_POW + }, /* keep as last array element */ { NULL, 0, 0 diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index add653bf90c..bdf3e97682a 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -739,6 +739,51 @@ getPoissonRand(TState *thread, int64 center) } /* + * pow() for integer values + */ +static int64 +ipow(int64 base, int64 exp) +{ + int64 result; + + if (base == 0) + { + if (exp > 0) + return 0; + else if (exp == 0) + return 1; + return PG_INT64_MAX; + } + + /* + * For exp > 0 calculate normally + * For exp == 0 return 1 * sign of base + * For exp < 0 return 0 except when the base is 1 or -1 + */ + if (exp > 0) + { + result = 1; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + } + else if (exp == 0) + result = (base > 0) - (base < 0); + else + { + result = 1 / base; + if (exp % 2 == 0) + result *= result; + } + + return result; +} + +/* * Initialize the given SimpleStats struct to all zeroes */ static void @@ -1474,6 +1519,7 @@ evalFunc(TState *thread, CState *st, case PGBENCH_NE: case PGBENCH_LE: case PGBENCH_LT: + case PGBENCH_POW: { PgBenchValue *lval = &vargs[0], *rval = &vargs[1]; @@ -1525,6 +1571,10 @@ evalFunc(TState *thread, CState *st, setBoolValue(retval, ld < rd); return true; + case PGBENCH_POW: + setDoubleValue(retval, pow(ld, rd)); + return true; + default: /* cannot get here */ Assert(0); @@ -1602,6 +1652,10 @@ evalFunc(TState *thread, CState *st, return true; + case PGBENCH_POW: + setIntValue(retval, ipow(li, ri)); + return true; + default: /* cannot get here */ Assert(0); diff --git a/src/bin/pgbench/pgbench.h b/src/bin/pgbench/pgbench.h index e1277a1dde6..9f26af92bf6 100644 --- a/src/bin/pgbench/pgbench.h +++ b/src/bin/pgbench/pgbench.h @@ -94,7 +94,8 @@ typedef enum PgBenchFunction PGBENCH_LE, PGBENCH_LT, PGBENCH_IS, - PGBENCH_CASE + PGBENCH_CASE, + PGBENCH_POW } PgBenchFunction; typedef struct PgBenchExpr PgBenchExpr; diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl index 8e19bbd3f45..c5ecd749c40 100644 --- a/src/bin/pgbench/t/001_pgbench_with_server.pl +++ b/src/bin/pgbench/t/001_pgbench_with_server.pl @@ -237,6 +237,10 @@ sub pgbench qr{command=36.: int 36\b}, qr{command=37.: boolean true\b}, qr{command=38.: boolean true\b}, + qr{command=44.: int -27\b}, + qr{command=45.: double 1024\b}, + qr{command=46.: int 0\b}, + qr{command=47.: double -0.125\b}, ], 'pgbench expressions', { '001_pgbench_expressions' => q{-- integer functions @@ -299,6 +303,11 @@ sub pgbench \set v2 5432 \set v3 -54.21E-2 SELECT :v0, :v1, :v2, :v3; +--- pow() operator +\set poweri debug(pow(-3,3)) +\set powerd debug(pow(2.0,10)) +\set powernegi debug(pow(-2,-3)) +\set powernegd debug(pow(-2.0,-3.0)) } }); =head
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers