From 332ea60d2378ef8d567c93502fa7b95eccd962e5 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 24 Apr 2006 20:36:32 +0000
Subject: [PATCH] Improve our private implementation of cbrt() to give results
 of the accuracy expected by the regression tests.  Per suggestion from
 Martijn van Oosterhout.

---
 src/backend/utils/adt/float.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 3382b86ba0d..b5147c9aa45 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.123 2006/03/11 01:19:22 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.124 2006/04/24 20:36:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2373,11 +2373,22 @@ float84ge(PG_FUNCTION_ARGS)
 /* ========== PRIVATE ROUTINES ========== */
 
 #ifndef HAVE_CBRT
+
 static double
 cbrt(double x)
 {
 	int			isneg = (x < 0.0);
-	double		tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
+	double		absx = fabs(x);
+	double		tmpres = pow(absx, (double) 1.0 / (double) 3.0);
+
+	/*
+	 * The result is somewhat inaccurate --- not really pow()'s fault,
+	 * as the exponent it's handed contains roundoff error.  We can improve
+	 * the accuracy by doing one iteration of Newton's formula.  Beware of
+	 * zero input however.
+	 */
+	if (tmpres > 0.0)
+		tmpres -= (tmpres - absx/(tmpres*tmpres)) / (double) 3.0;
 
 	return isneg ? -tmpres : tmpres;
 }
-- 
GitLab