diff options
Diffstat (limited to 'libtommath/bn_mp_set_double.c')
-rw-r--r-- | libtommath/bn_mp_set_double.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/libtommath/bn_mp_set_double.c b/libtommath/bn_mp_set_double.c new file mode 100644 index 0000000..76f6293 --- /dev/null +++ b/libtommath/bn_mp_set_double.c @@ -0,0 +1,62 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_DOUBLE_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * SPDX-License-Identifier: Unlicense + */ + +#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) +int mp_set_double(mp_int *a, double b) +{ + uint64_t frac; + int exp, res; + union { + double dbl; + uint64_t bits; + } cast; + cast.dbl = b; + + exp = (int)((unsigned)(cast.bits >> 52) & 0x7FFU); + frac = (cast.bits & ((1ULL << 52) - 1ULL)) | (1ULL << 52); + + if (exp == 0x7FF) { /* +-inf, NaN */ + return MP_VAL; + } + exp -= 1023 + 52; + + res = mp_set_long_long(a, frac); + if (res != MP_OKAY) { + return res; + } + + res = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); + if (res != MP_OKAY) { + return res; + } + + if (((cast.bits >> 63) != 0ULL) && (mp_iszero(a) == MP_NO)) { + SIGN(a) = MP_NEG; + } + + return MP_OKAY; +} +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format") +# else +# warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" +# endif +#endif +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ |