summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/float.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/float.c')
-rw-r--r--src/pkg/runtime/float.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/pkg/runtime/float.c b/src/pkg/runtime/float.c
new file mode 100644
index 000000000..5122f359a
--- /dev/null
+++ b/src/pkg/runtime/float.c
@@ -0,0 +1,173 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+static uint64 uvnan = 0x7FF0000000000001ULL;
+static uint64 uvinf = 0x7FF0000000000000ULL;
+static uint64 uvneginf = 0xFFF0000000000000ULL;
+
+uint32
+float32tobits(float32 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+uint64
+float64tobits(float64 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+float64
+float64frombits(uint64 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+float32
+float32frombits(uint32 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+bool
+isInf(float64 f, int32 sign)
+{
+ uint64 x;
+
+ x = float64tobits(f);
+ if(sign == 0)
+ return x == uvinf || x == uvneginf;
+ if(sign > 0)
+ return x == uvinf;
+ return x == uvneginf;
+}
+
+float64
+NaN(void)
+{
+ return float64frombits(uvnan);
+}
+
+bool
+isNaN(float64 f)
+{
+ uint64 x;
+
+ x = float64tobits(f);
+ return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0);
+}
+
+float64
+Inf(int32 sign)
+{
+ if(sign >= 0)
+ return float64frombits(uvinf);
+ else
+ return float64frombits(uvneginf);
+}
+
+enum
+{
+ MASK = 0x7ffL,
+ SHIFT = 64-11-1,
+ BIAS = 1022L,
+};
+
+float64
+frexp(float64 d, int32 *ep)
+{
+ uint64 x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x = float64tobits(d);
+ *ep = (int32)((x >> SHIFT) & MASK) - BIAS;
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)BIAS << SHIFT;
+ return float64frombits(x);
+}
+
+float64
+ldexp(float64 d, int32 e)
+{
+ uint64 x;
+
+ if(d == 0)
+ return 0;
+ x = float64tobits(d);
+ e += (int32)(x >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)e << SHIFT;
+ return float64frombits(x);
+}
+
+float64
+modf(float64 d, float64 *ip)
+{
+ float64 dd;
+ uint64 x;
+ int32 e;
+
+ if(d < 1) {
+ if(d < 0) {
+ d = modf(-d, ip);
+ *ip = -*ip;
+ return -d;
+ }
+ *ip = 0;
+ return d;
+ }
+
+ x = float64tobits(d);
+ e = (int32)((x >> SHIFT) & MASK) - BIAS;
+
+ /*
+ * Keep the top 11+e bits; clear the rest.
+ */
+ if(e <= 64-11)
+ x &= ~(((uint64)1 << (64LL-11LL-e))-1);
+ dd = float64frombits(x);
+ *ip = dd;
+ return d - dd;
+}
+