1 /* mpq_set_d(mpq_t q, double d) -- Set q to d without rounding. 2 3 Copyright 2000, 2002, 2003 Free Software Foundation, Inc. 4 5 This file is part of the GNU MP Library. 6 7 The GNU MP Library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 The GNU MP Library is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20 #include "config.h" 21 22 #if HAVE_FLOAT_H 23 #include <float.h> /* for DBL_MAX */ 24 #endif 25 26 #include "gmp.h" 27 #include "gmp-impl.h" 28 #include "longlong.h" 29 30 #if LIMBS_PER_DOUBLE > 4 31 choke me 32 #endif 33 34 void 35 mpq_set_d (mpq_ptr dest, double d) 36 { 37 int negative; 38 mp_exp_t exp; 39 mp_limb_t tp[LIMBS_PER_DOUBLE]; 40 mp_ptr np, dp; 41 mp_size_t nn, dn; 42 int c; 43 44 DOUBLE_NAN_INF_ACTION (d, 45 __gmp_invalid_operation (), 46 __gmp_invalid_operation ()); 47 48 negative = d < 0; 49 d = ABS (d); 50 51 exp = __gmp_extract_double (tp, d); 52 53 /* There are two main version of the conversion. The `then' arm handles 54 numbers with a fractional part, while the `else' arm handles integers. */ 55 #if LIMBS_PER_DOUBLE == 4 56 if (exp <= 1 || (exp == 2 && (tp[0] | tp[1]) != 0)) 57 #endif 58 #if LIMBS_PER_DOUBLE == 3 59 if (exp <= 1 || (exp == 2 && tp[0] != 0)) 60 #endif 61 #if LIMBS_PER_DOUBLE == 2 62 if (exp <= 1) 63 #endif 64 { 65 if (d == 0.0) 66 { 67 SIZ(&(dest->_mp_num)) = 0; 68 SIZ(&(dest->_mp_den)) = 1; 69 PTR(&(dest->_mp_den))[0] = 1; 70 return; 71 } 72 73 dn = -exp; 74 MPZ_REALLOC (&(dest->_mp_num), 3); 75 np = PTR(&(dest->_mp_num)); 76 #if LIMBS_PER_DOUBLE == 4 77 if ((tp[0] | tp[1] | tp[2]) == 0) 78 np[0] = tp[3], nn = 1; 79 else if ((tp[0] | tp[1]) == 0) 80 np[1] = tp[3], np[0] = tp[2], nn = 2; 81 else if (tp[0] == 0) 82 np[2] = tp[3], np[1] = tp[2], np[0] = tp[1], nn = 3; 83 else 84 np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 4; 85 #endif 86 #if LIMBS_PER_DOUBLE == 3 87 if ((tp[0] | tp[1]) == 0) 88 np[0] = tp[2], nn = 1; 89 else if (tp[0] == 0) 90 np[1] = tp[2], np[0] = tp[1], nn = 2; 91 else 92 np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 3; 93 #endif 94 #if LIMBS_PER_DOUBLE == 2 95 if (tp[0] == 0) 96 np[0] = tp[1], nn = 1; 97 else 98 np[1] = tp[1], np[0] = tp[0], nn = 2; 99 #endif 100 dn += nn + 1; 101 ASSERT_ALWAYS (dn > 0); 102 MPZ_REALLOC (&(dest->_mp_den), dn); 103 dp = PTR(&(dest->_mp_den)); 104 MPN_ZERO (dp, dn - 1); 105 dp[dn - 1] = 1; 106 count_trailing_zeros (c, np[0] | dp[0]); 107 if (c != 0) 108 { 109 mpn_rshift (np, np, nn, c); 110 nn -= np[nn - 1] == 0; 111 mpn_rshift (dp, dp, dn, c); 112 dn -= dp[dn - 1] == 0; 113 } 114 SIZ(&(dest->_mp_den)) = dn; 115 SIZ(&(dest->_mp_num)) = negative ? -nn : nn; 116 } 117 else 118 { 119 nn = exp; 120 MPZ_REALLOC (&(dest->_mp_num), nn); 121 np = PTR(&(dest->_mp_num)); 122 switch (nn) 123 { 124 default: 125 MPN_ZERO (np, nn - LIMBS_PER_DOUBLE); 126 np += nn - LIMBS_PER_DOUBLE; 127 /* fall through */ 128 #if LIMBS_PER_DOUBLE == 2 129 case 2: 130 np[1] = tp[1], np[0] = tp[0]; 131 break; 132 #endif 133 #if LIMBS_PER_DOUBLE == 3 134 case 3: 135 np[2] = tp[2], np[1] = tp[1], np[0] = tp[0]; 136 break; 137 case 2: 138 np[1] = tp[2], np[0] = tp[1]; 139 break; 140 #endif 141 #if LIMBS_PER_DOUBLE == 4 142 case 4: 143 np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0]; 144 break; 145 case 3: 146 np[2] = tp[3], np[1] = tp[2], np[0] = tp[1]; 147 break; 148 case 2: 149 np[1] = tp[3], np[0] = tp[2]; 150 break; 151 #endif 152 } 153 dp = PTR(&(dest->_mp_den)); 154 dp[0] = 1; 155 SIZ(&(dest->_mp_den)) = 1; 156 SIZ(&(dest->_mp_num)) = negative ? -nn : nn; 157 } 158 } 159