summaryrefslogtreecommitdiff
path: root/sys/src
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2018-03-09 20:51:28 +0000
committeraiju <devnull@localhost>2018-03-09 20:51:28 +0000
commitb9a08958e2b7a960b39c0db82a049836896e660e (patch)
tree76e7dd2c12256a96033813ea5c1c9a64b2090d7d /sys/src
parentbf555abcc3056ec74b785b6ff3f8e4b398ef09de (diff)
mp: add mptod and dtomp
Diffstat (limited to 'sys/src')
-rw-r--r--sys/src/libmp/port/mkfile1
-rw-r--r--sys/src/libmp/port/mptod.c83
2 files changed, 84 insertions, 0 deletions
diff --git a/sys/src/libmp/port/mkfile b/sys/src/libmp/port/mkfile
index 9aaad2d80..a94c4c92d 100644
--- a/sys/src/libmp/port/mkfile
+++ b/sys/src/libmp/port/mkfile
@@ -42,6 +42,7 @@ FILES=\
cnfield\
gmfield\
mplogic\
+ mptod\
ALLOFILES=${FILES:%=%.$O}
# cull things in the per-machine directories from this list
diff --git a/sys/src/libmp/port/mptod.c b/sys/src/libmp/port/mptod.c
new file mode 100644
index 000000000..d74e702fb
--- /dev/null
+++ b/sys/src/libmp/port/mptod.c
@@ -0,0 +1,83 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+double
+mptod(mpint *a)
+{
+ u64int v;
+ mpdigit w, r;
+ int sf, i, n, m, s;
+ FPdbleword x;
+
+ if(a->top == 0) return 0.0;
+ sf = mpsignif(a);
+ if(sf > 1024) return Inf(a->sign);
+ i = a->top - 1;
+ v = a->p[i];
+ n = sf & Dbits - 1;
+ n |= n - 1 & Dbits;
+ r = 0;
+ if(n > 54){
+ s = n - 54;
+ r = v & (1<<s) - 1;
+ v >>= s;
+ }
+ while(n < 54){
+ if(--i < 0)
+ w = 0;
+ else
+ w = a->p[i];
+ m = 54 - n;
+ if(m > Dbits) m = Dbits;
+ s = Dbits - m & Dbits - 1;
+ v = v << m | w >> s;
+ r = w & (1<<s) - 1;
+ n += m;
+ }
+ if((v & 3) == 1){
+ while(--i >= 0)
+ r |= a->p[i];
+ if(r != 0)
+ v++;
+ }else
+ v++;
+ v >>= 1;
+ while((v >> 53) != 0){
+ v >>= 1;
+ if(++sf > 1024)
+ return Inf(a->sign);
+ }
+ x.lo = v;
+ x.hi = (u32int)(v >> 32) & (1<<20) - 1 | sf + 1022 << 20 | a->sign & 1<<31;
+ return x.x;
+}
+
+mpint *
+dtomp(double d, mpint *a)
+{
+ FPdbleword x;
+ uvlong v;
+ int e;
+
+ if(a == nil)
+ a = mpnew(0);
+ x.x = d;
+ e = x.hi >> 20 & 2047;
+ assert(e != 2047);
+ if(e < 1022){
+ mpassign(mpzero, a);
+ return a;
+ }
+ v = x.lo | (uvlong)(x.hi & (1<<20) - 1) << 32 | 1ULL<<52;
+ if(e < 1075){
+ v += (1ULL<<1074 - e) - (~v >> 1075 - e & 1);
+ v >>= 1075 - e;
+ }
+ uvtomp(v, a);
+ if(e > 1075)
+ mpleft(a, e - 1075, a);
+ if((int)x.hi < 0)
+ a->sign = -1;
+ return a;
+}