summaryrefslogtreecommitdiff
path: root/sys/src/libc
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org'>2019-06-16 15:55:55 -0700
committerOri Bernstein <ori@eigenstate.org'>2019-06-16 15:55:55 -0700
commit37a5e86bf0aaffb1cdc841150ecc9c847b795e9b (patch)
treec1a499f8b41dc9f7828714cb4b06c6c7f45517b1 /sys/src/libc
parent55f018df8a6006125dcfda55c412ee6908c9ed9b (diff)
Handle NaN and Inf edge cases as specified by posix, instead of barfing.
We're not a posix system, but the posix spec is a good reference for what we should do. Thanks Geoff for the inspiration for this patch.
Diffstat (limited to 'sys/src/libc')
-rw-r--r--sys/src/libc/port/pow.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/sys/src/libc/port/pow.c b/sys/src/libc/port/pow.c
index 0a5a0b5cd..562db48c6 100644
--- a/sys/src/libc/port/pow.c
+++ b/sys/src/libc/port/pow.c
@@ -1,6 +1,16 @@
#include <u.h>
#include <libc.h>
+static int
+isodd(double v)
+{
+ double iv;
+
+ if(modf(v, &iv) != 0)
+ return 0;
+ return (vlong)iv & 1;
+}
+
double
pow(double x, double y) /* return x ^ y (exponentiation) */
{
@@ -8,8 +18,44 @@ pow(double x, double y) /* return x ^ y (exponentiation) */
long i;
int ex, ey, flip;
- if(y == 0.0)
+ /*
+ * Special cases.
+ * Checking early here prevents an infinite loop.
+ * We need to test if !isNaN() here because otherwise
+ * we trap.
+ */
+ if(!isNaN(x) && x == 1.0)
return 1.0;
+ if(!isNaN(y) && y == 0.0)
+ return 1.0;
+ if(isNaN(x) || isNaN(y))
+ return NaN();
+ if(isInf(x, 1)){
+ if(y < 0)
+ return 0.0;
+ else
+ return Inf(1);
+ }else if(isInf(x, -1)){
+ if(y < 0)
+ return isodd(y) ? -0.0 : 0.0;
+ else if(y > 0)
+ return isodd(y) ? Inf(-1) : Inf(1);
+ }
+ if(isInf(y, 1)){
+ if(x == -1.0)
+ return 1.0;
+ else if(fabs(x) < 1.0)
+ return 0.0;
+ else if(fabs(x) > 1.0)
+ return Inf(1);
+ }else if(isInf(y, -1)){
+ if(x == -1.0)
+ return 1.0;
+ else if(fabs(x) < 1.0)
+ return Inf(1);
+ else if(fabs(x) > 1.0)
+ return 0.0;
+ }
flip = 0;
if(y < 0.){