Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1186 savelij 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
}