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

Reply via email to