|
|
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:
116: void real_to_int(const temp_real * a, temp_int * b)
117: {
118: int shift = 16383 + 63 - (a->exponent & 0x7fff);
119: unsigned long underflow;
120:
121: b->a = b->b = underflow = 0;
122: b->sign = (a->exponent < 0);
123: if (shift < 0) {
124: set_OE();
125: return;
126: }
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: } else if (shift < 96) {
133: underflow = a->b;
134: shift -= 64;
135: } else
136: return;
137: __asm__("shrdl %2,%1,%0"
138: :"=r" (underflow),"=r" (b->a)
139: :"c" ((char) shift),"0" (underflow),"1" (b->a));
140: __asm__("shrdl %2,%1,%0"
141: :"=r" (b->a),"=r" (b->b)
142: :"c" ((char) shift),"0" (b->a),"1" (b->b));
143: __asm__("shrl %1,%0"
144: :"=r" (b->b)
145: :"c" ((char) shift),"0" (b->b));
146: switch (ROUNDING) {
147: case ROUND_NEAREST:
148: __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
149: :"=r" (b->a),"=r" (b->b)
150: :"0" (b->a),"1" (b->b)
151: ,"r" (0x7fffffff + (b->a & 1))
152: ,"m" (*&underflow));
153: break;
154: case ROUND_UP:
155: if (!b->sign && underflow)
156: __asm__("addl $1,%0 ; adcl $0,%1"
157: :"=r" (b->a),"=r" (b->b)
158: :"0" (b->a),"1" (b->b));
159: break;
160: case ROUND_DOWN:
161: if (b->sign && underflow)
162: __asm__("addl $1,%0 ; adcl $0,%1"
163: :"=r" (b->a),"=r" (b->b)
164: :"0" (b->a),"1" (b->b));
165: break;
166: }
167: }
168:
169: void int_to_real(const temp_int * a, temp_real * b)
170: {
171: b->a = a->a;
172: b->b = a->b;
173: if (b->a || b->b)
174: b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
175: else {
176: b->exponent = 0;
177: return;
178: }
179: while (b->b >= 0) {
180: b->exponent--;
181: __asm__("addl %0,%0 ; adcl %1,%1"
182: :"=r" (b->a),"=r" (b->b)
183: :"0" (b->a),"1" (b->b));
184: }
185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.