Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* ibmfloat.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* IBM Floating Point Format                                                 */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. /*****************************************************************************
  12.  * Includes
  13.  *****************************************************************************/
  14.  
  15. #include "stdinc.h"
  16. #include <math.h>
  17. #include <string.h>
  18.  
  19. #include "as_float.h"
  20. #include "errmsg.h"
  21. #include "asmerr.h"
  22. #include "ibmfloat.h"
  23.  
  24. /*!------------------------------------------------------------------------
  25.  * \fn     as_float_2_ibm_float(Word *pDest, as_float_t Src, Boolean ToDouble)
  26.  * \brief  convert floating point number to IBM single precision format
  27.  * \param  pDest where to write result (2 words)
  28.  * \param  Src floating point number to store
  29.  * \param  ToDouble convert to double precision (64 instead of 32 bits)?
  30.  * \return 0 or error code
  31.  * ------------------------------------------------------------------------ */
  32.  
  33. int as_float_2_ibm_float(Word *pDest, as_float_t Src, Boolean ToDouble)
  34. {
  35.   as_float_dissect_t dissect;
  36.   unsigned dest_num_bits;
  37.  
  38.   /* (1) Dissect IEEE number */
  39.  
  40.   as_float_dissect(&dissect, Src);
  41.  
  42.   /* NaN or infinity not representable: */
  43.  
  44.   if ((dissect.fp_class != AS_FP_NORMAL)
  45.    && (dissect.fp_class != AS_FP_SUBNORMAL))
  46.     return -EINVAL;
  47.  
  48.   /* IBM format mantissa is in range [0.5,1) instead of [1,2): */
  49.  
  50.   dissect.exponent++;
  51.  
  52.   /* (2) Convert 2^n exponent to multiple of four since IBM float exponent is to the base of 16.
  53.          Note that before shifting, we ad a zero bit at the end to avoid losing precision: */
  54.  
  55.   while (dissect.exponent & 3)
  56.   {
  57.     as_float_append_mantissa_bits(&dissect, 0, 1);
  58.     as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
  59.     dissect.exponent++;
  60.   }
  61.  
  62.   /* (3) make base-16 exponent explicit */
  63.  
  64.   dissect.exponent /= 4;
  65.  
  66.   /* (4) Round to target precision.  We cannot use as_float_round() for rounding
  67.          since the exponent is already base-16: */
  68.  
  69.   dest_num_bits = ToDouble ? 56 : 24;
  70.   if (dest_num_bits > dissect.mantissa_bits)
  71.     as_float_round(&dissect, dest_num_bits);
  72.   else if (dest_num_bits < dissect.mantissa_bits)
  73.   {
  74.     Boolean round_up;
  75.  
  76.     if (as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, dest_num_bits))
  77.     {
  78.       if (!as_float_mantissa_is_zero_from(&dissect, dest_num_bits + 1)) /* > 0.5 */
  79.         round_up = True;
  80.       else
  81.         round_up = !!as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, dest_num_bits - 1);
  82.     }
  83.     else /* < 0.5 */
  84.       round_up = False;
  85.  
  86.     if (round_up)
  87.     {
  88.       as_float_mant_word_t carry;
  89.       as_float_mant_t sum;
  90.  
  91.       carry = as_float_mantissa_add_bit(sum, dissect.mantissa, dest_num_bits, dissect.mantissa_bits);
  92.       if (carry)
  93.       {
  94.         as_float_mantissa_shift_right(sum, carry, dissect.mantissa_bits);
  95.         as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits);
  96.         as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits);
  97.         as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits);
  98.         dissect.exponent++;
  99.       }
  100.       memcpy(dissect.mantissa, sum, sizeof dissect.mantissa);
  101.     }
  102.     as_float_remove_mantissa_bits(&dissect, dissect.mantissa_bits - dest_num_bits);
  103.   }
  104.  
  105.   /* Overrange? */
  106.  
  107.   if (dissect.exponent > 63)
  108.     return -E2BIG;
  109.  
  110.   /* number that is too small may degenerate to 0: */
  111.  
  112.   while ((dissect.exponent < -64) && !as_float_mantissa_is_zero(&dissect))
  113.   {
  114.     as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
  115.     as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
  116.     as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
  117.     as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits);
  118.     dissect.exponent++;
  119.   }
  120.  
  121.   /* Zero shall get zero (-64) as exponent: */
  122.  
  123.   if (as_float_mantissa_is_zero(&dissect))
  124.     dissect.exponent = -64;
  125.  
  126.   if (dissect.exponent < -64)
  127.     dissect.exponent = -64;
  128.  
  129.   /* add bias to exponent */
  130.  
  131.   dissect.exponent += 64;
  132.  
  133.   /* store result: */
  134.  
  135.   pDest[0] = (dissect.negative << 15)
  136.            | ((dissect.exponent << 8) & 0x7f00)
  137.            | as_float_mantissa_extract(&dissect, 0, 8);
  138.   pDest[1] = as_float_mantissa_extract(&dissect, 8, 16);
  139.   if (ToDouble)
  140.   {
  141.     pDest[2] = as_float_mantissa_extract(&dissect, 24, 16);
  142.     pDest[3] = as_float_mantissa_extract(&dissect, 40, 16);
  143.   }
  144.  
  145.   return 0;
  146. }
  147.