summaryrefslogtreecommitdiff
path: root/src/out_raw.c
blob: 4bb699c561b3286e51334fcc2b3c87a9d707d3cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
This is work in progress. Before continuing, please read
http://websympa.loria.fr/wwsympa/arc/mpfr/2011-01/msg00039.html.

/* mpfr_out_raw -- output a floating-point number to binary portable format

Copyright 2011-2017 Free Software Foundation, Inc.
Contributed by the AriC and Caramba projects, INRIA.

This file is part of the GNU MPFR Library.

The GNU MPFR Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

The GNU MPFR Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */

#include "mpfr-impl.h"

/* format for out_raw:
   A mpfr_t is represented by up to 3 fields, each one is represented by a
   sequence of 32-bit words. 32-bit words are stored as 4 bytes in little
   endian format:
   (a) a field for sign, precision and other bit-fields:
       - the sign (1 bit)
       - 2 bits for NaN, Inf, 0, normal numbers:
         00: 0
         01: normal
         10: Inf
         11: NaN
       - 1 bit for the exponent encoding (exp_enc) for normal numbers,
         otherwise 0 is stored here (reserved for future extensions)
       - 1 bit for the precision encoding (prec_enc)
       If prec_enc=0, the remaining 27 bits encode the precision (< 2^27)
       If prec_enc=1, the precision is stored in the following 27 bits
       (high part) and then 32 bits (low part). Thus the maximal precision
       is 59 bits.
   (b) (optional) a field for the exponent:
       - if the number is NaN, Inf, 0, this field is empty
       - if exp_enc=0, this field contains one 32-bit (signed) word encoding
         the exponent
       - if exp_enc=1, a first 32-bit word encodes a positive integer m,
         and the following m 32-bit words encode the exponent (in 2-complement
         representation, with least significant words first)
   (c) (optional) a field for the significand:
       - if the number is NaN, Inf, 0, this field is empty
       - otherwise, let p = ceil(prec/32), the significand is represented
         by p consecutive 32-bit words (least significant words first).
         Thus on a little-endian machine the significand can be directly
         copied using memcopy.
   Examples:
   - a normal binary32 IEEE-754 number uses 96 bits: 32 for (a), 32 for (b),
     and 32 for (c);
   - a normal binary64 IEEE-754 number uses 128 bits: 32 for (a), 32 for (b),
     and 64 for (c) (idem for a significand of 64 bits, as in Intel x86
     double-extended format);
   - a normal binary128 IEEE-754 number uses 192 bits: 32 for (a), 32 for (b),
     and 128 for (c).
 */

size_t
mpfr_out_raw (FILE *stream, mpfr_srcptr x)
{
  size_t n; /* number of bytes of the output */
  mpfr_prec_t prec = MPFR_PREC(x);
  int prec_enc, exp_enc = 0;
  unsigned char *s, *t;

  MPFR_ASSERTN (CHAR_BIT == 8);

  prec_enc = (prec >= 134217728);
  n = 4 + 4 * prec_enc;
  if (MPFR_LIKELY (! MPFR_IS_SINGULAR(x)))
    {
      mpfr_exp_t e = MPFR_EXP(x);
      mpfr_prec_t p = (prec - 1) / 32 + 1; /* ceil(prec/32) */

      exp_enc = (e < -2147483648 || 2147483647 < e);
      n += 4 + 4 * exp_enc + 4 * p;
    }
  t = s = (unsigned char *) malloc (n * sizeof (char));
  t[0] = (mpfr_signbit (x) != 0) << 7;
  if (MPFR_IS_NAN(x))
    t[0] += 3 << 5;
  else if (MPFR_IS_INF(x))
    t[0] += 2 << 5;
  else if (MPFR_IS_ZERO(x))
    t[0] += 1 << 5;
  t[0] += exp_enc << 4;
  t[0] += prec_enc << 3;
  if (prec_enc)
    {
      /* FIXME: the shift count may be too large for the type size. */
      /* FIXME: check that the precision is not too large. */
      t[0] += prec >> 56; /* reduction mod 8 is implicit */
      t[1] = prec >> 48;
      t[2] = prec >> 40;
      t[3] = prec >> 32;
      t += 4;
      t[0] = 0;
    }
  t[0] += prec >> 24;  /* reduction mod 256 is implicit */
  t[1] = prec >> 16;
  t[2] = prec >> 8;
  t[3] = prec;
  free (s);
  return n;
}