summaryrefslogtreecommitdiff
path: root/math/R/patches/patch-src_main_format.c
blob: a369cbc6794de8b896318815e15561e1574a88cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$NetBSD: patch-src_main_format.c,v 1.1 2011/11/20 04:57:03 markd Exp $

NetBSD does not have rintl() or floorl() so use the OpenBSD implementation
of rintl() in that case.

--- src/main/format.c.orig	2011-10-02 22:02:34.000000000 +0000
+++ src/main/format.c
@@ -130,6 +130,7 @@ void formatInteger(int *x, int n, int *f
 # define R_nearbyintl rintl
 # else
 # define R_nearbyintl private_nearbyintl
+# ifndef __NetBSD__
 long double private_nearbyintl(long double x)
 {
     long double x1;
@@ -142,6 +143,55 @@ long double private_nearbyintl(long doub
         if (x/2.0 == floorl(x/2.0)) return(x); else return(x1);
     }
 }
+# else
+#include <machine/ieee.h>
+
+#if LDBL_MAX_EXP != 0x4000
+/* We also require the usual bias, min exp and expsign packing. */
+#error "Unsupported long double format"
+#endif
+
+#define BIAS    (LDBL_MAX_EXP - 1)
+
+static const float
+shift[2] = {
+#if LDBL_MANT_DIG == 64
+        0x1.0p63, -0x1.0p63
+#elif LDBL_MANT_DIG == 113
+        0x1.0p112, -0x1.0p112
+#else
+#error "Unsupported long double format"
+#endif
+};
+static const float zero[2] = { 0.0, -0.0 };
+
+long double private_nearbyintl(long double x)
+{
+        union {
+                long double e;
+                struct ieee_ext bits;
+        } u;
+        uint32_t expsign;
+        int ex, sign;
+        u.e = x;
+        expsign = (u.bits.ext_sign << 15) | u.bits.ext_exp;
+        ex = expsign & 0x7fff;
+
+        if (ex >= BIAS + LDBL_MANT_DIG - 1) {
+                if (ex == BIAS + LDBL_MAX_EXP)
+                        return (x + x); /* Inf, NaN, or unsupported format */
+                return (x);             /* finite and already an integer */
+        }
+        sign = expsign >> 15;
+        x += shift[sign];
+        x -= shift[sign];
+
+        if (ex < BIAS && x == 0.0L)
+                return (zero[sign]);
+
+        return (x);
+}
+# endif
 # endif
 # else /* no long double */
 # ifdef HAVE_NEARBYINT