1/* Test mpf_get_d_2exp. 2 3Copyright 2002, 2003, 2017, 2020 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library test suite. 6 7The GNU MP Library test suite is free software; you can redistribute it 8and/or modify it under the terms of the GNU General Public License as 9published by the Free Software Foundation; either version 3 of the License, 10or (at your option) any later version. 11 12The GNU MP Library test suite is distributed in the hope that it will be 13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 15Public License for more details. 16 17You should have received a copy of the GNU General Public License along with 18the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ 19 20#include <stdio.h> 21#include <stdlib.h> 22#include "gmp-impl.h" 23#include "tests.h" 24 25 26static void 27check_data (void) 28{ 29 mpf_t f; 30 double got, want; 31 long got_exp; 32 long exp; 33 struct { 34 int base; 35 int shift; 36 } data[] = { 37 {-1, 1}, {-3, 2}, {-5, 3}, {-7, 3}, { 1, 1}, { 3, 2}, { 5, 3}, { 7, 3} 38 }; 39 40 mpf_init2 (f, 3); 41 42 got = mpf_get_d_2exp (&got_exp, f); 43 if (got != 0 || got_exp != 0) 44 { 45 printf ("mpf_get_d_2exp wrong on zero\n"); 46 mpf_trace (" f ", f); 47 d_trace (" got ", got); 48 printf (" got exp %ld\n", got_exp); 49 abort(); 50 } 51 52 for (exp = -513; exp <= 513; exp++) 53 { 54 size_t i; 55 for (i = 0; i < numberof (data); i++) 56 { 57 want = (double) data[i].base / (1 << data[i].shift); 58 mpf_set_d (f, want); 59 60 if (exp >= 0) 61 mpf_mul_2exp (f, f, exp); 62 else 63 mpf_div_2exp (f, f, -exp); 64 65 got = mpf_get_d_2exp (&got_exp, f); 66 if (got != want || got_exp != exp) 67 { 68 printf ("mpf_get_d_2exp wrong on 2**%ld\n", exp); 69 mpf_trace (" f ", f); 70 d_trace (" want ", want); 71 d_trace (" got ", got); 72 printf (" want exp %ld\n", exp); 73 printf (" got exp %ld\n", got_exp); 74 abort(); 75 } 76 } 77 } 78 mpf_clear (f); 79} 80 81/* Check that hardware rounding doesn't make mpf_get_d_2exp return a value 82 outside its defined range. */ 83static void 84check_round (void) 85{ 86 static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 }; 87 mpf_t f; 88 double got; 89 long got_exp; 90 int i, rnd_mode, old_rnd_mode; 91 92 mpf_init2 (f, 1024L); 93 old_rnd_mode = tests_hardware_getround (); 94 95 for (rnd_mode = 0; rnd_mode < 4; rnd_mode++) 96 { 97 tests_hardware_setround (rnd_mode); 98 99 for (i = 0; i < numberof (data); i++) 100 { 101 mpf_set_ui (f, 1L); 102 mpf_mul_2exp (f, f, data[i]); 103 mpf_sub_ui (f, f, 1L); 104 105 got = mpf_get_d_2exp (&got_exp, f); 106 if (got < 0.5 || got >= 1.0) 107 { 108 printf ("mpf_get_d_2exp bad on 2**%lu-1\n", data[i]); 109 printf ("result out of range, expect 0.5 <= got < 1.0\n"); 110 printf (" rnd_mode = %d\n", rnd_mode); 111 printf (" data[i] = %lu\n", data[i]); 112 mpf_trace (" f ", f); 113 d_trace (" got ", got); 114 printf (" got exp %ld\n", got_exp); 115 abort(); 116 } 117 } 118 } 119 120 mpf_clear (f); 121 tests_hardware_setround (old_rnd_mode); 122} 123 124 125int 126main (void) 127{ 128 tests_start (); 129 mp_trace_base = 16; 130 131 check_data (); 132 check_round (); 133 134 tests_end (); 135 exit (0); 136} 137