fp80.c revision 10480
19888Sandreas@sandberg.pp.se/* 29888Sandreas@sandberg.pp.se * Copyright (c) 2013, Andreas Sandberg 39888Sandreas@sandberg.pp.se * All rights reserved. 49888Sandreas@sandberg.pp.se * 59888Sandreas@sandberg.pp.se * Redistribution and use in source and binary forms, with or without 69888Sandreas@sandberg.pp.se * modification, are permitted provided that the following conditions 79888Sandreas@sandberg.pp.se * are met: 89888Sandreas@sandberg.pp.se * 99888Sandreas@sandberg.pp.se * 1. Redistributions of source code must retain the above copyright 109888Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer. 119888Sandreas@sandberg.pp.se * 2. Redistributions in binary form must reproduce the above 129888Sandreas@sandberg.pp.se * copyright notice, this list of conditions and the following 139888Sandreas@sandberg.pp.se * disclaimer in the documentation and/or other materials provided 149888Sandreas@sandberg.pp.se * with the distribution. 159888Sandreas@sandberg.pp.se * 169888Sandreas@sandberg.pp.se * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179888Sandreas@sandberg.pp.se * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189888Sandreas@sandberg.pp.se * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 199888Sandreas@sandberg.pp.se * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 209888Sandreas@sandberg.pp.se * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 219888Sandreas@sandberg.pp.se * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 229888Sandreas@sandberg.pp.se * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 239888Sandreas@sandberg.pp.se * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249888Sandreas@sandberg.pp.se * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 259888Sandreas@sandberg.pp.se * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 269888Sandreas@sandberg.pp.se * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 279888Sandreas@sandberg.pp.se * OF THE POSSIBILITY OF SUCH DAMAGE. 289888Sandreas@sandberg.pp.se */ 299888Sandreas@sandberg.pp.se 309888Sandreas@sandberg.pp.se#include <fputils/fp80.h> 3110480SAndreas.Sandberg@ARM.com#include <fputils/fp64.h> 329888Sandreas@sandberg.pp.se#include "fpbits.h" 339888Sandreas@sandberg.pp.se 349888Sandreas@sandberg.pp.se#include <assert.h> 359888Sandreas@sandberg.pp.se#include <stdint.h> 369888Sandreas@sandberg.pp.se 379888Sandreas@sandberg.pp.se#include <stdio.h> 389888Sandreas@sandberg.pp.se 399888Sandreas@sandberg.pp.se 4010480SAndreas.Sandberg@ARM.comconst fp80_t fp80_pinf = BUILD_FP80(0, 0, FP80_EXP_SPECIAL); 4110480SAndreas.Sandberg@ARM.comconst fp80_t fp80_ninf = BUILD_FP80(1, 0, FP80_EXP_SPECIAL); 4210480SAndreas.Sandberg@ARM.comconst fp80_t fp80_qnan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); 439888Sandreas@sandberg.pp.seconst fp80_t fp80_qnani = BUILD_FP80(1, FP80_FRAC_QNANI, FP80_EXP_SPECIAL); 4410480SAndreas.Sandberg@ARM.comconst fp80_t fp80_snan = BUILD_FP80(0, FP80_FRAC_SNAN, FP80_EXP_SPECIAL); 4510480SAndreas.Sandberg@ARM.comconst fp80_t fp80_nan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); 469888Sandreas@sandberg.pp.se 479888Sandreas@sandberg.pp.seint 489888Sandreas@sandberg.pp.sefp80_sgn(fp80_t fp80) 499888Sandreas@sandberg.pp.se{ 509899Sandreas@sandberg.pp.se return (fp80.repr.se & FP80_SIGN_BIT) ? -1 : 1; 519888Sandreas@sandberg.pp.se} 529888Sandreas@sandberg.pp.se 539888Sandreas@sandberg.pp.seint 549888Sandreas@sandberg.pp.sefp80_isspecial(fp80_t fp80) 559888Sandreas@sandberg.pp.se{ 569888Sandreas@sandberg.pp.se const int exp = FP80_EXP(fp80); 579888Sandreas@sandberg.pp.se 589888Sandreas@sandberg.pp.se return exp == FP80_EXP_SPECIAL; 599888Sandreas@sandberg.pp.se} 609888Sandreas@sandberg.pp.se 619888Sandreas@sandberg.pp.seint 629888Sandreas@sandberg.pp.sefp80_isinf(fp80_t fp80) 639888Sandreas@sandberg.pp.se{ 649888Sandreas@sandberg.pp.se const uint64_t frac = FP80_FRAC(fp80); 659888Sandreas@sandberg.pp.se 669888Sandreas@sandberg.pp.se return fp80_isspecial(fp80) && frac == 0 ? fp80_sgn(fp80) : 0; 679888Sandreas@sandberg.pp.se} 689888Sandreas@sandberg.pp.se 699888Sandreas@sandberg.pp.se 709888Sandreas@sandberg.pp.seint 719888Sandreas@sandberg.pp.sefp80_isqnan(fp80_t fp80) 729888Sandreas@sandberg.pp.se{ 739888Sandreas@sandberg.pp.se const uint64_t frac = FP80_FRAC(fp80); 749888Sandreas@sandberg.pp.se 759888Sandreas@sandberg.pp.se return fp80_isspecial(fp80) && (frac & FP80_QNAN_BIT); 769888Sandreas@sandberg.pp.se} 779888Sandreas@sandberg.pp.se 789888Sandreas@sandberg.pp.seint 799888Sandreas@sandberg.pp.sefp80_isqnani(fp80_t fp80) 809888Sandreas@sandberg.pp.se{ 819899Sandreas@sandberg.pp.se const uint64_t frac_low = fp80.repr.fi & (FP80_FRAC_MASK >> 1); 829888Sandreas@sandberg.pp.se 839899Sandreas@sandberg.pp.se return fp80_isqnan(fp80) && (fp80.repr.se & FP80_SIGN_BIT) && !frac_low; 849888Sandreas@sandberg.pp.se} 859888Sandreas@sandberg.pp.se 869888Sandreas@sandberg.pp.seint 879888Sandreas@sandberg.pp.sefp80_issnan(fp80_t fp80) 889888Sandreas@sandberg.pp.se{ 899888Sandreas@sandberg.pp.se const uint64_t frac = FP80_FRAC(fp80); 909888Sandreas@sandberg.pp.se 919888Sandreas@sandberg.pp.se return fp80_isspecial(fp80) && !(frac & FP80_QNAN_BIT) && frac; 929888Sandreas@sandberg.pp.se} 939888Sandreas@sandberg.pp.se 949888Sandreas@sandberg.pp.seint 959888Sandreas@sandberg.pp.sefp80_isfinite(fp80_t fp80) 969888Sandreas@sandberg.pp.se{ 979888Sandreas@sandberg.pp.se return !fp80_isnan(fp80) && !fp80_isinf(fp80); 989888Sandreas@sandberg.pp.se} 999888Sandreas@sandberg.pp.se 1009888Sandreas@sandberg.pp.seint 1019888Sandreas@sandberg.pp.sefp80_isnan(fp80_t fp80) 1029888Sandreas@sandberg.pp.se{ 1039888Sandreas@sandberg.pp.se return fp80_issnan(fp80) || fp80_isqnan(fp80) ? fp80_sgn(fp80) : 0; 1049888Sandreas@sandberg.pp.se} 1059888Sandreas@sandberg.pp.se 1069888Sandreas@sandberg.pp.seint 1079888Sandreas@sandberg.pp.sefp80_iszero(fp80_t fp80) 1089888Sandreas@sandberg.pp.se{ 1099899Sandreas@sandberg.pp.se return fp80.repr.fi == 0 && FP80_EXP(fp80) == 0 ? fp80_sgn(fp80) : 0; 1109888Sandreas@sandberg.pp.se} 1119888Sandreas@sandberg.pp.se 1129888Sandreas@sandberg.pp.seint 1139888Sandreas@sandberg.pp.sefp80_isnormal(fp80_t fp80) 1149888Sandreas@sandberg.pp.se{ 1159888Sandreas@sandberg.pp.se return FP80_EXP(fp80) != 0 && !fp80_isspecial(fp80) ? 1169888Sandreas@sandberg.pp.se fp80_sgn(fp80) : 0; 1179888Sandreas@sandberg.pp.se} 1189888Sandreas@sandberg.pp.se 1199888Sandreas@sandberg.pp.seint 1209888Sandreas@sandberg.pp.sefp80_issubnormal(fp80_t fp80) 1219888Sandreas@sandberg.pp.se{ 1229888Sandreas@sandberg.pp.se return FP80_FRAC(fp80) && FP80_EXP(fp80) == 0 ? fp80_sgn(fp80) : 0; 1239888Sandreas@sandberg.pp.se} 1249888Sandreas@sandberg.pp.se 1259888Sandreas@sandberg.pp.seint 1269888Sandreas@sandberg.pp.sefp80_classify(fp80_t fp80) 1279888Sandreas@sandberg.pp.se{ 1289888Sandreas@sandberg.pp.se if (fp80_issubnormal(fp80)) { 1299888Sandreas@sandberg.pp.se return FP_SUBNORMAL; 1309888Sandreas@sandberg.pp.se } else if (fp80_iszero(fp80)) { 1319888Sandreas@sandberg.pp.se return FP_ZERO; 1329888Sandreas@sandberg.pp.se } else if (fp80_isinf(fp80)) { 1339888Sandreas@sandberg.pp.se return FP_INFINITE; 1349888Sandreas@sandberg.pp.se } else if (fp80_isnan(fp80)) { 1359888Sandreas@sandberg.pp.se return FP_NAN; 1369888Sandreas@sandberg.pp.se } else { 1379888Sandreas@sandberg.pp.se assert(fp80_isfinite(fp80)); 1389888Sandreas@sandberg.pp.se return FP_NORMAL; 1399888Sandreas@sandberg.pp.se } 1409888Sandreas@sandberg.pp.se} 1419888Sandreas@sandberg.pp.se 1429888Sandreas@sandberg.pp.sedouble 1439888Sandreas@sandberg.pp.sefp80_cvtd(fp80_t fp80) 1449888Sandreas@sandberg.pp.se{ 14510480SAndreas.Sandberg@ARM.com return fp80_cvtfp64(fp80).value; 14610480SAndreas.Sandberg@ARM.com} 14710480SAndreas.Sandberg@ARM.com 14810480SAndreas.Sandberg@ARM.comfp64_t 14910480SAndreas.Sandberg@ARM.comfp80_cvtfp64(fp80_t fp80) 15010480SAndreas.Sandberg@ARM.com{ 1519899Sandreas@sandberg.pp.se const int sign = fp80.repr.se & FP80_SIGN_BIT; 1529888Sandreas@sandberg.pp.se 1539888Sandreas@sandberg.pp.se if (!fp80_isspecial(fp80)) { 1549899Sandreas@sandberg.pp.se const uint64_t frac = fp80.repr.fi; 1559888Sandreas@sandberg.pp.se const int unb_exp = FP80_EXP(fp80) - FP80_EXP_BIAS; 1569888Sandreas@sandberg.pp.se const int fp64_exp = unb_exp + FP64_EXP_BIAS; 1579888Sandreas@sandberg.pp.se const uint64_t fp64_frac = frac >> (FP80_FRAC_BITS - FP64_FRAC_BITS); 1589888Sandreas@sandberg.pp.se 1599888Sandreas@sandberg.pp.se if (fp64_exp > 0 && fp64_exp < FP64_EXP_SPECIAL) { 1609888Sandreas@sandberg.pp.se /* These numbers fall in the range of what we can express 1619888Sandreas@sandberg.pp.se * as normals */ 1629888Sandreas@sandberg.pp.se return build_fp64(sign, fp64_frac, fp64_exp); 1639888Sandreas@sandberg.pp.se } else if (fp64_exp <= 0) { 1649888Sandreas@sandberg.pp.se uint64_t fp64_denormal_frac = fp64_frac >> (-fp64_exp); 1659888Sandreas@sandberg.pp.se /* Generate a denormal or zero */ 1669888Sandreas@sandberg.pp.se return build_fp64(sign, fp64_denormal_frac, 0); 1679888Sandreas@sandberg.pp.se } else { 1689888Sandreas@sandberg.pp.se /* Infinity */ 1699888Sandreas@sandberg.pp.se return build_fp64(sign, 0, FP64_EXP_SPECIAL); 1709888Sandreas@sandberg.pp.se } 1719888Sandreas@sandberg.pp.se } else { 1729888Sandreas@sandberg.pp.se if (fp80_isinf(fp80)) { 1739888Sandreas@sandberg.pp.se return build_fp64(sign, 0, FP64_EXP_SPECIAL); 1749888Sandreas@sandberg.pp.se } else if (fp80_issnan(fp80)) { 17510480SAndreas.Sandberg@ARM.com return fp80_sgn(fp80) > 0 ? fp64_snan : fp64_nsnan; 1769888Sandreas@sandberg.pp.se } else if (fp80_isqnani(fp80)) { 17710480SAndreas.Sandberg@ARM.com return fp64_qnani; 1789888Sandreas@sandberg.pp.se } else { 1799888Sandreas@sandberg.pp.se assert(fp80_isqnan(fp80)); 18010480SAndreas.Sandberg@ARM.com return fp80_sgn(fp80) > 0 ? fp64_qnan : fp64_nqnan; 1819888Sandreas@sandberg.pp.se } 1829888Sandreas@sandberg.pp.se } 1839888Sandreas@sandberg.pp.se} 1849888Sandreas@sandberg.pp.se 1859888Sandreas@sandberg.pp.sefp80_t 1869888Sandreas@sandberg.pp.sefp80_cvfd(double value) 1879888Sandreas@sandberg.pp.se{ 1889888Sandreas@sandberg.pp.se const fp64_t fp64 = { .value = value }; 18910480SAndreas.Sandberg@ARM.com 19010480SAndreas.Sandberg@ARM.com return fp80_cvffp64(fp64); 19110480SAndreas.Sandberg@ARM.com} 19210480SAndreas.Sandberg@ARM.com 19310480SAndreas.Sandberg@ARM.comfp80_t 19410480SAndreas.Sandberg@ARM.comfp80_cvffp64(fp64_t fp64) 19510480SAndreas.Sandberg@ARM.com{ 1969888Sandreas@sandberg.pp.se const uint64_t frac = FP64_FRAC(fp64); 1979888Sandreas@sandberg.pp.se const unsigned exp = FP64_EXP(fp64); 1989888Sandreas@sandberg.pp.se const int unb_exp = exp - FP64_EXP_BIAS; 1999888Sandreas@sandberg.pp.se const uint64_t fp80_frac = frac << (FP80_FRAC_BITS - FP64_FRAC_BITS); 2009888Sandreas@sandberg.pp.se 2019888Sandreas@sandberg.pp.se if (exp != 0) { 2029888Sandreas@sandberg.pp.se // Normal, inf, nan 2039888Sandreas@sandberg.pp.se const unsigned fp80_exp = exp == FP64_EXP_SPECIAL ? 2049888Sandreas@sandberg.pp.se FP80_EXP_SPECIAL : (unb_exp + FP80_EXP_BIAS); 2059888Sandreas@sandberg.pp.se const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 2069888Sandreas@sandberg.pp.se fp80_frac, fp80_exp); 2079888Sandreas@sandberg.pp.se return fp80; 2089888Sandreas@sandberg.pp.se } else if (exp == 0 && frac == 0) { 2099888Sandreas@sandberg.pp.se // Zero 2109888Sandreas@sandberg.pp.se const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 0, 0); 2119888Sandreas@sandberg.pp.se return fp80; 2129888Sandreas@sandberg.pp.se } else { 2139888Sandreas@sandberg.pp.se // Denormal 2149888Sandreas@sandberg.pp.se uint64_t fp80_fi = fp80_frac; 2159888Sandreas@sandberg.pp.se int shift_amt = 0; 2169888Sandreas@sandberg.pp.se while (!(fp80_fi & FP80_INT_BIT)) { 2179888Sandreas@sandberg.pp.se fp80_fi <<= 1; 2189888Sandreas@sandberg.pp.se ++shift_amt; 2199888Sandreas@sandberg.pp.se } 2209888Sandreas@sandberg.pp.se const unsigned fp80_exp = (unb_exp - shift_amt) + FP80_EXP_BIAS; 2219888Sandreas@sandberg.pp.se const fp80_t fp80 = BUILD_FP80(fp64.bits & FP64_SIGN_BIT, 2229888Sandreas@sandberg.pp.se fp80_fi, fp80_exp); 2239888Sandreas@sandberg.pp.se return fp80; 2249888Sandreas@sandberg.pp.se } 2259888Sandreas@sandberg.pp.se} 2269888Sandreas@sandberg.pp.se 2279888Sandreas@sandberg.pp.sevoid 2289888Sandreas@sandberg.pp.sefp80_debug_dump(FILE *fout, fp80_t fp80) 2299888Sandreas@sandberg.pp.se{ 2309888Sandreas@sandberg.pp.se fprintf(fout, "sgn: %i, int: %i, frac: 0x%llx, exp: 0x%x (%i)\n", 2319899Sandreas@sandberg.pp.se fp80_sgn(fp80), !!(fp80.repr.fi & FP80_INT_BIT), FP80_FRAC(fp80), 2329888Sandreas@sandberg.pp.se FP80_EXP(fp80), FP80_EXP(fp80) - FP80_EXP_BIAS); 2339888Sandreas@sandberg.pp.se} 234