|
|
1.1 root 1: /*
2: * linux/kernel/math/convert.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: #include <linux/math_emu.h>
8:
9: /*
10: * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
11: * and temp_to_short conversion routines: don't touch them if you don't
12: * know what's going on. They are the adding of one in the rounding: the
13: * overflow bit is also used for adding one into the exponent. Thus it
14: * looks like the overflow would be incorrectly handled, but due to the
15: * way the IEEE numbers work, things are correct.
16: *
17: * There is no checking for total overflow in the conversions, though (ie
18: * if the temp-real number simply won't fit in a short- or long-real.)
19: */
20:
21: void short_to_temp(const short_real * a, temp_real * b)
22: {
23: if (!(*a & 0x7fffffff)) {
24: b->a = b->b = 0;
25: if (*a)
26: b->exponent = 0x8000;
27: else
28: b->exponent = 0;
29: return;
30: }
31: b->exponent = ((*a>>23) & 0xff)-127+16383;
32: if (*a<0)
33: b->exponent |= 0x8000;
34: b->b = (*a<<8) | 0x80000000;
35: b->a = 0;
36: }
37:
38: void long_to_temp(const long_real * a, temp_real * b)
39: {
40: if (!a->a && !(a->b & 0x7fffffff)) {
41: b->a = b->b = 0;
42: if (a->b)
43: b->exponent = 0x8000;
44: else
45: b->exponent = 0;
46: return;
47: }
48: b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
49: if (a->b<0)
50: b->exponent |= 0x8000;
51: b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21);
52: b->a = a->a<<11;
53: }
54:
55: void temp_to_short(const temp_real * a, short_real * b)
56: {
57: if (!(a->exponent & 0x7fff)) {
58: *b = (a->exponent)?0x80000000:0;
59: return;
60: }
61: *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
62: if (a->exponent < 0)
63: *b |= 0x80000000;
64: *b |= (a->b >> 8) & 0x007fffff;
65: switch (ROUNDING) {
66: case ROUND_NEAREST:
67: if ((a->b & 0xff) > 0x80)
68: ++*b;
69: break;
70: case ROUND_DOWN:
71: if ((a->exponent & 0x8000) && (a->b & 0xff))
72: ++*b;
73: break;
74: case ROUND_UP:
75: if (!(a->exponent & 0x8000) && (a->b & 0xff))
76: ++*b;
77: break;
78: }
79: }
80:
81: void temp_to_long(const temp_real * a, long_real * b)
82: {
83: if (!(a->exponent & 0x7fff)) {
84: b->a = 0;
85: b->b = (a->exponent)?0x80000000:0;
86: return;
87: }
88: b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
89: if (a->exponent < 0)
90: b->b |= 0x80000000;
91: b->b |= (a->b >> 11) & 0x000fffff;
92: b->a = a->b << 21;
93: b->a |= (a->a >> 11) & 0x001fffff;
94: switch (ROUNDING) {
95: case ROUND_NEAREST:
96: if ((a->a & 0x7ff) > 0x400)
97: __asm__("addl $1,%0 ; adcl $0,%1"
98: :"=r" (b->a),"=r" (b->b)
99: :"0" (b->a),"1" (b->b));
100: break;
101: case ROUND_DOWN:
102: if ((a->exponent & 0x8000) && (a->b & 0xff))
103: __asm__("addl $1,%0 ; adcl $0,%1"
104: :"=r" (b->a),"=r" (b->b)
105: :"0" (b->a),"1" (b->b));
106: break;
107: case ROUND_UP:
108: if (!(a->exponent & 0x8000) && (a->b & 0xff))
109: __asm__("addl $1,%0 ; adcl $0,%1"
110: :"=r" (b->a),"=r" (b->b)
111: :"0" (b->a),"1" (b->b));
112: break;
113: }
114: }
115:
1.1.1.2 ! root 116: void frndint(const temp_real * a, temp_real * b)
! 117: {
! 118: int shift = 16383 + 63 - (a->exponent & 0x7fff);
! 119: unsigned long underflow;
! 120:
! 121: if ((shift < 0) || (shift == 16383+63)) {
! 122: *b = *a;
! 123: return;
! 124: }
! 125: b->a = b->b = underflow = 0;
! 126: b->exponent = a->exponent;
! 127: if (shift < 32) {
! 128: b->b = a->b; b->a = a->a;
! 129: } else if (shift < 64) {
! 130: b->a = a->b; underflow = a->a;
! 131: shift -= 32;
! 132: b->exponent += 32;
! 133: } else if (shift < 96) {
! 134: underflow = a->b;
! 135: shift -= 64;
! 136: b->exponent += 64;
! 137: } else {
! 138: underflow = 1;
! 139: shift = 0;
! 140: }
! 141: b->exponent += shift;
! 142: __asm__("shrdl %2,%1,%0"
! 143: :"=r" (underflow),"=r" (b->a)
! 144: :"c" ((char) shift),"0" (underflow),"1" (b->a));
! 145: __asm__("shrdl %2,%1,%0"
! 146: :"=r" (b->a),"=r" (b->b)
! 147: :"c" ((char) shift),"0" (b->a),"1" (b->b));
! 148: __asm__("shrl %1,%0"
! 149: :"=r" (b->b)
! 150: :"c" ((char) shift),"0" (b->b));
! 151: switch (ROUNDING) {
! 152: case ROUND_NEAREST:
! 153: __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
! 154: :"=r" (b->a),"=r" (b->b)
! 155: :"0" (b->a),"1" (b->b)
! 156: ,"r" (0x7fffffff + (b->a & 1))
! 157: ,"m" (*&underflow));
! 158: break;
! 159: case ROUND_UP:
! 160: if ((b->exponent >= 0) && underflow)
! 161: __asm__("addl $1,%0 ; adcl $0,%1"
! 162: :"=r" (b->a),"=r" (b->b)
! 163: :"0" (b->a),"1" (b->b));
! 164: break;
! 165: case ROUND_DOWN:
! 166: if ((b->exponent < 0) && underflow)
! 167: __asm__("addl $1,%0 ; adcl $0,%1"
! 168: :"=r" (b->a),"=r" (b->b)
! 169: :"0" (b->a),"1" (b->b));
! 170: break;
! 171: }
! 172: if (b->a || b->b)
! 173: while (b->b >= 0) {
! 174: b->exponent--;
! 175: __asm__("addl %0,%0 ; adcl %1,%1"
! 176: :"=r" (b->a),"=r" (b->b)
! 177: :"0" (b->a),"1" (b->b));
! 178: }
! 179: else
! 180: b->exponent = 0;
! 181: }
! 182:
1.1 root 183: void real_to_int(const temp_real * a, temp_int * b)
184: {
185: int shift = 16383 + 63 - (a->exponent & 0x7fff);
186: unsigned long underflow;
187:
188: b->a = b->b = underflow = 0;
189: b->sign = (a->exponent < 0);
190: if (shift < 0) {
191: set_OE();
192: return;
193: }
194: if (shift < 32) {
195: b->b = a->b; b->a = a->a;
196: } else if (shift < 64) {
197: b->a = a->b; underflow = a->a;
198: shift -= 32;
199: } else if (shift < 96) {
200: underflow = a->b;
201: shift -= 64;
1.1.1.2 ! root 202: } else {
! 203: underflow = 1;
! 204: shift = 0;
! 205: }
1.1 root 206: __asm__("shrdl %2,%1,%0"
207: :"=r" (underflow),"=r" (b->a)
208: :"c" ((char) shift),"0" (underflow),"1" (b->a));
209: __asm__("shrdl %2,%1,%0"
210: :"=r" (b->a),"=r" (b->b)
211: :"c" ((char) shift),"0" (b->a),"1" (b->b));
212: __asm__("shrl %1,%0"
213: :"=r" (b->b)
214: :"c" ((char) shift),"0" (b->b));
215: switch (ROUNDING) {
216: case ROUND_NEAREST:
217: __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
218: :"=r" (b->a),"=r" (b->b)
219: :"0" (b->a),"1" (b->b)
220: ,"r" (0x7fffffff + (b->a & 1))
221: ,"m" (*&underflow));
222: break;
223: case ROUND_UP:
224: if (!b->sign && underflow)
225: __asm__("addl $1,%0 ; adcl $0,%1"
226: :"=r" (b->a),"=r" (b->b)
227: :"0" (b->a),"1" (b->b));
228: break;
229: case ROUND_DOWN:
230: if (b->sign && underflow)
231: __asm__("addl $1,%0 ; adcl $0,%1"
232: :"=r" (b->a),"=r" (b->b)
233: :"0" (b->a),"1" (b->b));
234: break;
235: }
236: }
237:
238: void int_to_real(const temp_int * a, temp_real * b)
239: {
240: b->a = a->a;
241: b->b = a->b;
242: if (b->a || b->b)
243: b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
244: else {
245: b->exponent = 0;
246: return;
247: }
248: while (b->b >= 0) {
249: b->exponent--;
250: __asm__("addl %0,%0 ; adcl %1,%1"
251: :"=r" (b->a),"=r" (b->b)
252: :"0" (b->a),"1" (b->b));
253: }
254: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.