Oops. Resending patches in .txt files.

I’ve also reattached the test file, to which I added a small amount of 
additional testing.

Thanks, David.

From: JonY via Mingw-w64-public<mailto:[email protected]>
Sent: 03 October 2021 04:12
To: 
[email protected]<mailto:[email protected]>
Cc: JonY<mailto:[email protected]>
Subject: Re: [Mingw-w64-public] Patches to fix #515 and 916.

On 10/2/21 5:27 PM, David James wrote:
>
> Hello – I’ve coded some fixed for bugs #515 Incorrect sign output from 
> asinh<https://sourceforge.net/p/mingw-w64/bugs/515/> (which also impacted 
> atanh) and #916 asinh incorrect for large 
> values<https://sourceforge.net/p/mingw-w64/bugs/916/> and attached some patch 
> files. I’m hoping to get these fixes into GHC Haskell (I believe they need to 
> get to msys2 first).
>
> Please could you review / comment?
>
> I’ve also included a file I used for testing the fixes. (I don’t know if this 
> could/should be integrated into any CI testing?)
>
> Please let me know if there are any questions, etc. (It’s the first time I’ve 
> created patch files, so please let me know if I’ve done something wrong).
>
> Thanks!
> David.
>

Looks like SF ate your patches, please resend with the .txt extension,
it may help.



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

From f03ed1372d031e529ae9a2cdaad4db7ea66c95af Mon Sep 17 00:00:00 2001
From: davjam <[email protected]>
Date: Sat, 2 Oct 2021 17:33:26 +0100
Subject: [PATCH 1/3] Fixes asinh,f,l for bugs #515 and #916

ie. fix sign of asinh(-0) and ensure results returned for large values.
---
 mingw-w64-crt/math/x86/asinh.c  | 55 ++++++++++++++++++++++++++++-----
 mingw-w64-crt/math/x86/asinhf.c | 17 +++++-----
 mingw-w64-crt/math/x86/asinhl.c | 16 +++++-----
 3 files changed, 65 insertions(+), 23 deletions(-)

diff --git a/mingw-w64-crt/math/x86/asinh.c b/mingw-w64-crt/math/x86/asinh.c
index 826cc6dee..002aedee8 100644
--- a/mingw-w64-crt/math/x86/asinh.c
+++ b/mingw-w64-crt/math/x86/asinh.c
@@ -5,6 +5,7 @@
  */
 #include <math.h>
 #include <errno.h>
+#include <float.h>
 #include "fastmath.h"
 
  /* asinh(x) = copysign(log(fabs(x) + sqrt(x * x + 1.0)), x) */
@@ -21,13 +22,53 @@ double asinh(double x)
     return x;
 #endif
 
-  /* Use log1p to avoid cancellation with small x. Put
-     x * x in denom, so overflow is harmless. 
-     asinh(x) = log1p (x + sqrt (x * x + 1.0) - 1.0)
-              = log1p (x + x * x / (sqrt (x * x + 1.0) + 1.0))  */
+  /* NB the previous formula
+          z = __fast_log1p (z + z * z / (__fast_sqrt (z * z + 1.0) + 1.0));
+     was defective in two ways:
+     1: It ommitted required brackets:
+          z = __fast_log1p (z + z * (z / (__fast_sqrt (z * z + 1.0) + 1.0)));
+                                    ^                                     ^
+        so would still overflow for large z.
+     2: Even with the brackets, it still degraded quickly for large z
+        (where z*z+1 == z*z).
+        e.g. asinh (sinh 356.0)) gave 355.30685281944005
+    */
 
-  z = __fast_log1p (z + z * z / (__fast_sqrt (z * z + 1.0) + 1.0));
+  const double asinhCutover = pow(2,DBL_MAX_EXP/2); // 1.3407807929943e+154
 
