home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / bytewarp.zip / EMFLOAT.C < prev    next >
C/C++ Source or Header  |  1995-11-30  |  37KB  |  1,281 lines

  1. /*
  2. ** emfloat.c
  3. ** Source for emulated floating-point routines.
  4. ** BYTEmark (tm)
  5. ** BYTE's Native Mode Benchmarks
  6. ** Rick Grehan, BYTE Magazine.
  7. **
  8. ** Created:
  9. ** Last update: 3/95
  10. **
  11. ** DISCLAIMER
  12. ** The source, executable, and documentation files that comprise
  13. ** the BYTEmark benchmarks are made available on an "as is" basis.
  14. ** This means that we at BYTE Magazine have made every reasonable
  15. ** effort to verify that the there are no errors in the source and
  16. ** executable code.  We cannot, however, guarantee that the programs
  17. ** are error-free.  Consequently, McGraw-HIll and BYTE Magazine make
  18. ** no claims in regard to the fitness of the source code, executable
  19. ** code, and documentation of the BYTEmark.
  20. **  Furthermore, BYTE Magazine, McGraw-Hill, and all employees
  21. ** of McGraw-Hill cannot be held responsible for any damages resulting
  22. ** from the use of this code or the results obtained from using
  23. ** this code.
  24. */
  25.  
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include "nmglobal.h"
  30. #include "emfloat.h"
  31.  
  32.  
  33. /*
  34. ** Floating-point emulator.
  35. ** These routines are only "sort of" IEEE-compliant.  All work is
  36. ** done using an internal representation.  Also, the routines do
  37. ** not check for many of the exceptions that might occur.
  38. ** Still, the external formats produced are IEEE-compatible,
  39. ** with the restriction that they presume a low-endian machine
  40. ** (though the endianism will not effect the performance).
  41. **
  42. ** Some code here was based on work done by Steve Snelgrove of
  43. ** Orem, UT.  Other code comes from routines presented in
  44. ** the long-ago book: "Microprocessor Programming for
  45. ** Computer Hobbyists" by Neill Graham.
  46. */
  47.  
  48. /**************************
  49. ** SetupCPUEmFloatArrays **
  50. ***************************
  51. ** Set up the arrays that will be used in the emulated
  52. ** floating-point tests.
  53. ** This is done by loading abase and bbase elements with
  54. ** random numbers.  We use our long-to-floating point
  55. ** routine to set them up.
  56. ** NOTE: We really don't need the pointer to cbase...cbase
  57. ** is overwritten in the benchmark.
  58. */
  59. void SetupCPUEmFloatArrays(InternalFPF *abase,
  60.                 InternalFPF *bbase,
  61.                 InternalFPF *cbase,
  62.                 ulong arraysize)
  63. {
  64. ulong i;
  65. InternalFPF locFPF1,locFPF2;
  66.  
  67. for(i=0;i<arraysize;i++)
  68. {       LongToInternalFPF(randwc(50000L),&locFPF1);
  69.         LongToInternalFPF(randwc(50000L)+1L,&locFPF2);
  70.         DivideInternalFPF(&locFPF1,&locFPF2,abase+i);
  71.         LongToInternalFPF(randwc(50000L)+1L,&locFPF2);
  72.         DivideInternalFPF(&locFPF1,&locFPF2,bbase+i);
  73. }
  74. return;
  75. }
  76.  
  77. /***********************
  78. ** DoEmFloatIteration **
  79. ************************
  80. ** Perform an iteration of the emulated floating-point
  81. ** benchmark.  Note that "an iteration" can involve multiple
  82. ** loops through the benchmark.
  83. */
  84. ulong DoEmFloatIteration(InternalFPF *abase,
  85.                 InternalFPF *bbase,
  86.                 InternalFPF *cbase,
  87.                 ulong arraysize, ulong loops)
  88. {
  89. ulong elapsed;          /* For the stopwatch */
  90. static uchar jtable[16] = {0,0,0,0,1,1,1,1,2,2,2,2,2,3,3,3};
  91. ulong i;
  92.  
  93. /*
  94. ** Begin timing
  95. */
  96. elapsed=StartStopwatch();
  97.  
  98. /*
  99. ** Each pass through the array performs operations in
  100. ** the followingratios:
  101. **   4 adds, 4 subtracts, 5 multiplies, 3 divides
  102. ** (adds and subtracts being nearly the same operation)
  103. */
  104. while(loops--)
  105. {
  106.         for(i=0;i<arraysize;i++)
  107.                 switch(jtable[i % 16])
  108.                 {
  109.                         case 0: /* Add */
  110.                                 AddSubInternalFPF(0,abase+i,
  111.                                   bbase+i,
  112.                                   cbase+i);
  113.                                 break;
  114.                         case 1: /* Subtract */
  115.                                 AddSubInternalFPF(1,abase+i,
  116.                                   bbase+i,
  117.                                   cbase+i);
  118.                                 break;
  119.                         case 2: /* Multiply */
  120.                                 MultiplyInternalFPF(abase+i,
  121.                                   bbase+i,
  122.                                   cbase+i);
  123.                                 break;
  124.                         case 3: /* Divide */
  125.                                 DivideInternalFPF(abase+i,
  126.                                   bbase+i,
  127.                                   cbase+i);
  128.                                 break;
  129.                 }
  130. }
  131.  
  132. return(StopStopwatch(elapsed));
  133. }
  134.  
  135. /***********************
  136. ** SetInternalFPFZero **
  137. ************************
  138. ** Set an internal floating-point-format number to zero.
  139. ** sign determines the sign of the zero.
  140. */
  141. static void SetInternalFPFZero(InternalFPF *dest,
  142.                         uchar sign)
  143. {
  144. int i;          /* Index */
  145.  
  146. dest->type=IFPF_IS_ZERO;
  147. dest->sign=sign;
  148. dest->exp=MIN_EXP;
  149. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  150.         dest->mantissa[i]=0;
  151. return;
  152. }
  153.  
  154. /***************************
  155. ** SetInternalFPFInfinity **
  156. ****************************
  157. ** Set an internal floating-point-format number to infinity.
  158. ** This can happen if the exponent exceeds MAX_EXP.
  159. ** As above, sign picks the sign of infinity.
  160. */
  161. static void SetInternalFPFInfinity(InternalFPF *dest,
  162.                         uchar sign)
  163. {
  164. int i;          /* Index */
  165.  
  166. dest->type=IFPF_IS_INFINITY;
  167. dest->sign=sign;
  168. dest->exp=MIN_EXP;
  169. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  170.         dest->mantissa[i]=0;
  171. return;
  172. }
  173.  
  174. /**********************
  175. ** SetInternalFPFNaN **
  176. ***********************
  177. ** Set an internal floating-point-format number to Nan
  178. ** (not a number).  Note that we "emulate" an 80x87 as far
  179. ** as the mantissa bits go.
  180. */
  181. static void SetInternalFPFNaN(InternalFPF *dest)
  182. {
  183. int i;          /* Index */
  184.  
  185. dest->type=IFPF_IS_NAN;
  186. dest->exp=MAX_EXP;
  187. dest->sign=1;
  188. dest->mantissa[0]=0x4000;
  189. for(i=1;i<INTERNAL_FPF_PRECISION;i++)
  190.         dest->mantissa[i]=0;
  191.  
  192. return;
  193. }
  194.  
  195. /*******************
  196. ** IsMantissaZero **
  197. ********************
  198. ** Pass this routine a pointer to an internal floating point format
  199. ** number's mantissa.  It checks for an all-zero mantissa.
  200. ** Returns 0 if it is NOT all zeros, !=0 otherwise.
  201. */
  202. static int IsMantissaZero(u16 *mant)
  203. {
  204. int i;          /* Index */
  205. int n;          /* Return value */
  206.  
  207. n=0;
  208. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  209.         n|=mant[i];
  210.  
  211. return(!n);
  212. }
  213.  
  214. /**************
  215. ** Add16Bits **
  216. ***************
  217. ** Add b, c, and carry.  Retult in a.  New carry in carry.
  218. */
  219. static void Add16Bits(u16 *carry,
  220.                 u16 *a,
  221.                 u16 b,
  222.                 u16 c)
  223. {
  224. u32 accum;              /* Accumulator */
  225.  
  226. /*
  227. ** Do the work in the 32-bit accumulator so we can return
  228. ** the carry.
  229. */
  230. accum=(u32)b;
  231. accum+=(u32)c;
  232. accum+=(u32)*carry;
  233. *carry=(u16)((accum & 0x00010000) ? 1 : 0);     /* New carry */
  234. *a=(u16)(accum & 0xFFFF);       /* Result is lo 16 bits */
  235. return;
  236. }
  237.  
  238. /**************
  239. ** Sub16Bits **
  240. ***************
  241. ** Additive inverse of above.
  242. */
  243. static void Sub16Bits(u16 *borrow,
  244.                 u16 *a,
  245.                 u16 b,
  246.                 u16 c)
  247. {
  248. u32 accum;              /* Accumulator */
  249.  
  250. accum=(u32)b;
  251. accum-=(u32)c;
  252. accum-=(u32)*borrow;
  253. *borrow=(u32)((accum & 0x00010000) ? 1 : 0);    /* New borrow */
  254. *a=(u16)(accum & 0xFFFF);
  255. return;
  256. }
  257.  
  258. /*******************
  259. ** ShiftMantLeft1 **
  260. ********************
  261. ** Shift a vector of 16-bit numbers left 1 bit.  Also provides
  262. ** a carry bit, which is shifted in at the beginning, and
  263. ** shifted out at the end.
  264. */
  265. static void ShiftMantLeft1(u16 *carry,
  266.                         u16 *mantissa)
  267. {
  268. int i;          /* Index */
  269. int new_carry;
  270. u16 accum;      /* Temporary holding placed */
  271.  
  272. for(i=INTERNAL_FPF_PRECISION-1;i>=0;i--)
  273. {       accum=mantissa[i];
  274.         new_carry=accum & 0x8000;       /* Get new carry */
  275.         accum=accum<<1;                 /* Do the shift */
  276.         if(*carry)
  277.                 accum|=1;               /* Insert previous carry */
  278.         *carry=new_carry;
  279.         mantissa[i]=accum;              /* Return shifted value */
  280. }
  281. return;
  282. }
  283.  
  284. /********************
  285. ** ShiftMantRight1 **
  286. *********************
  287. ** Shift a mantissa right by 1 bit.  Provides carry, as
  288. ** above
  289. */
  290. static void ShiftMantRight1(u16 *carry,
  291.                         u16 *mantissa)
  292. {
  293. int i;          /* Index */
  294. int new_carry;
  295. u16 accum;
  296.  
  297. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  298. {       accum=mantissa[i];
  299.         new_carry=accum & 1;            /* Get new carry */
  300.         accum=accum>>1;
  301.         if(*carry)
  302.                 accum|=0x8000;
  303.         *carry=new_carry;
  304.         mantissa[i]=accum;
  305. }
  306. return;
  307. }
  308.  
  309.  
  310. /*****************************
  311. ** StickyShiftMantRight **
  312. ******************************
  313. ** This is a shift right of the mantissa with a "sticky bit".
  314. ** I.E., if a carry of 1 is shifted out of the least significant
  315. ** bit, the least significant bit is set to 1.
  316. */
  317. static void StickyShiftRightMant(InternalFPF *ptr,
  318.                         int amount)
  319. {
  320. int i;          /* Index */
  321. u16 carry;      /* Self-explanatory */
  322. u16 *mantissa;
  323.  
  324. mantissa=ptr->mantissa;
  325.  
  326. if(ptr->type!=IFPF_IS_ZERO)     /* Don't bother shifting a zero */
  327. {
  328.         /*
  329.         ** If the amount of shifting will shift everyting
  330.         ** out of existence, then just clear the whole mantissa
  331.         ** and set the lowmost bit to 1.
  332.         */
  333.         if(amount>=INTERNAL_FPF_PRECISION * 16)
  334.         {
  335.                 for(i=0;i<INTERNAL_FPF_PRECISION-1;i++)
  336.                         mantissa[i]=0;
  337.                 mantissa[INTERNAL_FPF_PRECISION-1]=1;
  338.         }
  339.         else
  340.                 for(i=0;i<amount;i++)
  341.                 {
  342.                         carry=0;
  343.                         ShiftMantRight1(&carry,mantissa);
  344.                         if(carry)
  345.                                 mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
  346.                 }
  347. }
  348. return;
  349. }
  350.  
  351.  
  352. /**************************************************
  353. **         POST ARITHMETIC PROCESSING            **
  354. **  (NORMALIZE, ROUND, OVERFLOW, AND UNDERFLOW)  **
  355. **************************************************/
  356.  
  357. /**************
  358. ** normalize **
  359. ***************
  360. ** Normalize an internal-representation number.  Normalization
  361. ** discards empty most-significant bits.
  362. */
  363. static void normalize(InternalFPF *ptr)
  364. {
  365. u16     carry;
  366.  
  367. /*
  368. ** As long as there's a highmost 0 bit, shift the significand
  369. ** left 1 bit.  Each time you do this, though, you've
  370. ** gotta decrement the exponent.
  371. */
  372. while ((ptr->mantissa[0] & 0x8000) == 0)
  373. {
  374.         carry = 0;
  375.         ShiftMantLeft1(&carry, ptr->mantissa);
  376.         ptr->exp--;
  377. }
  378. return;
  379. }
  380.  
  381. /****************
  382. ** denormalize **
  383. *****************
  384. ** Denormalize an internal-representation number.  This means
  385. ** shifting it right until its exponent is equivalent to
  386. ** minimum_exponent. (You have to do this often in order
  387. ** to perform additions and subtractions).
  388. */
  389. static void denormalize(InternalFPF *ptr,
  390.                 int minimum_exponent)
  391. {
  392. long exponent_difference;
  393.  
  394. if (IsMantissaZero(ptr->mantissa))
  395. {
  396.         printf("Error:  zero significand in denormalize\n");
  397. }
  398.  
  399. exponent_difference = ptr->exp-minimum_exponent;
  400. if (exponent_difference < 0)
  401. {
  402.         /*
  403.         ** The number is subnormal
  404.         */
  405.         exponent_difference = -exponent_difference;
  406.         if (exponent_difference >= (INTERNAL_FPF_PRECISION * 16))
  407.         {
  408.                 /* Underflow */
  409.                 SetInternalFPFZero(ptr, ptr->sign);
  410.         }
  411.         else
  412.         {
  413.                 ptr->exp+=exponent_difference;
  414.                 StickyShiftRightMant(ptr, exponent_difference);
  415.         }
  416. }
  417. return;
  418. }
  419.  
  420.  
  421. /*********************
  422. ** RoundInternalFPF **
  423. **********************
  424. ** Round an internal-representation number.
  425. ** The kind of rounding we do here is simplest...referred to as
  426. ** "chop".  "Extraneous" rightmost bits are simply hacked off.
  427. */
  428. void RoundInternalFPF(InternalFPF *ptr)
  429. {
  430. /* int i; */
  431.  
  432. if (ptr->type == IFPF_IS_NORMAL ||
  433.         ptr->type == IFPF_IS_SUBNORMAL)
  434. {
  435.         denormalize(ptr, MIN_EXP);
  436.         if (ptr->type != IFPF_IS_ZERO)
  437.         {
  438.  
  439.                 /* clear the extraneous bits */
  440.                 ptr->mantissa[3] &= 0xfff8;
  441. /*              for (i=4; i<INTERNAL_FPF_PRECISION; i++)
  442.                 {
  443.                         ptr->mantissa[i] = 0;
  444.                 }
  445. */
  446.                 /*
  447.                 ** Check for overflow
  448.                 */
  449.                 if (ptr->exp > MAX_EXP)
  450.                 {
  451.                         SetInternalFPFInfinity(ptr, ptr->sign);
  452.                 }
  453.         }
  454. }
  455. return;
  456. }
  457.  
  458. /*******************************************************
  459. **  ARITHMETIC OPERATIONS ON INTERNAL REPRESENTATION  **
  460. *******************************************************/
  461.  
  462. /***************
  463. ** choose_nan **
  464. ****************
  465. ** Called by routines that are forced to perform math on
  466. ** a pair of NaN's.  This routine "selects" which NaN is
  467. ** to be returned.
  468. */
  469. static void choose_nan(InternalFPF *x,
  470.                 InternalFPF *y,
  471.                 InternalFPF *z,
  472.                 int intel_flag)
  473. {
  474. int i;
  475.  
  476. /*
  477. ** Compare the two mantissas,
  478. ** return the larger.  Note that we will be emulating
  479. ** an 80387 in this operation.
  480. */
  481. for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  482. {
  483.         if (x->mantissa[i] > y->mantissa[i])
  484.         {
  485.                 memmove((void *)x,(void *)z,sizeof(InternalFPF));
  486.                 return;
  487.         }
  488.         if (x->mantissa[i] < y->mantissa[i])
  489.         {
  490.                 memmove((void *)y,(void *)z,sizeof(InternalFPF));
  491.                 return;
  492.         }
  493. }
  494.  
  495. /*
  496. ** They are equal
  497. */
  498. if (!intel_flag)
  499.         /* if the operation is addition */
  500.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  501. else
  502.         /* if the operation is multiplication */
  503.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  504. return;
  505. }
  506.  
  507.  
  508. /**********************
  509. ** AddSubInternalFPF **
  510. ***********************
  511. ** Adding or subtracting internal-representation numbers.
  512. ** Internal-representation numbers pointed to by x and y are
  513. ** added/subtracted and the result returned in z.
  514. */
  515. static void AddSubInternalFPF(uchar operation,
  516.                 InternalFPF *x,
  517.                 InternalFPF *y,
  518.                 InternalFPF *z)
  519. {
  520. int exponent_difference;
  521. u16 borrow;
  522. u16 carry;
  523. int i;
  524. InternalFPF locx,locy;  /* Needed since we alter them */
  525.  
  526. /*
  527. ** Following big switch statement handles the
  528. ** various combinations of operand types.
  529. */
  530. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  531. {
  532. case ZERO_ZERO:
  533.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  534.         if (x->sign ^ y->sign ^ operation)
  535.         {
  536.                 z->sign = 0; /* positive */
  537.         }
  538.         break;
  539.  
  540. case NAN_ZERO:
  541. case NAN_SUBNORMAL:
  542. case NAN_NORMAL:
  543. case NAN_INFINITY:
  544. case SUBNORMAL_ZERO:
  545. case NORMAL_ZERO:
  546. case INFINITY_ZERO:
  547. case INFINITY_SUBNORMAL:
  548. case INFINITY_NORMAL:
  549.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  550.         break;
  551.  
  552.  
  553. case ZERO_NAN:
  554. case SUBNORMAL_NAN:
  555. case NORMAL_NAN:
  556. case INFINITY_NAN:
  557.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  558.         break;
  559.  
  560. case ZERO_SUBNORMAL:
  561. case ZERO_NORMAL:
  562. case ZERO_INFINITY:
  563. case SUBNORMAL_INFINITY:
  564. case NORMAL_INFINITY:
  565.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  566.         z->sign ^= operation;
  567.         break;
  568.  
  569. case SUBNORMAL_SUBNORMAL:
  570. case SUBNORMAL_NORMAL:
  571. case NORMAL_SUBNORMAL:
  572. case NORMAL_NORMAL:
  573.         /*
  574.         ** Copy x and y to locals, since we may have
  575.         ** to alter them.
  576.         */
  577.         memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
  578.         memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
  579.  
  580.         /* compute sum/difference */
  581.         exponent_difference = locx.exp-locy.exp;
  582.         if (exponent_difference == 0)
  583.         {
  584.                 /*
  585.                 ** locx.exp == locy.exp
  586.                 ** so, no shifting required
  587.                 */
  588.                 if (locx.type == IFPF_IS_SUBNORMAL ||
  589.                   locy.type == IFPF_IS_SUBNORMAL)
  590.                         z->type = IFPF_IS_SUBNORMAL;
  591.                 else
  592.                         z->type = IFPF_IS_NORMAL;
  593.  
  594.                 /*
  595.                 ** Assume that locx.mantissa > locy.mantissa
  596.                 */
  597.                 z->sign = locx.sign;
  598.                 z->exp= locx.exp;
  599.         }
  600.         else
  601.                 if (exponent_difference > 0)
  602.                 {
  603.                         /*
  604.                         ** locx.exp > locy.exp
  605.                         */
  606.                         StickyShiftRightMant(&locy,
  607.                                  exponent_difference);
  608.                         z->type = locx.type;
  609.                         z->sign = locx.sign;
  610.                         z->exp = locx.exp;
  611.                 }
  612.                 else    /* if (exponent_difference < 0) */
  613.                 {
  614.                         /*
  615.                         ** locx.exp < locy.exp
  616.                         */
  617.                         StickyShiftRightMant(&locx,
  618.                                 -exponent_difference);
  619.                         z->type = locy.type;
  620.                         z->sign = locy.sign ^ operation;
  621.                         z->exp = locy.exp;
  622.                 }
  623.  
  624.                 if (locx.sign ^ locy.sign ^ operation)
  625.                 {
  626.                         /*
  627.                         ** Signs are different, subtract mantissas
  628.                         */
  629.                         borrow = 0;
  630.                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  631.                                 Sub16Bits(&borrow,
  632.                                         &z->mantissa[i],
  633.                                         locx.mantissa[i],
  634.                                         locy.mantissa[i]);
  635.  
  636.                         if (borrow)
  637.                         {
  638.                                 /* The y->mantissa was larger than the
  639.                                 ** x->mantissa leaving a negative
  640.                                 ** result.  Change the result back to
  641.                                 ** an unsigned number and flip the
  642.                                 ** sign flag.
  643.                                 */
  644.                                 z->sign = locy.sign ^ operation;
  645.                                 borrow = 0;
  646.                                 for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  647.                                 {
  648.                                         Sub16Bits(&borrow,
  649.                                                 &z->mantissa[i],
  650.                                                 0,
  651.                                                 z->mantissa[i]);
  652.                                 }
  653.                         }
  654.                         else
  655.                         {
  656.                                 /* The assumption made above
  657.                                 ** (i.e. x->mantissa >= y->mantissa)
  658.                                 ** was correct.  Therefore, do nothing.
  659.                                 ** z->sign = x->sign;
  660.                                 */
  661.                         }
  662.  
  663.                         if (IsMantissaZero(z->mantissa))
  664.                         {
  665.                                 z->type = IFPF_IS_ZERO;
  666.                                 z->sign = 0; /* positive */
  667.                         }
  668.                         else
  669.                                 if (locx.type == IFPF_IS_NORMAL ||
  670.                                          locy.type == IFPF_IS_NORMAL)
  671.                                 {
  672.                                         normalize(z);
  673.                                 }
  674.                 }
  675.                 else
  676.                 {
  677.                         /* signs are the same, add mantissas */
  678.                         carry = 0;
  679.                         for (i=(INTERNAL_FPF_PRECISION-1); i>=0; i--)
  680.                         {
  681.                                 Add16Bits(&carry,
  682.                                         &z->mantissa[i],
  683.                                         locx.mantissa[i],
  684.                                         locy.mantissa[i]);
  685.                         }
  686.  
  687.                         if (carry)
  688.                         {
  689.                                 z->exp++;
  690.                                 carry=0;
  691.                                 ShiftMantRight1(&carry,z->mantissa);
  692.                                 z->mantissa[0] |= 0x8000;
  693.                                 z->type = IFPF_IS_NORMAL;
  694.                         }
  695.                         else
  696.                                 if (z->mantissa[0] & 0x8000)
  697.                                         z->type = IFPF_IS_NORMAL;
  698.         }
  699.         break;
  700.  
  701. case INFINITY_INFINITY:
  702.         SetInternalFPFNaN(z);
  703.         break;
  704.  
  705. case NAN_NAN:
  706.         choose_nan(x, y, z, 1);
  707.         break;
  708. }
  709.  
  710. /*
  711. ** All the math is done; time to round.
  712. */
  713. RoundInternalFPF(z);
  714. return;
  715. }
  716.  
  717.  
  718. /************************
  719. ** MultiplyInternalFPF **
  720. *************************
  721. ** Two internal-representation numbers x and y are multiplied; the
  722. ** result is returned in z.
  723. */
  724. static void MultiplyInternalFPF(InternalFPF *x,
  725.                         InternalFPF *y,
  726.                         InternalFPF *z)
  727. {
  728. int i;
  729. int j;
  730. u16 carry;
  731. u16 extra_bits[INTERNAL_FPF_PRECISION];
  732. InternalFPF locy;       /* Needed since this will be altered */
  733. /*
  734. ** As in the preceding function, this large switch
  735. ** statement selects among the many combinations
  736. ** of operands.
  737. */
  738. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  739. {
  740. case INFINITY_SUBNORMAL:
  741. case INFINITY_NORMAL:
  742. case INFINITY_INFINITY:
  743. case ZERO_ZERO:
  744. case ZERO_SUBNORMAL:
  745. case ZERO_NORMAL:
  746.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  747.         z->sign ^= y->sign;
  748.         break;
  749.  
  750. case SUBNORMAL_INFINITY:
  751. case NORMAL_INFINITY:
  752. case SUBNORMAL_ZERO:
  753. case NORMAL_ZERO:
  754.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  755.         z->sign ^= x->sign;
  756.         break;
  757.  
  758. case ZERO_INFINITY:
  759. case INFINITY_ZERO:
  760.         SetInternalFPFNaN(z);
  761.         break;
  762.  
  763. case NAN_ZERO:
  764. case NAN_SUBNORMAL:
  765. case NAN_NORMAL:
  766. case NAN_INFINITY:
  767.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  768.         break;
  769.  
  770. case ZERO_NAN:
  771. case SUBNORMAL_NAN:
  772. case NORMAL_NAN:
  773. case INFINITY_NAN:
  774.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  775.         break;
  776.  
  777.  
  778. case SUBNORMAL_SUBNORMAL:
  779. case SUBNORMAL_NORMAL:
  780. case NORMAL_SUBNORMAL:
  781. case NORMAL_NORMAL:
  782.         /*
  783.         ** Make a local copy of the y number, since we will be
  784.         ** altering it in the process of multiplying.
  785.         */
  786.         memmove((void *)&locy,(void *)y,sizeof(InternalFPF));
  787.  
  788.         /*
  789.         ** Check for unnormal zero arguments
  790.         */
  791.         if (IsMantissaZero(x->mantissa) || IsMantissaZero(y->mantissa))
  792.                 SetInternalFPFInfinity(z, 0);
  793.  
  794.         /*
  795.         ** Initialize the result
  796.         */
  797.         if (x->type == IFPF_IS_SUBNORMAL ||
  798.             y->type == IFPF_IS_SUBNORMAL)
  799.                 z->type = IFPF_IS_SUBNORMAL;
  800.         else
  801.                 z->type = IFPF_IS_NORMAL;
  802.  
  803.         z->sign = x->sign ^ y->sign;
  804.         z->exp = x->exp + y->exp ;
  805.         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  806.         {
  807.                 z->mantissa[i] = 0;
  808.                 extra_bits[i] = 0;
  809.         }
  810.  
  811.         for (i=0; i<(INTERNAL_FPF_PRECISION*16); i++)
  812.         {
  813.                 /*
  814.                 ** Get rightmost bit of the multiplier
  815.                 */
  816.                 carry = 0;
  817.                 ShiftMantRight1(&carry, locy.mantissa);
  818.                 if (carry)
  819.                 {
  820.                         /*
  821.                         ** Add the multiplicand to the product
  822.                         */
  823.                         carry = 0;
  824.                         for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
  825.                                 Add16Bits(&carry,
  826.                                         &z->mantissa[j],
  827.                                         z->mantissa[j],
  828.                                         x->mantissa[j]);
  829.                 }
  830.                 else
  831.                 {
  832.                         carry = 0;
  833.                 }
  834.  
  835.                 /*
  836.                 ** Shift the product right.  Overflow bits get
  837.                 ** shifted into extra_bits.  We'll use it later
  838.                 ** to help with the "sticky" bit.
  839.                 */
  840.                 ShiftMantRight1(&carry, z->mantissa);
  841.                 ShiftMantRight1(&carry, extra_bits);
  842.         }
  843.  
  844.         /*
  845.         ** Normalize
  846.         ** Note that we use a "special" normalization routine
  847.         ** because we need to use the extra bits. (These are
  848.         ** bits that may have been shifted off the bottom that
  849.         ** we want to reclaim...if we can.
  850.         */
  851.         while ((z->mantissa[0] & 0x8000) == 0)
  852.         {
  853.                 carry = 0;
  854.                 ShiftMantLeft1(&carry, extra_bits);
  855.                 ShiftMantLeft1(&carry, z->mantissa);
  856.                 z->exp--;
  857.         }
  858.  
  859.         /*
  860.         ** Set the sticky bit if any bits set in extra bits.
  861.         */
  862.         if (IsMantissaZero(extra_bits))
  863.         {
  864.                 z->mantissa[INTERNAL_FPF_PRECISION-1] |= 1;
  865.         }
  866.         break;
  867.  
  868. case NAN_NAN:
  869.         choose_nan(x, y, z, 0);
  870.         break;
  871. }
  872.  
  873. /*
  874. ** All math done...do rounding.
  875. */
  876. RoundInternalFPF(z);
  877. return;
  878. }
  879.  
  880.  
  881. /**********************
  882. ** DivideInternalFPF **
  883. ***********************
  884. ** Divide internal FPF number x by y.  Return result in z.
  885. */
  886. static void DivideInternalFPF(InternalFPF *x,
  887.                         InternalFPF *y,
  888.                         InternalFPF *z)
  889. {
  890. int i;
  891. int j;
  892. u16 carry;
  893. u16 extra_bits[INTERNAL_FPF_PRECISION];
  894. InternalFPF locx;       /* Local for x number */
  895.  
  896. /*
  897. ** As with preceding function, the following switch
  898. ** statement selects among the various possible
  899. ** operands.
  900. */
  901. switch ((x->type * IFPF_TYPE_COUNT) + y->type)
  902. {
  903. case ZERO_ZERO:
  904. case INFINITY_INFINITY:
  905.         SetInternalFPFNaN(z);
  906.         break;
  907.  
  908. case ZERO_SUBNORMAL:
  909. case ZERO_NORMAL:
  910.         if (IsMantissaZero(y->mantissa))
  911.         {
  912.                 SetInternalFPFNaN(z);
  913.                 break;
  914.         }
  915.  
  916. case ZERO_INFINITY:
  917. case SUBNORMAL_INFINITY:
  918. case NORMAL_INFINITY:
  919.         SetInternalFPFZero(z, x->sign ^ y->sign);
  920.         break;
  921.  
  922. case SUBNORMAL_ZERO:
  923. case NORMAL_ZERO:
  924.         if (IsMantissaZero(x->mantissa))
  925.         {
  926.                 SetInternalFPFNaN(z);
  927.                 break;
  928.         }
  929.  
  930. case INFINITY_ZERO:
  931. case INFINITY_SUBNORMAL:
  932. case INFINITY_NORMAL:
  933.         SetInternalFPFInfinity(z, 0);
  934.         z->sign = x->sign ^ y->sign;
  935.         break;
  936.  
  937. case NAN_ZERO:
  938. case NAN_SUBNORMAL:
  939. case NAN_NORMAL:
  940. case NAN_INFINITY:
  941.         memmove((void *)x,(void *)z,sizeof(InternalFPF));
  942.         break;
  943.  
  944. case ZERO_NAN:
  945. case SUBNORMAL_NAN:
  946. case NORMAL_NAN:
  947. case INFINITY_NAN:
  948.         memmove((void *)y,(void *)z,sizeof(InternalFPF));
  949.         break;
  950.  
  951. case SUBNORMAL_SUBNORMAL:
  952. case NORMAL_SUBNORMAL:
  953. case SUBNORMAL_NORMAL:
  954. case NORMAL_NORMAL:
  955.         /*
  956.         ** Make local copy of x number, since we'll be
  957.         ** altering it in the process of dividing.
  958.         */
  959.         memmove((void *)&locx,(void *)x,sizeof(InternalFPF));
  960.  
  961.         /*
  962.         ** Check for unnormal zero arguments
  963.         */
  964.         if (IsMantissaZero(locx.mantissa))
  965.         {
  966.                 if (IsMantissaZero(y->mantissa))
  967.                         SetInternalFPFNaN(z);
  968.                 else
  969.                         SetInternalFPFZero(z, 0);
  970.                 break;
  971.         }
  972.         if (IsMantissaZero(y->mantissa))
  973.         {
  974.                 SetInternalFPFInfinity(z, 0);
  975.                 break;
  976.         }
  977.  
  978.         /*
  979.         ** Initialize the result
  980.         */
  981.         z->type = x->type;
  982.         z->sign = x->sign ^ y->sign;
  983.         z->exp = x->exp - y->exp +
  984.                         ((INTERNAL_FPF_PRECISION * 16 * 2));
  985.         for (i=0; i<INTERNAL_FPF_PRECISION; i++)
  986.         {
  987.                 z->mantissa[i] = 0;
  988.                 extra_bits[i] = 0;
  989.         }
  990.  
  991.         while ((z->mantissa[0] & 0x8000) == 0)
  992.         {
  993.                 carry = 0;
  994.                 ShiftMantLeft1(&carry, locx.mantissa);
  995.                 ShiftMantLeft1(&carry, extra_bits);
  996.  
  997.                 /*
  998.                 ** Time to subtract yet?
  999.                 */
  1000.                 if (carry == 0)
  1001.                         for (j=0; j<INTERNAL_FPF_PRECISION; j++)
  1002.                         {
  1003.                                 if (y->mantissa[j] > extra_bits[j])
  1004.                                 {
  1005.                                         carry = 0;
  1006.                                         goto no_subtract;
  1007.                                 }
  1008.                                 if (y->mantissa[j] < extra_bits[j])
  1009.                                         break;
  1010.                         }
  1011.                 /*
  1012.                 ** Divisor (y) <= dividend (x), subtract
  1013.                 */
  1014.                 carry = 0;
  1015.                 for (j=(INTERNAL_FPF_PRECISION-1); j>=0; j--)
  1016.                         Sub16Bits(&carry,
  1017.                                 &extra_bits[j],
  1018.                                 extra_bits[j],
  1019.                                 y->mantissa[j]);
  1020.                 carry = 1;      /* 1 shifted into quotient */
  1021.         no_subtract:
  1022.                 ShiftMantLeft1(&carry, z->mantissa);
  1023.                 z->exp--;
  1024.         }
  1025.         break;
  1026.  
  1027. case NAN_NAN:
  1028.         choose_nan(x, y, z, 0);
  1029.         break;
  1030. }
  1031.  
  1032. /*
  1033. ** Math complete...do rounding
  1034. */
  1035. RoundInternalFPF(z);
  1036. }
  1037.  
  1038. /**********************
  1039. ** LongToInternalFPF **
  1040. ***********************
  1041. ** Convert a signed long integer into an internal FPF number.
  1042. */
  1043. static void LongToInternalFPF(long mylong,
  1044.                 InternalFPF *dest)
  1045. {
  1046. int i;          /* Index */
  1047. u16 myword;     /* Used to hold converted stuff */
  1048. /*
  1049. ** Save the sign and get the absolute value.  This will help us
  1050. ** with 64-bit machines, since we use only the lower 32
  1051. ** bits just in case.
  1052. */
  1053. if(mylong<0L)
  1054. {       dest->sign=1;
  1055.         mylong=0L-mylong;
  1056. }
  1057. else
  1058.         dest->sign=0;
  1059. /*
  1060. ** Prepare the destination floating point number
  1061. */
  1062. dest->type=IFPF_IS_NORMAL;
  1063. for(i=0;i<INTERNAL_FPF_PRECISION;i++)
  1064.         dest->mantissa[i]=0;
  1065.  
  1066. /*
  1067. ** See if we've got a zero.  If so, make the resultant FP
  1068. ** number a true zero and go home.
  1069. */
  1070. if(mylong==0)
  1071. {       dest->type=IFPF_IS_ZERO;
  1072.         dest->exp=0;
  1073.         return;
  1074. }
  1075.  
  1076. /*
  1077. ** Not a true zero.  Set the exponent to 32 (internal FPFs have
  1078. ** no bias) and load the low and high words into their proper
  1079. ** locations in the mantissa.  Then normalize.  The action of
  1080. ** normalizing slides the mantissa bits into place and sets
  1081. ** up the exponent properly.
  1082. */
  1083. dest->exp=32;
  1084. myword=(u16)((mylong >> 16) & 0xFFFFL);
  1085. dest->mantissa[0]=myword;
  1086. myword=(u16)(mylong & 0xFFFFL);
  1087. dest->mantissa[1]=myword;
  1088. normalize(dest);
  1089. return;
  1090. }
  1091.  
  1092. /************************
  1093. ** InternalFPFToString **
  1094. *************************
  1095. ** FOR DEBUG PURPOSES
  1096. ** This routine converts an internal floating point representation
  1097. ** number to a string.  Used in debugging the package.
  1098. ** Returns length of converted number.
  1099. ** NOTE: dest must point to a buffer big enough to hold the
  1100. **  result.  Also, this routine does append a null (an effect
  1101. **  of using the sprintf() function).  It also returns
  1102. **  a length count.
  1103. ** NOTE: This routine returns 5 significant digits.  Thats
  1104. **  about all I feel safe with, given the method of
  1105. **  conversion.  It should be more than enough for programmers
  1106. **  to determine whether the package is properly ported.
  1107. */
  1108. static int InternalFPFToString(char *dest,
  1109.                 InternalFPF *src)
  1110. {
  1111. InternalFPF locFPFNum;          /* Local for src (will be altered) */
  1112. InternalFPF IFPF10;             /* Floating-point 10 */
  1113. InternalFPF IFPFComp;           /* For doing comparisons */
  1114. int msign;                      /* Holding for mantissa sign */
  1115. int expcount;                   /* Exponent counter */
  1116. int ccount;                     /* Character counter */
  1117. int i,j,k;                      /* Index */
  1118. u16 carryaccum;                 /* Carry accumulator */
  1119. u16 mycarry;                    /* Local for carry */
  1120.  
  1121. /*
  1122. ** Check first for the simple things...Nan, Infinity, Zero.
  1123. ** If found, copy the proper string in and go home.
  1124. */
  1125. switch(src->type)
  1126. {
  1127.         case IFPF_IS_NAN:
  1128.                 memcpy(dest,"NaN",3);
  1129.                 return(3);
  1130.  
  1131.         case IFPF_IS_INFINITY:
  1132.                 if(src->sign==0)
  1133.                         memcpy(dest,"+Inf",4);
  1134.                 else
  1135.                         memcpy(dest,"-Inf",4);
  1136.                 return(4);
  1137.  
  1138.         case IFPF_IS_ZERO:
  1139.                 if(src->sign==0)
  1140.                         memcpy(dest,"+0",2);
  1141.                 else
  1142.                         memcpy(dest,"-0",2);
  1143.                 return(2);
  1144. }
  1145.  
  1146. /*
  1147. ** Move the internal number into our local holding area, since
  1148. ** we'll be altering it to print it out.
  1149. */
  1150. memcpy((void *)&locFPFNum,(void *)src,sizeof(InternalFPF));
  1151.  
  1152. /*
  1153. ** Set up a floating-point 10...which we'll use a lot in a minute.
  1154. */
  1155. LongToInternalFPF(10L,&IFPF10);
  1156.  
  1157. /*
  1158. ** Save the mantissa sign and make it positive.
  1159. */
  1160. msign=src->sign;
  1161. src->sign=0;
  1162.  
  1163. expcount=0;             /* Init exponent counter */
  1164.  
  1165. /*
  1166. ** See if the number is less than 10.  If so, multiply
  1167. ** the number repeatedly by 10 until it's not.   For each
  1168. ** multiplication, decrement a counter so we can keep track
  1169. ** of the exponent.
  1170. */
  1171. while(1)
  1172. {       AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
  1173.         if(IFPFComp.sign==0) break;
  1174.         MultiplyInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
  1175.         expcount--;
  1176.         memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
  1177. }
  1178.  
  1179. /*
  1180. ** Do the reverse of the above.  As long as the number is
  1181. ** greater than or equal to 10, divide it by 10.  Increment the
  1182. ** exponent counter for each multiplication.
  1183. */
  1184. while(1)
  1185. {
  1186.         AddSubInternalFPF(1,&locFPFNum,&IFPF10,&IFPFComp);
  1187.         if(IFPFComp.sign!=0) break;
  1188.         DivideInternalFPF(&locFPFNum,&IFPF10,&IFPFComp);
  1189.         expcount++;
  1190.         memcpy((void *)&locFPFNum,(void *)&IFPFComp,sizeof(InternalFPF));
  1191. }
  1192.  
  1193. /*
  1194. ** About time to start storing things.  First, store the
  1195. ** mantissa sign.
  1196. */
  1197. ccount=1;               /* Init character counter */
  1198. if(msign==0)
  1199.         *dest++='+';
  1200. else
  1201.         *dest++='-';
  1202.  
  1203. /*
  1204. ** At this point we know that the number is in the range
  1205. ** 10 > n >=1.  We need to "strip digits" out of the
  1206. ** mantissa.  We do this by treating the mantissa as
  1207. ** an integer and multiplying by 10. (Not a floating-point
  1208. ** 10, but an integer 10.  Since this is debug code and we
  1209. ** could care less about speed, we'll do it the stupid
  1210. ** way and simply add the number to itself 10 times.
  1211. ** Anything that makes it to the left of the implied binary point
  1212. ** gets stripped off and emitted.  We'll do this for
  1213. ** 5 significant digits (which should be enough to
  1214. ** verify things).
  1215. */
  1216. /*
  1217. ** Re-position radix point
  1218. */
  1219. carryaccum=0;
  1220. while(locFPFNum.exp>0)
  1221. {
  1222.         mycarry=0;
  1223.         ShiftMantLeft1(&mycarry,locFPFNum.mantissa);
  1224.         carryaccum=(carryaccum<<1);
  1225.         if(mycarry) carryaccum++;
  1226.         locFPFNum.exp--;
  1227. }
  1228.  
  1229. while(locFPFNum.exp<0)
  1230. {
  1231.         mycarry=0;
  1232.         ShiftMantRight1(&mycarry,locFPFNum.mantissa);
  1233.         locFPFNum.exp++;
  1234. }
  1235.  
  1236. for(i=0;i<6;i++)
  1237.         if(i==1)
  1238.         {       /* Emit decimal point */
  1239.                 *dest++='.';
  1240.                 ccount++;
  1241.         }
  1242.         else
  1243.         {       /* Emit a digit */
  1244.                 *dest++=('0'+carryaccum);
  1245.                 ccount++;
  1246.  
  1247.                 carryaccum=0;
  1248.                 memcpy((void *)&IFPF10,
  1249.                         (void *)&locFPFNum,
  1250.                         sizeof(InternalFPF));
  1251.  
  1252.                 /* Do multiply via repeated adds */
  1253.                 for(j=0;j<9;j++)
  1254.                 {
  1255.                         mycarry=0;
  1256.                         for(k=(INTERNAL_FPF_PRECISION-1);k>=0;k--)
  1257.                                 Add16Bits(&mycarry,&(IFPFComp.mantissa[k]),
  1258.                                         locFPFNum.mantissa[k],
  1259.                                         IFPF10.mantissa[k]);
  1260.                         carryaccum+=mycarry ? 1 : 0;
  1261.                         memcpy((void *)&locFPFNum,
  1262.                                 (void *)&IFPFComp,
  1263.                                 sizeof(InternalFPF));
  1264.                 }
  1265.         }
  1266.  
  1267. /*
  1268. ** Now move the 'E', the exponent sign, and the exponent
  1269. ** into the string.
  1270. */
  1271. *dest++='E';
  1272.  
  1273. ccount+=sprintf(dest,"%4d",expcount);
  1274.  
  1275. /*
  1276. ** All done, go home.
  1277. */
  1278. return(ccount);
  1279.  
  1280. }
  1281.