root/kernel/math/convert.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. short_to_temp
  2. long_to_temp
  3. temp_to_short
  4. temp_to_long
  5. frndint
  6. real_to_int
  7. int_to_real

   1 /*
   2  * linux/kernel/math/convert.c
   3  *
   4  * Copyright (C) 1991, 1992 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 frndint(const temp_real * a, temp_real * b)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 
 183 void real_to_int(const temp_real * a, temp_int * b)
     /* [previous][next][first][last][top][bottom][index][help] */
 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;
 202         } else {
 203                 underflow = 1;
 204                 shift = 0;
 205         }
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */