1 /* mpfr_fpif -- Binary export & import of MPFR numbers
2 (floating-point interchange format)
3
4 Copyright 2012-2023 Free Software Foundation, Inc.
5 Contributed by Olivier Demengeon.
6
7 This file is part of the GNU MPFR Library.
8
9 The GNU MPFR Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14 The GNU MPFR Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
21 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
22 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
23
24 #include "mpfr-impl.h"
25
26 #if !defined (HAVE_BIG_ENDIAN) && !defined (HAVE_LITTLE_ENDIAN)
27 #error "Endianness is unknown. Not supported yet."
28 #endif
29
30 /* The format is described as follows. Any multi-byte number is encoded
31 in little endian.
32
33 1. We first store the precision p (this format is able to represent
34 any precision from 1 to 2^64 + 248).
35 Let B be the first byte (0 <= B <= 255).
36 * If B >= 8, the precision p is B-7.
37 Here, the condition is equivalent to 1 <= p <= 248.
38 * If B <= 7, the next B+1 bytes contain p-249.
39 Here, the condition is equivalent to 249 <= p <= 2^64 + 248.
40 We will use the following macros:
41 * MPFR_MAX_PRECSIZE = 7
42 * MPFR_MAX_EMBEDDED_PRECISION = 255 - 7 = 248
43
44 2. Then we store the sign bit and exponent related information
45 (possibly a special value). We first have byte A = [seeeeeee],
46 where s is the sign bit and E = [eeeeeee] such that:
47 * If 0 <= E <= 94, then the exponent e is E-47 (-47 <= e <= 47).
48 * If 95 <= E <= 110, the exponent is stored in the next E-94 bytes
49 (1 to 16 bytes) in sign + absolute value representation,
50 where the absolute value is increased by 47 (e <= -47 or 47 <= e).
51 * If 111 <= E <= 118, the exponent size S is stored in the next
52 E-110 bytes (1 to 8), then the exponent itself is stored in the
53 next S bytes. [Not implemented yet]
54 * If 119 <= E <= 127, we have a special value:
55 E = 119 (MPFR_KIND_ZERO) for a signed zero;
56 E = 120 (MPFR_KIND_INF) for a signed infinity;
57 E = 121 (MPFR_KIND_NAN) for NaN.
58
59 3. Then we store the significand (for regular values).
60
61 The sign bit is preserved by the import/export functions, even for NaN.
62
63 Note: When a size is stored, it must be minimal, i.e. a number cannot
64 start with a null byte. Otherwise the import may fail.
65 */
66
67 #define MPFR_MAX_PRECSIZE 7
68 #define MPFR_MAX_EMBEDDED_PRECISION (255 - MPFR_MAX_PRECSIZE)
69
70 #define MPFR_KIND_ZERO 119
71 #define MPFR_KIND_INF 120
72 #define MPFR_KIND_NAN 121
73 #define MPFR_MAX_EMBEDDED_EXPONENT 47
74 #define MPFR_EXTERNAL_EXPONENT 94
75
76 /* Begin: Low level helper functions */
77
78 /* storage must have an unsigned type */
79 #define COUNT_NB_BYTE(storage, size) \
80 do \
81 { \
82 (storage) >>= 8; \
83 (size)++; \
84 } \
85 while ((storage) != 0)
86
87 #define ALLOC_RESULT(buffer, buffer_size, wanted_size) \
88 do \
89 { \
90 if ((buffer) == NULL || *(buffer_size) < (wanted_size)) \
91 { \
92 (buffer) = (unsigned char *) mpfr_reallocate_func \
93 ((buffer), *(buffer_size), (wanted_size)); \
94 MPFR_ASSERTN((buffer) != 0); \
95 } \
96 *(buffer_size) = (wanted_size); \
97 } \
98 while (0)
99
100 /*
101 * size in byte of a MPFR number in a binary object of a variable size
102 */
103 #define MAX_VARIABLE_STORAGE(exponent_size, precision) \
104 ((size_t)(((precision) >> 3) + (exponent_size) + \
105 ((precision) > 248 ? sizeof(mpfr_prec_t) : 0) + 3))
106
107 /* copy in result[] the values in data[] with a different endianness,
108 where data_size might be smaller than data_max_size, so that we only
109 copy data_size bytes from the end of data[]. */
110 static void
111 #if defined (HAVE_BIG_ENDIAN)
putLittleEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)112 putLittleEndianData (unsigned char *result, unsigned char *data,
113 size_t data_max_size, size_t data_size)
114 #elif defined (HAVE_LITTLE_ENDIAN)
115 putBigEndianData (unsigned char *result, unsigned char *data,
116 size_t data_max_size, size_t data_size)
117 #endif
118 {
119 size_t j;
120
121 MPFR_ASSERTD (data_size <= data_max_size);
122 for (j = 0; j < data_size; j++)
123 result[j] = data[data_max_size - j - 1];
124 }
125
126 /* copy in result[] the values in data[] with the same endianness */
127 static void
128 #if defined (HAVE_BIG_ENDIAN)
putBigEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)129 putBigEndianData (unsigned char *result, unsigned char *data,
130 size_t data_max_size, size_t data_size)
131 #elif defined (HAVE_LITTLE_ENDIAN)
132 putLittleEndianData (unsigned char *result, unsigned char *data,
133 size_t data_max_size, size_t data_size)
134 #endif
135 {
136 MPFR_ASSERTD (data_size <= data_max_size);
137 memcpy (result, data, data_size);
138 }
139
140 /* copy in result[] the values in data[] with a different endianness;
141 the data are written at the end of the result[] buffer (if
142 data_size < data_max_size, the first bytes of result[] are
143 left untouched). */
144 static void
145 #if defined (HAVE_BIG_ENDIAN)
getLittleEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)146 getLittleEndianData (unsigned char *result, unsigned char *data,
147 size_t data_max_size, size_t data_size)
148 #elif defined (HAVE_LITTLE_ENDIAN)
149 getBigEndianData (unsigned char *result, unsigned char *data,
150 size_t data_max_size, size_t data_size)
151 #endif
152 {
153 size_t j;
154
155 MPFR_ASSERTD (data_size <= data_max_size);
156 for (j = 0; j < data_size; j++)
157 result[data_max_size - j - 1] = data[j];
158 }
159
160 /* copy in result[] the values in data[] with the same endianness */
161 static void
162 #if defined (HAVE_BIG_ENDIAN)
getBigEndianData(unsigned char * result,unsigned char * data,size_t data_max_size,size_t data_size)163 getBigEndianData (unsigned char *result, unsigned char *data,
164 size_t data_max_size, size_t data_size)
165 #elif defined (HAVE_LITTLE_ENDIAN)
166 getLittleEndianData (unsigned char *result, unsigned char *data,
167 size_t data_max_size, size_t data_size)
168 #endif
169 {
170 MPFR_ASSERTD (data_size <= data_max_size);
171 memcpy (result, data, data_size);
172 }
173
174 /* End: Low level helper functions */
175
176 /* Internal Function */
177 /*
178 * buffer : OUT : store the precision in binary format, can be null
179 * (may be reallocated if too small)
180 * buffer_size : IN/OUT : size of the buffer => size used in the buffer
181 * precision : IN : precision to store
182 * return pointer to a buffer storing the precision in binary format
183 */
184 static unsigned char *
mpfr_fpif_store_precision(unsigned char * buffer,size_t * buffer_size,mpfr_prec_t precision)185 mpfr_fpif_store_precision (unsigned char *buffer, size_t *buffer_size,
186 mpfr_prec_t precision)
187 {
188 unsigned char *result;
189 size_t size_precision;
190
191 MPFR_ASSERTD (precision >= 1);
192 size_precision = 0;
193
194 if (precision > MPFR_MAX_EMBEDDED_PRECISION)
195 {
196 mpfr_uprec_t copy_precision;
197
198 copy_precision = precision - (MPFR_MAX_EMBEDDED_PRECISION + 1);
199 COUNT_NB_BYTE(copy_precision, size_precision);
200 }
201
202 result = buffer;
203 ALLOC_RESULT(result, buffer_size, size_precision + 1);
204
205 if (precision > MPFR_MAX_EMBEDDED_PRECISION)
206 {
207 result[0] = size_precision - 1;
208 precision -= (MPFR_MAX_EMBEDDED_PRECISION + 1);
209 putLittleEndianData (result + 1, (unsigned char *) &precision,
210 sizeof(mpfr_prec_t), size_precision);
211 }
212 else
213 result[0] = precision + MPFR_MAX_PRECSIZE;
214
215 return result;
216 }
217
218 #define BUFFER_SIZE 8
219
220 /*
221 * fh : IN : file handler
222 * return the precision stored in the binary buffer, 0 in case of error
223 */
224 static mpfr_prec_t
mpfr_fpif_read_precision_from_file(FILE * fh)225 mpfr_fpif_read_precision_from_file (FILE *fh)
226 {
227 mpfr_prec_t precision;
228 size_t precision_size;
229 unsigned char buffer[BUFFER_SIZE];
230
231 if (fh == NULL)
232 return 0;
233
234 if (fread (buffer, 1, 1, fh) != 1)
235 return 0;
236
237 precision_size = buffer[0];
238 if (precision_size > MPFR_MAX_PRECSIZE)
239 return precision_size - MPFR_MAX_PRECSIZE;
240
241 precision_size++;
242 MPFR_ASSERTD (precision_size <= BUFFER_SIZE);
243
244 /* Read the precision in little-endian format. */
245 if (fread (buffer, precision_size, 1, fh) != 1)
246 return 0;
247
248 /* Justification of the #if below. */
249 MPFR_ASSERTD (precision_size <= MPFR_MAX_PRECSIZE + 1);
250
251 #if (MPFR_MAX_PRECSIZE + 1) * CHAR_BIT > MPFR_PREC_BITS
252 while (precision_size > sizeof(mpfr_prec_t))
253 {
254 if (buffer[precision_size-1] != 0)
255 return 0; /* the read precision doesn't fit in a mpfr_prec_t */
256 precision_size--;
257 }
258 #endif
259
260 /* To detect bugs affecting particular platforms (thus MPFR_ASSERTN)... */
261 MPFR_ASSERTN (precision_size <= sizeof(mpfr_prec_t));
262
263 /* Since mpfr_prec_t is signed, one also needs to check that the
264 most significant bit of the corresponding unsigned value is 0. */
265 if (precision_size == sizeof(mpfr_prec_t) &&
266 buffer[precision_size-1] >= 0x80)
267 return 0; /* the read precision doesn't fit in a mpfr_prec_t */
268
269 precision = 0; /* to pad with 0's if data_size < data_max_size */
270
271 /* On big-endian machines, the data must be copied at the end of the
272 precision object in the memory; thus data_max_size (3rd argument)
273 must be sizeof(mpfr_prec_t). */
274 getLittleEndianData ((unsigned char *) &precision, buffer,
275 sizeof(mpfr_prec_t), precision_size);
276
277 return precision + (MPFR_MAX_EMBEDDED_PRECISION + 1);
278 }
279
280 /*
281 * buffer : OUT : store the kind of the MPFR number x, its sign, the size of
282 * its exponent and its exponent value in a binary format,
283 * can be null (may be reallocated if too small)
284 * buffer_size : IN/OUT : size of the buffer => size used in the buffer
285 * x : IN : MPFR number
286 * return pointer to a buffer storing the kind of the MPFR number x, its sign,
287 * the size of its exponent and its exponent value in a binary format,
288 */
289 /* TODO
290 * Exponents that use more than 16 bytes are not managed (not an issue
291 * until one has integer types larger than 128 bits).
292 */
293 static unsigned char*
mpfr_fpif_store_exponent(unsigned char * buffer,size_t * buffer_size,mpfr_ptr x)294 mpfr_fpif_store_exponent (unsigned char *buffer, size_t *buffer_size,
295 mpfr_ptr x)
296 {
297 unsigned char *result;
298 mpfr_uexp_t uexp;
299 size_t exponent_size;
300
301 exponent_size = 0;
302
303 if (MPFR_IS_PURE_FP (x))
304 {
305 mpfr_exp_t exponent = MPFR_GET_EXP (x);
306
307 if (exponent > MPFR_MAX_EMBEDDED_EXPONENT ||
308 exponent < -MPFR_MAX_EMBEDDED_EXPONENT)
309 {
310 mpfr_uexp_t copy_exponent, exp_sign_bit;
311
312 uexp = SAFE_ABS (mpfr_uexp_t, exponent)
313 - MPFR_MAX_EMBEDDED_EXPONENT;
314
315 /* Shift uexp to take the sign bit of the exponent into account.
316 Because of constraints on the valid exponents, this cannot
317 overflow (check with an MPFR_ASSERTD). */
318 copy_exponent = uexp << 1;
319 MPFR_ASSERTD (copy_exponent > uexp);
320 COUNT_NB_BYTE(copy_exponent, exponent_size);
321 MPFR_ASSERTN (exponent_size <= 16); /* see TODO */
322
323 /* Sign bit of the exponent. */
324 exp_sign_bit = (mpfr_uexp_t) 1 << (8 * exponent_size - 1);
325 MPFR_ASSERTD (uexp < exp_sign_bit);
326 if (exponent < 0)
327 uexp |= exp_sign_bit;
328 }
329 else
330 uexp = exponent + MPFR_MAX_EMBEDDED_EXPONENT;
331 }
332
333 result = buffer;
334 ALLOC_RESULT(result, buffer_size, exponent_size + 1);
335
336 if (MPFR_IS_PURE_FP (x))
337 {
338 if (exponent_size == 0)
339 result[0] = uexp;
340 else
341 {
342 result[0] = MPFR_EXTERNAL_EXPONENT + exponent_size;
343
344 putLittleEndianData (result + 1, (unsigned char *) &uexp,
345 sizeof(mpfr_exp_t), exponent_size);
346 }
347 }
348 else if (MPFR_IS_ZERO (x))
349 result[0] = MPFR_KIND_ZERO;
350 else if (MPFR_IS_INF (x))
351 result[0] = MPFR_KIND_INF;
352 else
353 {
354 MPFR_ASSERTD (MPFR_IS_NAN (x));
355 result[0] = MPFR_KIND_NAN;
356 }
357
358 /* Set the sign, even for NaN. */
359 if (MPFR_IS_NEG (x))
360 result[0] |= 0x80;
361
362 return result;
363 }
364
365 /*
366 * x : OUT : MPFR number extracted from the binary buffer
367 * fh : IN : file handler (should not be NULL)
368 * return 0 if successful
369 */
370 /* TODO
371 * Exponents that use more than 16 bytes are not managed (this is not
372 * an issue if the data were written by MPFR with mpfr_exp_t not larger
373 * than 128 bits).
374 */
375 static int
mpfr_fpif_read_exponent_from_file(mpfr_ptr x,FILE * fh)376 mpfr_fpif_read_exponent_from_file (mpfr_ptr x, FILE * fh)
377 {
378 mpfr_exp_t exponent;
379 mpfr_uexp_t uexp;
380 size_t exponent_size;
381 int sign;
382 unsigned char buffer[sizeof(mpfr_exp_t)];
383
384 MPFR_ASSERTD(fh != NULL);
385
386 if (fread (buffer, 1, 1, fh) != 1)
387 return 1;
388
389 /* sign value that can be used with MPFR_SET_SIGN,
390 mpfr_set_zero and mpfr_set_inf */
391 sign = (buffer[0] & 0x80) ? MPFR_SIGN_NEG : MPFR_SIGN_POS;
392 /* Set the sign, even for NaN. */
393 MPFR_SET_SIGN (x, sign);
394
395 exponent = buffer[0] & 0x7F;
396 exponent_size = 1;
397
398 if (exponent > MPFR_EXTERNAL_EXPONENT && exponent < MPFR_KIND_ZERO)
399 {
400 mpfr_uexp_t exp_sign_bit;
401
402 exponent_size = exponent - MPFR_EXTERNAL_EXPONENT;
403
404 /* A failure is acceptable when the exponent starts with leading zeros,
405 even if it would fit in mpfr_exp_t (see format description). */
406 if (MPFR_UNLIKELY (exponent_size > 16 /* see TODO */ ||
407 exponent_size > sizeof(mpfr_exp_t)))
408 return 1;
409
410 if (MPFR_UNLIKELY (fread (buffer, exponent_size, 1, fh) != 1))
411 return 1;
412
413 uexp = 0;
414 getLittleEndianData ((unsigned char *) &uexp, buffer,
415 sizeof(mpfr_exp_t), exponent_size);
416
417 /* Sign bit of the exponent. */
418 exp_sign_bit = uexp & ((mpfr_uexp_t) 1 << (8 * exponent_size - 1));
419
420 uexp &= ~exp_sign_bit;
421 uexp += MPFR_MAX_EMBEDDED_EXPONENT;
422 if (MPFR_UNLIKELY (uexp > MPFR_EMAX_MAX && uexp > -MPFR_EMIN_MIN))
423 return 1;
424
425 exponent = exp_sign_bit ? - (mpfr_exp_t) uexp : (mpfr_exp_t) uexp;
426 if (MPFR_UNLIKELY (! MPFR_EXP_IN_RANGE (exponent)))
427 return 1;
428 MPFR_SET_EXP (x, exponent);
429
430 exponent_size++;
431 }
432 else if (exponent == MPFR_KIND_ZERO)
433 MPFR_SET_ZERO (x);
434 else if (exponent == MPFR_KIND_INF)
435 MPFR_SET_INF (x);
436 else if (exponent == MPFR_KIND_NAN)
437 MPFR_SET_NAN (x);
438 else if (exponent <= MPFR_EXTERNAL_EXPONENT)
439 {
440 exponent -= MPFR_MAX_EMBEDDED_EXPONENT;
441 if (MPFR_UNLIKELY (! MPFR_EXP_IN_RANGE (exponent)))
442 return 1;
443 MPFR_SET_EXP (x, exponent);
444 }
445 else
446 return 1;
447
448 return 0;
449 }
450
451 /*
452 * buffer : OUT : store the limb of the MPFR number x in a binary format,
453 * can be null (may be reallocated if too small)
454 * buffer_size : IN/OUT : size of the buffer => size used in the buffer
455 * x : IN : MPFR number
456 * return pointer to a buffer storing the limb of the MPFR number x in a binary
457 * format
458 */
459 static unsigned char*
mpfr_fpif_store_limbs(unsigned char * buffer,size_t * buffer_size,mpfr_ptr x)460 mpfr_fpif_store_limbs (unsigned char *buffer, size_t *buffer_size, mpfr_ptr x)
461 {
462 unsigned char *result;
463 mpfr_prec_t precision;
464 size_t nb_byte;
465 size_t nb_limb, mp_bytes_per_limb;
466 size_t nb_partial_byte;
467 size_t i, j;
468
469 precision = mpfr_get_prec (x);
470 nb_byte = (precision + 7) >> 3;
471 mp_bytes_per_limb = mp_bits_per_limb >> 3;
472 nb_partial_byte = nb_byte % mp_bytes_per_limb;
473 nb_limb = (nb_byte + mp_bytes_per_limb - 1) / mp_bytes_per_limb;
474
475 result = buffer;
476 ALLOC_RESULT(result, buffer_size, nb_byte);
477
478 putBigEndianData (result, (unsigned char*) MPFR_MANT(x),
479 sizeof(mp_limb_t), nb_partial_byte);
480 for (i = nb_partial_byte, j = (nb_partial_byte == 0) ? 0 : 1; j < nb_limb;
481 i += mp_bytes_per_limb, j++)
482 putLittleEndianData (result + i, (unsigned char*) (MPFR_MANT(x) + j),
483 sizeof(mp_limb_t), sizeof(mp_limb_t));
484
485 return result;
486 }
487
488 /*
489 * x : OUT : MPFR number extracted from the binary buffer, should have the same
490 * precision than the number in the binary format
491 * buffer : IN : limb of the MPFR number x in a binary format
492 * nb_byte : IN : size of the buffer (in bytes)
493 * Assume buffer is not NULL.
494 */
495 static void
mpfr_fpif_read_limbs(mpfr_ptr x,unsigned char * buffer,size_t nb_byte)496 mpfr_fpif_read_limbs (mpfr_ptr x, unsigned char *buffer, size_t nb_byte)
497 {
498 size_t mp_bytes_per_limb;
499 size_t nb_partial_byte;
500 size_t i, j;
501
502 MPFR_ASSERTD (buffer != NULL);
503
504 mp_bytes_per_limb = mp_bits_per_limb >> 3;
505 nb_partial_byte = nb_byte % mp_bytes_per_limb;
506
507 if (nb_partial_byte > 0)
508 {
509 memset (MPFR_MANT(x), 0, sizeof(mp_limb_t));
510 getBigEndianData ((unsigned char*) MPFR_MANT(x), buffer,
511 sizeof(mp_limb_t), nb_partial_byte);
512 }
513 for (i = nb_partial_byte, j = (nb_partial_byte == 0) ? 0 : 1; i < nb_byte;
514 i += mp_bytes_per_limb, j++)
515 getLittleEndianData ((unsigned char*) (MPFR_MANT(x) + j), buffer + i,
516 sizeof(mp_limb_t), sizeof(mp_limb_t));
517 }
518
519 /* External Function */
520 /*
521 * fh : IN : file handler
522 * x : IN : MPFR number to put in the file
523 * return 0 if successful
524 */
525 int
mpfr_fpif_export(FILE * fh,mpfr_ptr x)526 mpfr_fpif_export (FILE *fh, mpfr_ptr x)
527 {
528 int status;
529 unsigned char *buf;
530 unsigned char *bufResult;
531 size_t used_size, buf_size;
532
533 if (fh == NULL)
534 return -1;
535
536 buf_size = MAX_VARIABLE_STORAGE(sizeof(mpfr_exp_t), mpfr_get_prec (x));
537 buf = (unsigned char*) mpfr_allocate_func (buf_size);
538 MPFR_ASSERTN(buf != NULL);
539
540 used_size = buf_size;
541 buf = mpfr_fpif_store_precision (buf, &used_size, mpfr_get_prec (x));
542 used_size > buf_size ? buf_size = used_size : 0;
543 status = fwrite (buf, used_size, 1, fh);
544 if (status != 1)
545 {
546 mpfr_free_func (buf, buf_size);
547 return -1;
548 }
549 used_size = buf_size;
550 bufResult = mpfr_fpif_store_exponent (buf, &used_size, x);
551 /* bufResult cannot be NULL: if reallocation failed in
552 mpfr_fpif_store_exponent, an assertion failed */
553 buf = bufResult;
554 used_size > buf_size ? buf_size = used_size : 0;
555 status = fwrite (buf, used_size, 1, fh);
556 if (status != 1)
557 {
558 mpfr_free_func (buf, buf_size);
559 return -1;
560 }
561
562 if (mpfr_regular_p (x))
563 {
564 used_size = buf_size;
565 buf = mpfr_fpif_store_limbs (buf, &used_size, x);
566 used_size > buf_size ? buf_size = used_size : 0;
567 status = fwrite (buf, used_size, 1, fh);
568 if (status != 1)
569 {
570 mpfr_free_func (buf, buf_size);
571 return -1;
572 }
573 }
574
575 mpfr_free_func (buf, buf_size);
576 return 0;
577 }
578
579 /*
580 * x : IN/OUT : MPFR number extracted from the file, its precision is reset to
581 * be able to hold the number
582 * fh : IN : file handler
583 * Return 0 if the import was successful.
584 */
585 int
mpfr_fpif_import(mpfr_ptr x,FILE * fh)586 mpfr_fpif_import (mpfr_ptr x, FILE *fh)
587 {
588 int status;
589 mpfr_prec_t precision;
590 unsigned char *buffer;
591 size_t used_size;
592
593 precision = mpfr_fpif_read_precision_from_file (fh);
594 if (precision == 0) /* precision = 0 means an error */
595 return -1;
596 MPFR_ASSERTD(fh != NULL); /* checked by mpfr_fpif_read_precision_from_file */
597 if (precision > MPFR_PREC_MAX)
598 return -1;
599 MPFR_STAT_STATIC_ASSERT (MPFR_PREC_MIN == 1); /* as specified */
600 mpfr_set_prec (x, precision);
601
602 status = mpfr_fpif_read_exponent_from_file (x, fh);
603 if (status != 0)
604 {
605 mpfr_set_nan (x);
606 return -1;
607 }
608
609 /* Warning! The significand of x is not set yet. Thus use MPFR_IS_SINGULAR
610 for the test. */
611 if (!MPFR_IS_SINGULAR (x))
612 {
613 /* For portability, we need to consider bytes with only 8 significant
614 bits in the interchange format. That's OK because CHAR_BIT >= 8.
615 But the implementation is currently not clear when CHAR_BIT > 8.
616 This may have never been tested. For safety, require CHAR_BIT == 8,
617 and test/adapt the code if this ever fails. */
618 MPFR_STAT_STATIC_ASSERT (CHAR_BIT == 8);
619 MPFR_STAT_STATIC_ASSERT ((MPFR_PREC_MAX + 7) >> 3 <= (size_t) -1);
620 used_size = (precision + 7) >> 3; /* ceil(precision/8) */
621 buffer = (unsigned char*) mpfr_allocate_func (used_size);
622 MPFR_ASSERTN(buffer != NULL);
623 status = fread (buffer, used_size, 1, fh);
624 if (status != 1)
625 {
626 mpfr_free_func (buffer, used_size);
627 mpfr_set_nan (x);
628 return -1;
629 }
630 mpfr_fpif_read_limbs (x, buffer, used_size);
631 mpfr_free_func (buffer, used_size);
632 }
633
634 return 0;
635 }
636