180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier
480ee5cbfSDavid du Colombier /*
580ee5cbfSDavid du Colombier * this is big/little endian non-portable
680ee5cbfSDavid du Colombier * it gets the endian from the FPdbleword
780ee5cbfSDavid du Colombier * union in u.h.
880ee5cbfSDavid du Colombier */
980ee5cbfSDavid du Colombier #define MASK 0x7ffL
1080ee5cbfSDavid du Colombier #define SHIFT 20
1180ee5cbfSDavid du Colombier #define BIAS 1022L
12eaba85aaSDavid du Colombier #define SIG 52
1380ee5cbfSDavid du Colombier
1480ee5cbfSDavid du Colombier double
frexp(double d,int * ep)1580ee5cbfSDavid du Colombier frexp(double d, int *ep)
1680ee5cbfSDavid du Colombier {
17eaba85aaSDavid du Colombier FPdbleword x, a;
1880ee5cbfSDavid du Colombier
1980ee5cbfSDavid du Colombier *ep = 0;
20eaba85aaSDavid du Colombier /* order matters: only isNaN can operate on NaN */
21eaba85aaSDavid du Colombier if(isNaN(d) || isInf(d, 0) || d == 0)
22eaba85aaSDavid du Colombier return d;
2380ee5cbfSDavid du Colombier x.x = d;
24eaba85aaSDavid du Colombier a.x = fabs(d);
25eaba85aaSDavid du Colombier if((a.hi >> SHIFT) == 0){ /* normalize subnormal numbers */
26eaba85aaSDavid du Colombier x.x = (double)(1ULL<<SIG) * d;
27eaba85aaSDavid du Colombier *ep = -SIG;
28eaba85aaSDavid du Colombier }
29eaba85aaSDavid du Colombier *ep += ((x.hi >> SHIFT) & MASK) - BIAS;
3080ee5cbfSDavid du Colombier x.hi &= ~(MASK << SHIFT);
3180ee5cbfSDavid du Colombier x.hi |= BIAS << SHIFT;
3280ee5cbfSDavid du Colombier return x.x;
3380ee5cbfSDavid du Colombier }
3480ee5cbfSDavid du Colombier
3580ee5cbfSDavid du Colombier double
ldexp(double d,int deltae)369a747e4fSDavid du Colombier ldexp(double d, int deltae)
3780ee5cbfSDavid du Colombier {
389a747e4fSDavid du Colombier int e, bits;
3980ee5cbfSDavid du Colombier FPdbleword x;
409a747e4fSDavid du Colombier ulong z;
4180ee5cbfSDavid du Colombier
4280ee5cbfSDavid du Colombier if(d == 0)
4380ee5cbfSDavid du Colombier return 0;
4480ee5cbfSDavid du Colombier x.x = d;
459a747e4fSDavid du Colombier e = (x.hi >> SHIFT) & MASK;
469a747e4fSDavid du Colombier if(deltae >= 0 || e+deltae >= 1){ /* no underflow */
479a747e4fSDavid du Colombier e += deltae;
4880ee5cbfSDavid du Colombier if(e >= MASK){ /* overflow */
4980ee5cbfSDavid du Colombier if(d < 0)
5080ee5cbfSDavid du Colombier return Inf(-1);
5180ee5cbfSDavid du Colombier return Inf(1);
5280ee5cbfSDavid du Colombier }
539a747e4fSDavid du Colombier }else{ /* underflow gracefully */
549a747e4fSDavid du Colombier deltae = -deltae;
559a747e4fSDavid du Colombier /* need to shift d right deltae */
569a747e4fSDavid du Colombier if(e > 1){ /* shift e-1 by exponent manipulation */
579a747e4fSDavid du Colombier deltae -= e-1;
589a747e4fSDavid du Colombier e = 1;
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier if(deltae > 0 && e==1){ /* shift 1 by switch from 1.fff to 0.1ff */
619a747e4fSDavid du Colombier deltae--;
629a747e4fSDavid du Colombier e = 0;
639a747e4fSDavid du Colombier x.lo >>= 1;
649a747e4fSDavid du Colombier x.lo |= (x.hi&1)<<31;
659a747e4fSDavid du Colombier z = x.hi & ((1<<SHIFT)-1);
669a747e4fSDavid du Colombier x.hi &= ~((1<<SHIFT)-1);
679a747e4fSDavid du Colombier x.hi |= (1<<(SHIFT-1)) | (z>>1);
689a747e4fSDavid du Colombier }
699a747e4fSDavid du Colombier while(deltae > 0){ /* shift bits down */
709a747e4fSDavid du Colombier bits = deltae;
719a747e4fSDavid du Colombier if(bits > SHIFT)
729a747e4fSDavid du Colombier bits = SHIFT;
739a747e4fSDavid du Colombier x.lo >>= bits;
749a747e4fSDavid du Colombier x.lo |= (x.hi&((1<<bits)-1)) << (32-bits);
759a747e4fSDavid du Colombier z = x.hi & ((1<<SHIFT)-1);
769a747e4fSDavid du Colombier x.hi &= ~((1<<SHIFT)-1);
779a747e4fSDavid du Colombier x.hi |= z>>bits;
789a747e4fSDavid du Colombier deltae -= bits;
799a747e4fSDavid du Colombier }
809a747e4fSDavid du Colombier }
8180ee5cbfSDavid du Colombier x.hi &= ~(MASK << SHIFT);
8280ee5cbfSDavid du Colombier x.hi |= (long)e << SHIFT;
8380ee5cbfSDavid du Colombier return x.x;
8480ee5cbfSDavid du Colombier }
8580ee5cbfSDavid du Colombier
8680ee5cbfSDavid du Colombier double
modf(double d,double * ip)8780ee5cbfSDavid du Colombier modf(double d, double *ip)
8880ee5cbfSDavid du Colombier {
8980ee5cbfSDavid du Colombier FPdbleword x;
9080ee5cbfSDavid du Colombier int e;
9180ee5cbfSDavid du Colombier
92*f1b2ee28SDavid du Colombier x.x = d;
93*f1b2ee28SDavid du Colombier e = (x.hi >> SHIFT) & MASK;
94*f1b2ee28SDavid du Colombier if(e == MASK){
95*f1b2ee28SDavid du Colombier *ip = d;
96*f1b2ee28SDavid du Colombier if(x.lo != 0 || (x.hi & 0xfffffL) != 0) /* NaN */
97*f1b2ee28SDavid du Colombier return d;
98*f1b2ee28SDavid du Colombier /* ±Inf */
99*f1b2ee28SDavid du Colombier x.hi &= 0x80000000L;
100*f1b2ee28SDavid du Colombier return x.x;
101*f1b2ee28SDavid du Colombier }
10280ee5cbfSDavid du Colombier if(d < 1) {
10380ee5cbfSDavid du Colombier if(d < 0) {
10480ee5cbfSDavid du Colombier x.x = modf(-d, ip);
10580ee5cbfSDavid du Colombier *ip = -*ip;
10680ee5cbfSDavid du Colombier return -x.x;
10780ee5cbfSDavid du Colombier }
10880ee5cbfSDavid du Colombier *ip = 0;
10980ee5cbfSDavid du Colombier return d;
11080ee5cbfSDavid du Colombier }
111*f1b2ee28SDavid du Colombier e -= BIAS;
11280ee5cbfSDavid du Colombier if(e <= SHIFT+1) {
11380ee5cbfSDavid du Colombier x.hi &= ~(0x1fffffL >> e);
11480ee5cbfSDavid du Colombier x.lo = 0;
11580ee5cbfSDavid du Colombier } else
11680ee5cbfSDavid du Colombier if(e <= SHIFT+33)
11780ee5cbfSDavid du Colombier x.lo &= ~(0x7fffffffL >> (e-SHIFT-2));
11880ee5cbfSDavid du Colombier *ip = x.x;
11980ee5cbfSDavid du Colombier return d - x.x;
12080ee5cbfSDavid du Colombier }
121