|
|
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.