-  return ( x > 0.0 ? z : -z);
+  if (z < asinhCutover)
+  /* After excluding large values, the rearranged formula gives better results
+     the original formula log(z + sqrt(z * z + 1.0)) for very small z.
+        e.g. rearranged asinh(sinh 2e-301)) = 2e-301
+             original   asinh(sinh 2e-301)) = 0.
+     asinh(z) = log   (z + sqrt (z * z + 1.0))
+              = log1p (z + sqrt (z * z + 1.0) - 1.0)
+              = log1p (z + (sqrt (z * z + 1.0) - 1.0)
+                         * (sqrt (z * z + 1.0) + 1.0)
+                         / (sqrt (z * z + 1.0) + 1.0))
+              = log1p (z + ((z * z + 1.0) - 1.0)
+                         / (sqrt (z * z + 1.0) + 1.0))
+              = log1p (z + z * z / (sqrt (z * z + 1.0) + 1.0))
+    */
+    z = __fast_log1p (z + z * (z / (__fast_sqrt (z * z + 1.0) + 1.0)));
+  else
+  /* above this, z*z+1 == z*z, so we can simplify
+     (and avoid z*z being infinity).
+      asinh(z) = log (z + sqrt (z * z + 1.0))
+               = log (z + sqrt (z * z      ))
+               = log (2 * z)
+               = log 2 + log z
+      Choosing asinhCutover is a little tricky.
+      We'd like something that's based on the nature of
+      the numeric type (DBL_MAX_EXP, etc).
+      If c = asinhCutover, then we need:
+         (1) c*c == c*c + 1
+         (2) log (2*c) = log 2 + log c.
+      For float:
+         9.490626562425156e7 is the smallest value that
+         achieves (1), but it fails (2). (It only just fails,
+         but enough to make the function erroneously non-monotonic).
+    */
+    z = __fast_log(2) + __fast_log(z);
+  return copysign(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
-
diff --git a/mingw-w64-crt/math/x86/asinhf.c b/mingw-w64-crt/math/x86/asinhf.c
index fae785abe..f27f84314 100644
--- a/mingw-w64-crt/math/x86/asinhf.c
+++ b/mingw-w64-crt/math/x86/asinhf.c
@@ -5,6 +5,7 @@
  */
 #include <math.h>
 #include <errno.h>
+#include <float.h>
 #include "fastmath.h"
 
  /* asinh(x) = copysign(log(fabs(x) + sqrt(x * x + 1.0)), x) */
@@ -21,13 +22,13 @@ float asinhf(float x)
     return x;
 #endif
 
+  /* See commentary in asinh */
+  const float asinhCutover = pow(2,FLT_MAX_EXP/2); 
 
-  /* Use log1p to avoid cancellation with small x. Put
-     x * x in denom, so overflow is harmless. 
-     asinh(x) = log1p (x + sqrt (x * x + 1.0) - 1.0)
-              = log1p (x + x * x / (sqrt (x * x + 1.0) + 1.0))  */
-
-  z = __fast_log1p (z + z * z / (__fast_sqrt (z * z + 1.0) + 1.0));
-
-  return ( x > 0.0 ? z : -z);
+  if (z < asinhCutover)
+    z = __fast_log1p (z + z * (z / (__fast_sqrt (z * z + 1.0) + 1.0)));
+    //z = __fast_log(z + __fast_sqrt(z * z + 1.0));
+  else
+    z = __fast_log(2) + __fast_log(z);
+  return copysignf(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
diff --git a/mingw-w64-crt/math/x86/asinhl.c b/mingw-w64-crt/math/x86/asinhl.c
index bb2ca97b2..7c0a64e2a 100644
--- a/mingw-w64-crt/math/x86/asinhl.c
+++ b/mingw-w64-crt/math/x86/asinhl.c
@@ -5,6 +5,7 @@
  */
 #include <math.h>
 #include <errno.h>
+#include <float.h>
 #include "fastmath.h"
 
  /* asinh(x) = copysign(log(fabs(x) + sqrt(x * x + 1.0)), x) */
@@ -13,7 +14,6 @@ long double asinhl(long double x)
   long double z;
   if (!isfinite (x))
     return x;
-
   z = fabsl (x);
 
   /* Avoid setting FPU underflow exception flag in x * x. */
@@ -22,12 +22,12 @@ long double asinhl(long double x)
     return x;
 #endif
 
-  /* Use log1p to avoid cancellation with small x. Put
-     x * x in denom, so overflow is harmless. 
-     asinh(x) = log1p (x + sqrt (x * x + 1.0) - 1.0)
-              = log1p (x + x * x / (sqrt (x * x + 1.0) + 1.0))  */
-
-  z = __fast_log1pl (z + z * z / (__fast_sqrtl (z * z + 1.0L) + 1.0L));
+  /* See commentary in asinh */
+  const long double asinhCutover = powl(2,LDBL_MAX_EXP/2); 
 
-  return ( x > 0.0 ? z : -z);
+  if (z < asinhCutover)
+    z = __fast_log1pl (z + z * (z / (__fast_sqrtl (z * z + 1.0) + 1.0)));
+  else
+    z = __fast_logl(2) + __fast_logl(z);
+  return copysignl(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
-- 
2.25.1.windows.1

From 1ac64e22b5e30ab543b37f142cef517a624c576d Mon Sep 17 00:00:00 2001
From: davjam <[email protected]>
Date: Sat, 2 Oct 2021 17:34:13 +0100
Subject: [PATCH 2/3] fix atanh,f,l for bug #515

atanh(-0) now gives -0.
---
 mingw-w64-crt/math/x86/atanh.c  | 2 +-
 mingw-w64-crt/math/x86/atanhf.c | 2 +-
 mingw-w64-crt/math/x86/atanhl.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mingw-w64-crt/math/x86/atanh.c b/mingw-w64-crt/math/x86/atanh.c
index 429bfeae7..b3aa76fe9 100644
--- a/mingw-w64-crt/math/x86/atanh.c
+++ b/mingw-w64-crt/math/x86/atanh.c
@@ -32,5 +32,5 @@ double atanh(double x)
            = 0.5 * log1p ((1.0 + x - 1.0 + x) /(1.0 - x)) 
            = 0.5 * log1p ((2.0 * x ) / (1.0 - x))  */
   z = 0.5 * __fast_log1p ((z + z) / (1.0 - z));
-  return x >= 0 ? z : -z;
+  return copysign(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
diff --git a/mingw-w64-crt/math/x86/atanhf.c b/mingw-w64-crt/math/x86/atanhf.c
index 96d1e9b22..9adc6902d 100644
--- a/mingw-w64-crt/math/x86/atanhf.c
+++ b/mingw-w64-crt/math/x86/atanhf.c
@@ -31,5 +31,5 @@ float atanhf (float x)
            = 0.5 * log1p ((1.0 + x - 1.0 + x) /(1.0 - x)) 
            = 0.5 * log1p ((2.0 * x ) / (1.0 - x))  */
   z = 0.5 * __fast_log1p ((z + z) / (1.0 - z));
-  return x >= 0 ? z : -z;
+  return copysignf(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
diff --git a/mingw-w64-crt/math/x86/atanhl.c b/mingw-w64-crt/math/x86/atanhl.c
index 59eb1bd91..76897466e 100644
--- a/mingw-w64-crt/math/x86/atanhl.c
+++ b/mingw-w64-crt/math/x86/atanhl.c
@@ -30,5 +30,5 @@ long double atanhl (long double x)
            = 0.5 * log1p ((1.0 + x - 1.0 + x) /(1.0 - x)) 
            = 0.5 * log1p ((2.0 * x ) / (1.0 - x))  */
   z = 0.5L * __fast_log1pl ((z + z) / (1.0L - z));
-  return x >= 0 ? z : -z;
+  return copysignl(z, x); //ensure 0.0 -> 0.0 and -0.0 -> -0.0.
 }
-- 
2.25.1.windows.1

#include <stdio.h>
#include <string.h>

//Include this to show the errors in the exiting functions:
// #include <math.h>

//Include these to test the fixes:
#include "asinh.c"
#include "asinhf.c"
#include "asinhl.c"
#include "atanh.c"
#include "atanhf.c"
#include "atanhl.c"

void printErr (char *sMsg, int ndps, double x, double y) {
  char xStr[50], yStr[50];
  sprintf(xStr, "%.*e", ndps, x);
  sprintf(yStr, "%.*e", ndps, y);
  if (strcmp(xStr,yStr) != 0)
    printf("%s: %.16e doesn't match %.16e\n",sMsg,x,y);
}

void test_asinh() {
  double x;
  x = 0.0;  //use a variable to prevent constant folding (which uses a better 
version of asinh).
  printErr("asinh", 8, asinh( x),  x);
  printErr("asinh", 8, asinh(-x), -x);

  for (x = -700.0; x <= 700.0; x += 10) {
    printErr("asinh(sinh(x))", 12, asinh(sinh(x)),x);
  }
  for (x = -1; x <= 1; x += 0.01) {
    printErr("asinh(sinh(x))", 12, asinh(sinh(x)),x);
  }
  for (x = -1e-300; x <= 1e-300; x += 1e-302) {
    printErr("asinh(sinh(x))", 12, asinh(sinh(x)),x);
  }
}

void test_asinhf() {
  float xf;
  xf = 0.0;
  printErr("asinhf", 8, (double)asinhf( xf),  xf);
  printErr("asinhf", 8, (double)asinhf(-xf), -xf);

  for (xf = -80.0; xf <= 80.0; xf += 1) {
    printErr("asinhf(sinhf(xf))", 9, (double)asinhf(sinhf(xf)), (double)xf);
  }
  for (xf = -1; xf <= 1; xf += 0.01) {
    //strangely float seems less accurate in the range +/- [0.5 - 1] (neither 
sinh nor asinh).
    printErr("asinhf(sinhf(xf))", 5, (double)asinhf(sinhf(xf)), (double)xf);
  }
  for (xf = -1e-30; xf <= 1e-30; xf += 1e-32) {
    printErr("asinhf(sinhf(xf))", 9, (double)asinhf(sinhf(xf)), (double)xf);
  }
}

void test_asinhl() {
  long double xl;
  xl = 0.0L;
  printErr("asinhl", 8, (double)asinhl( xl),  xl);
  printErr("asinhl", 8, (double)asinhl(-xl), -xl);

  for (xl = -11000.0L; xl <= 11000.0L; xl += 100.0L) {
    //sinh(-10000L) is too big for a double, but asinh(sinh(-10000L)) is fine.
    printErr("asinhl(sinhl(xl))", 15, (double)asinhl(sinhl(xl)), (double)xl);
  }
  for (xl = -1; xl <= 1; xl += 0.01) {
    printErr("asinhl(sinhl(xl))", 15, (double)asinhl(sinhl(xl)), (double)xl);
  }
  for (xl = -1e-4900L; xl <= 1e-4900L; xl += 1e-4902L) {
    printErr("asinhl(sinhl(xl))", 15, (double)asinhl(sinhl(xl)), (double)xl);
  }
}

void test_atanh() {
  double x;
  x = 0.0;
  printErr("atanh", 8, atanh( x),  x);
  printErr("atanh", 8, atanh(-x), -x);

  /* only test tanh in range within [-pi, pi] to avoid infinities */
  for (x = -1; x <= 1; x += 0.01) {
    printErr("atanh(tanh(x))", 12, atanh(tanh(x)),x);
  }
}

void test_atanhf() {
  float xf;
  xf = 0.0;
  printErr("atanhf", 8, (double)atanhf( xf),  xf);
  printErr("atanhf", 8, (double)atanhf(-xf), -xf);

  for (xf = -1; xf <= 1; xf += 0.01) {
    printErr("atanhf(tanhf(xf))", 5, (double)atanhf(tanhf(xf)), (double)xf);
  }
}

void test_atanhl() {
  long double xl;
  xl = 0.0L;
  printErr("atanhl", 8, (double)atanhl( xl),  xl);
  printErr("atanhl", 8, (double)atanhl(-xl), -xl);

  for (xl = -1; xl <= 1; xl += 0.01) {
    printErr("atanhl(tanhl(xl))", 14, (double)atanhl(tanhl(xl)), (double)xl);
  }
}

void main () {
  test_asinh();
  test_asinhf();
  test_asinhl();
  test_atanh();
  test_atanhf();
  test_atanhl();
  printf("Completed tests.\n");
}

_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to