fp80.c revision 10480
1/* 2 * Copyright (c) 2013, Andreas Sandberg 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 * OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include <fputils/fp80.h> 31#include <fputils/fp64.h> 32#include "fpbits.h" 33 34#include <assert.h> 35#include <stdint.h> 36 37#include <stdio.h> 38 39 40const fp80_t fp80_pinf = BUILD_FP80(0, 0, FP80_EXP_SPECIAL); 41const fp80_t fp80_ninf = BUILD_FP80(1, 0, FP80_EXP_SPECIAL); 42const fp80_t fp80_qnan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); 43const fp80_t fp80_qnani = BUILD_FP80(1, FP80_FRAC_QNANI, FP80_EXP_SPECIAL); 44const fp80_t fp80_snan = BUILD_FP80(0, FP80_FRAC_SNAN, FP80_EXP_SPECIAL); 45const fp80_t fp80_nan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); 46 47int 48fp80_sgn(fp80_t fp80) 49{ 50 return (fp80.repr.se & FP80_SIGN_BIT) ? -1 : 1; 51} 52 53int 54fp80_isspecial(fp80_t fp80) 55{ 56 const int exp = FP80_EXP(fp80); 57 58 return exp == FP80_EXP_SPECIAL; 59} 60 61int 62fp80_isinf(fp80_t fp80) 63{ 64 const uint64_t frac = FP80_FRAC(fp80); 65 66 return fp80_isspecial(fp80) && frac == 0 ? fp80_sgn(fp80) : 0; 67} 68 69 70int 71fp80_isqnan(fp80_t fp80) 72{ 73 const uint64_t frac = FP80_FRAC(fp80); 74 75 return fp80_isspecial(fp80) && (frac & FP80_QNAN_BIT); 76} 77 78int 79fp80_isqnani(fp80_t fp80) 80{ 81 const uint64_t frac_low = fp80.repr.fi & (FP80_FRAC_MASK >> 1); 82 83 return fp80_isqnan(fp80) && (fp80.repr.se & FP80_SIGN_BIT) && !frac_low; 84} 85 86int 87fp80_issnan(fp80_t fp80) 88{ 89 const uint64_t frac = FP80_FRAC(fp80); 90 91 return fp80_isspecial(fp80) && !(frac & FP80_QNAN_BIT) && frac; 92} 93 94int 95fp80_isfinite(fp80_t fp80) 96{ 97 return !fp80_isnan(fp80) && !fp80_isinf(fp80); 98} 99 100int 101fp80_isnan(fp80_t fp80) 102{ 103 return fp80_issnan(fp80) || fp80_isqnan(fp80) ? fp80_sgn(fp80) : 0; 104} 105 106int 107fp80_iszero(fp80_t fp80) 108{ 109 return fp80.repr.fi == 0 && FP80_EXP(fp80) == 0 ? fp80_sgn(fp80) : 0; 110} 111 112int 113fp80_isnormal(fp80_t fp80) 114{ 115 return FP80_EXP(fp80) != 0 && !fp80_isspecial(fp80) ? 116 fp80_sgn(fp80) : 0; 117} 118 119int 120fp80_issubnormal(fp80_t fp80) 121{ 122 return FP80_FRAC(fp80) && FP80_EXP(fp80) == 0 ? fp80_sgn(fp80) : 0; 123} 124 125int 126fp80_classify(fp80_t fp80) 127{ 128 if (fp80_issubnormal(fp80)) { 129 return FP_SUBNORMAL; 130 } else if (fp80_iszero(fp80)) { 131 return FP_ZERO; 132 } else if (fp80_isinf(fp80)) { 133 return FP_INFINITE; 134 } else if (fp80_isnan(fp80)) { 135 return FP_NAN; 136 } else { 137 assert(fp80_isfinite(fp80)); 138 return FP_NORMAL; 139 } 140} 141 142double 143fp80_cvtd(fp80_t fp80) 144{ 145 return fp80_cvtfp64(fp80).value; 146} 147 148fp64_t 149fp80_cvtfp64(fp80_t fp80) 150{ 151 const int sign = fp80.repr.se & FP80_SIGN_BIT; 152 153 if (!fp80_isspecial(fp80)) { 154 const uint64_t frac = fp80.repr.fi; 155 const int unb_exp = FP80_EXP(fp80) - FP80_EXP_BIAS; 156 const int fp64_exp = unb_exp + FP64_EXP_BIAS; 157 const uint64_t fp64_frac = frac >> (FP80_FRAC_BITS - FP64_FRAC_BITS); 158 159 if (fp64_exp > 0 && fp64_exp < FP64_EXP_SPECIAL) { 160 /* These numbers fall in the range of what we can express 161 * as normals */ 162 return build_fp64(sign, fp64_frac, fp64_exp); 163 } else if (fp64_exp <= 0) { 164 uint64_t fp64_denormal_frac = fp64_frac >> (-fp64_exp); 165 /* Generate a denormal or zero */ 166 return build_fp64(sign, fp64_denormal_frac, 0); 167 } else { 168 /* Infinity */ 169 return build_fp64(sign, 0, FP64_EXP_SPECIAL); 170 } 171 } else { 172 if (fp80_isinf(fp80)) { 173 return build_fp64(sign, 0, FP64_EXP_SPECIAL); 174 } else if (fp80_issnan(fp80)) { 175 return fp80_sgn(fp80) > 0 ? fp64_snan : fp64_nsnan; 176 } else if (fp80_isqnani(fp80)) { 177 return fp64_qnani; 178 } else { 179 assert(fp80_isqnan(fp80)); 180 return fp80_sgn(fp80) > 0 ? fp64_qnan : fp64_nqnan; 181 } 182 } 183} 184 185fp80_t 186fp80_cvfd(double value) 187{ 188 const fp64_t fp64 = { .value = value }; 189 190 return fp80_cvffp64(fp64); 191} 192 193fp80_t 194fp80_cvffp64(fp64_t fp64) 195{ 196 const uint64_t frac = FP64_FRAC(fp64); 197 const unsigned exp = FP64_EXP(fp64); 198 const int unb_exp = exp - FP64_EXP_BIAS; 199 const uint64_t fp80_frac = frac << (FP80_FRAC_BITS - FP64_FRAC_BITS); 200 201 if (exp != 0) { 202 // Normal, inf, nan 203 const unsigned fp80_exp = exp == FP64_EXP_SPECIAL ? 204 FP80_EXP_SPECIAL : (unb_exp + FP80_EXP_BIAS); 205 const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 206 fp80_frac, fp80_exp); 207 return fp80; 208 } else if (exp == 0 && frac == 0) { 209 // Zero 210 const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 0, 0); 211 return fp80; 212 } else { 213 // Denormal 214 uint64_t fp80_fi = fp80_frac; 215 int shift_amt = 0; 216 while (!(fp80_fi & FP80_INT_BIT)) { 217 fp80_fi <<= 1; 218 ++shift_amt; 219 } 220 const unsigned fp80_exp = (unb_exp - shift_amt) + FP80_EXP_BIAS; 221 const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 222 fp80_fi, fp80_exp); 223 return fp80; 224 } 225} 226 227void 228fp80_debug_dump(FILE *fout, fp80_t fp80) 229{ 230 fprintf(fout, "sgn: %i, int: %i, frac: 0x%llx, exp: 0x%x (%i)\n", 231 fp80_sgn(fp80), !!(fp80.repr.fi & FP80_INT_BIT), FP80_FRAC(fp80), 232 FP80_EXP(fp80), FP80_EXP(fp80) - FP80_EXP_BIAS); 233} 234