From 6ded81a4e55c44aee736475bb526ede72163cb1f Mon Sep 17 00:00:00 2001 From: czurnieden Date: Thu, 14 Feb 2019 15:49:32 +0100 Subject: [PATCH 01/21] made set_double arch/mem-layout independent --- bn_mp_set_double.c | 86 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index c96a3b353..930dde507 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -12,47 +12,83 @@ * SPDX-License-Identifier: Unlicense */ -#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) -int mp_set_double(mp_int *a, double b) +#include +#if ((defined DBL_MAX_EXP) && (FLT_RADIX == 2)) +static double s_math_h_less_frexp(double x, int *exp) { - 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 */ + int exponent = 0; + while (x >= 1.0) { + exponent++; + /* exp > DBL_MAX_EXP + 1, it is inf */ + if (exponent == (DBL_MAX_EXP + 1)) { + *exp = exponent; + return x; + } + x /= 2.0; + } + + *exp = exponent; + return x; +} + + +int mp_set_double(mp_int *c, double d) +{ + int expnt, res, sign = MP_ZPOS; + double frac; + + + if (d != d) { return MP_VAL; } - exp -= 1023 + 52; - - res = mp_set_long_long(a, frac); - if (res != MP_OKAY) { - return res; + if (d < 0) { + d = d * (-1.0); + sign = MP_NEG; + } + /* We do not work on copy, hence clear output memory */ + mp_zero(c); + /* Integers only */ + if (d < 1.0) { + c->sign = sign; + return MP_OKAY; } - res = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); - if (res != MP_OKAY) { - return res; + frac = s_math_h_less_frexp(d, &expnt); + /* +/-inf if exp > DBL_MAX_EXP */ + if (expnt == (DBL_MAX_EXP + 1)) { + return MP_VAL; } - if (((cast.bits >> 63) != 0ULL) && !IS_ZERO(a)) { - a->sign = MP_NEG; + if (frac == 0.0) { + c->sign = sign; + return MP_OKAY; } + while (expnt-- >= 0) { + frac *= 2.0; + if (frac >= 1.0) { + if ((res = mp_add_d(c, 1, c)) != MP_OKAY) { + return res; + } + frac -= 1.0; + } + if (expnt > 0) { + if ((res = mp_mul_2d(c, 1, c)) != MP_OKAY) { + return res; + } + } + } + c->sign = sign; 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") +# pragma message("mp_set_double implementation is only available on platforms with IEEE754 floating point format.") +# pragma message("At least DBL_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2.") # else # warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" +# warning "At least DBL_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2." # endif #endif #endif From afb7c6340c592b00ebbce8821b6fe30def833b49 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Fri, 15 Feb 2019 03:03:03 +0100 Subject: [PATCH 02/21] added get/set for 'float', 'long double'; additional tests for edgecases ; documentation. --- bn_mp_get_float.c | 41 +++++++++++++++ bn_mp_get_long_double.c | 43 ++++++++++++++++ bn_mp_set_double.c | 91 +++++++++++++++++---------------- bn_mp_set_float.c | 106 +++++++++++++++++++++++++++++++++++++++ bn_mp_set_long_double.c | 89 ++++++++++++++++++++++++++++++++ callgraph.txt | 60 +++++++++++++++++++--- doc/bn.tex | 53 +++++++++++++++++++- libtommath_VS2008.vcproj | 16 ++++++ makefile | 40 +++++++-------- makefile.mingw | 40 +++++++-------- makefile.msvc | 40 +++++++-------- makefile.shared | 40 +++++++-------- makefile.unix | 40 +++++++-------- tommath.h | 25 +++++++-- tommath_class.h | 29 ++++++++++- 15 files changed, 599 insertions(+), 154 deletions(-) create mode 100644 bn_mp_get_float.c create mode 100644 bn_mp_get_long_double.c create mode 100644 bn_mp_set_float.c create mode 100644 bn_mp_set_long_double.c diff --git a/bn_mp_get_float.c b/bn_mp_get_float.c new file mode 100644 index 000000000..4096ee230 --- /dev/null +++ b/bn_mp_get_float.c @@ -0,0 +1,41 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_FLOAT_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 + */ +#ifdef FLT_MAX +/* This function is independent of the implementation of the floating point type */ +float mp_get_float(const mp_int *a) +{ + int i; + float d = 0.0, fac = 1.0; + for (i = 0; i < DIGIT_BIT; ++i) { + fac *= 2.0; + } + for (i = a->used; i --> 0;) { + d = (d * fac) + (float)DIGIT(a, i); + } + return (a->sign == MP_NEG) ? -d : d; +} +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("The type 'float' does not seem to be supported on your system.") +# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# else +# warning "The type 'float' does not seem to be supported on your system." +# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# endif +#endif +#endif +/* ref: \$Format:\%D$ */ +/* git commit: \$Format:\%H$ */ +/* commit time: \$Format:\%ai$ */ diff --git a/bn_mp_get_long_double.c b/bn_mp_get_long_double.c new file mode 100644 index 000000000..fce1eb279 --- /dev/null +++ b/bn_mp_get_long_double.c @@ -0,0 +1,43 @@ +#include "tommath_private.h" +#ifdef BN_MP_GET_LONG_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 + */ + +#ifdef LDBL_MAX +/* This function is independent of the implementation of the floating point type */ +long double mp_get_long_double(const mp_int *a) +{ + int i; + long double d = 0.0, fac = 1.0; + for (i = 0; i < DIGIT_BIT; ++i) { + fac *= 2.0; + } + for (i = a->used; i --> 0;) { + d = (d * fac) + (long double)DIGIT(a, i); + } + return (a->sign == MP_NEG) ? -d : d; +} +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("The type 'long double' does not seem to be supported on your system.") +# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# else +# warning "The type 'long double' does not seem to be supported on your system." +# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# endif +#endif + +#endif +/* ref: \$Format:\%D$ */ +/* git commit: \$Format:\%H$ */ +/* commit time: \$Format:\%ai$ */ diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index 930dde507..693253f8f 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -13,72 +13,79 @@ */ #include -#if ((defined DBL_MAX_EXP) && (FLT_RADIX == 2)) +#if ( (defined DBL_MAX_EXP) && (FLT_RADIX == 2) ) + static double s_math_h_less_frexp(double x, int *exp) { - int exponent = 0; - while (x >= 1.0) { - exponent++; - /* exp > DBL_MAX_EXP + 1, it is inf */ - if (exponent == (DBL_MAX_EXP + 1)) { - *exp = exponent; - return x; - } - x /= 2.0; - } + int exponent = 0; - *exp = exponent; - return x; + while (x >= 1.0) { + exponent++; + if (exponent > DBL_MAX_EXP) { + break; + } + x /= 2.0; + } + *exp = exponent; + return x; } - -int mp_set_double(mp_int *c, double d) +int mp_set_double(mp_int *a, double b) { - int expnt, res, sign = MP_ZPOS; - double frac; - - - if (d != d) { + int exp = 0, res, sign = MP_ZPOS; + /* Check for NaN */ + if (b != b) { return MP_VAL; } - if (d < 0) { - d = d * (-1.0); + + if (b < 0.0) { + b = b * (-1.0); sign = MP_NEG; } - /* We do not work on copy, hence clear output memory */ - mp_zero(c); - /* Integers only */ - if (d < 1.0) { - c->sign = sign; + mp_zero(a); + /* Numbers smaller than 1 truncate to zero */ + if (b < 1.0) { + a->sign = sign; return MP_OKAY; } - frac = s_math_h_less_frexp(d, &expnt); + b = s_math_h_less_frexp(b, &exp); /* +/-inf if exp > DBL_MAX_EXP */ - if (expnt == (DBL_MAX_EXP + 1)) { + if (exp > DBL_MAX_EXP) { return MP_VAL; } - if (frac == 0.0) { - c->sign = sign; - return MP_OKAY; - } - - while (expnt-- >= 0) { - frac *= 2.0; - if (frac >= 1.0) { - if ((res = mp_add_d(c, 1, c)) != MP_OKAY) { + while (exp-- >= 0) { + b *= 2.0; + if (b >= 1.0) { + if ((res = mp_add_d(a, 1, a)) != MP_OKAY) { return res; } - frac -= 1.0; + b -= 1.0; } - if (expnt > 0) { - if ((res = mp_mul_2d(c, 1, c)) != MP_OKAY) { + + if (exp >= 0) { + if ((res = mp_mul_2d(a, 1, a)) != MP_OKAY) { return res; } } + if (b == 0.0) { + exp--; + break; + } + } + + if (res != MP_OKAY) { + return res; } - c->sign = sign; + + res = (exp < 0) ? mp_div_2d(a, -exp, a, NULL) : mp_mul_2d(a, exp, a); + if (res != MP_OKAY) { + return res; + } + + SIGN(a) = sign; + return MP_OKAY; } #else diff --git a/bn_mp_set_float.c b/bn_mp_set_float.c new file mode 100644 index 000000000..91a816c26 --- /dev/null +++ b/bn_mp_set_float.c @@ -0,0 +1,106 @@ +#include "tommath_private.h" +#ifdef BN_MP_SET_FLOAT_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 + */ + + + +#include +#if ( (defined FLT_MAX_EXP) && (FLT_RADIX == 2) ) + +static float s_math_h_less_frexp(float x, int *exp) +{ + int exponent = 0; + + while (x >= 1.0) { + exponent++; + if (exponent > FLT_MAX_EXP) { + break; + } + x /= 2.0; + } + *exp = exponent; + return x; +} + +int mp_set_float(mp_int *a, float b) +{ + int exp = 0, res, sign = MP_ZPOS; + /* Check for NaN */ + if (b != b) { + return MP_VAL; + } + + if (b < 0.0f) { + b = b * (-1.0f); + sign = MP_NEG; + } + mp_zero(a); + /* Numbers smaller than 1 truncate to zero */ + if (b < 1.0f) { + a->sign = sign; + return MP_OKAY; + } + + b = s_math_h_less_frexp(b, &exp); + /* +/-inf if exp > FLT_MAX_EXP */ + if (exp > FLT_MAX_EXP) { + return MP_VAL; + } + + while (exp-- >= 0) { + b *= 2.0f; + if (b >= 1.0f) { + if ((res = mp_add_d(a, 1, a)) != MP_OKAY) { + return res; + } + b -= 1.0f; + } + + if (exp >= 0) { + if ((res = mp_mul_2d(a, 1, a)) != MP_OKAY) { + return res; + } + } + if (b == 0.0f) { + exp--; + break; + } + } + + 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; + } + + SIGN(a) = sign; + + 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_float implementation is only available on platforms with IEEE754 floating point format.") +# pragma message("At least FLT_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2.") +# else +# warning "mp_set_float implementation is only available on platforms with IEEE754 floating point format" +# warning "At least FLT_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2." +# endif +#endif +#endif +/* ref: \$Format:\%D$ */ +/* git commit: \$Format:\%H$ */ +/* commit time: \$Format:\%ai$ */ diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c new file mode 100644 index 000000000..38d93a3c8 --- /dev/null +++ b/bn_mp_set_long_double.c @@ -0,0 +1,89 @@ +#include "tommath_private.h" + +#include +#if ( (defined LDBL_MAX_EXP) && (FLT_RADIX == 2) ) + +static long double s_math_h_less_frexp(long double x, int *exp) +{ + int exponent = 0; + + while (x >= 1.0) { + exponent++; + if (exponent > LDBL_MAX_EXP) { + break; + } + x /= 2.0; + } + *exp = exponent; + return x; +} + +int mp_set_long_double(mp_int *a, long double b) +{ + int exp = 0, res, sign = MP_ZPOS; + /* Check for NaN */ + if (b != b) { + return MP_VAL; + } + + if (b < 0.0L) { + b = b * (-1.0L); + sign = MP_NEG; + } + mp_zero(a); + /* Numbers smaller than 1 truncate to zero */ + if (b < 1.0L) { + a->sign = sign; + return MP_OKAY; + } + + b = s_math_h_less_frexp(b, &exp); + /* +/-inf if exp > LDBL_MAX_EXP */ + if (exp > LDBL_MAX_EXP) { + return MP_VAL; + } + + while (exp-- >= 0) { + b *= 2.0L; + if (b >= 1.0L) { + if ((res = mp_add_d(a, 1, a)) != MP_OKAY) { + return res; + } + b -= 1.0L; + } + + if (exp >= 0) { + if ((res = mp_mul_2d(a, 1, a)) != MP_OKAY) { + return res; + } + } + if (b == 0.0L) { + exp--; + break; + } + } + + 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; + } + + SIGN(a) = sign; + + return MP_OKAY; +} + +#else +/* pragma message() not supported by several compilers (in mostly older but still used versions) */ +# ifdef _MSC_VER +# pragma message("The type 'long double' does not seem to be supported on your system.") +# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# else +# warning "The type 'long double' does not seem to be supported on your system." +# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# endif +#endif diff --git a/callgraph.txt b/callgraph.txt index 565a4ea8b..6d870c031 100644 --- a/callgraph.txt +++ b/callgraph.txt @@ -2332,12 +2332,18 @@ BN_MP_GET_BIT_C BN_MP_GET_DOUBLE_C +BN_MP_GET_FLOAT_C + + BN_MP_GET_INT_C BN_MP_GET_LONG_C +BN_MP_GET_LONG_DOUBLE_C + + BN_MP_GET_LONG_LONG_C @@ -18626,14 +18632,27 @@ BN_MP_SET_C BN_MP_SET_DOUBLE_C -+--->BN_MP_SET_LONG_LONG_C -+--->BN_MP_DIV_2D_C ++--->BN_MP_ZERO_C ++--->BN_MP_ADD_D_C +| +--->BN_MP_GROW_C +| +--->BN_MP_SUB_D_C +| | +--->BN_MP_CLAMP_C +| +--->BN_MP_CLAMP_C ++--->BN_MP_MUL_2D_C | +--->BN_MP_COPY_C | | +--->BN_MP_GROW_C -| +--->BN_MP_ZERO_C -| +--->BN_MP_MOD_2D_C +| +--->BN_MP_GROW_C +| +--->BN_MP_LSHD_C +| | +--->BN_MP_RSHD_C +| +--->BN_MP_CLAMP_C + + +BN_MP_SET_FLOAT_C ++--->BN_MP_ZERO_C ++--->BN_MP_ADD_D_C +| +--->BN_MP_GROW_C +| +--->BN_MP_SUB_D_C | | +--->BN_MP_CLAMP_C -| +--->BN_MP_RSHD_C | +--->BN_MP_CLAMP_C +--->BN_MP_MUL_2D_C | +--->BN_MP_COPY_C @@ -18641,7 +18660,13 @@ BN_MP_SET_DOUBLE_C | +--->BN_MP_GROW_C | +--->BN_MP_LSHD_C | | +--->BN_MP_RSHD_C -| | | +--->BN_MP_ZERO_C +| +--->BN_MP_CLAMP_C ++--->BN_MP_DIV_2D_C +| +--->BN_MP_COPY_C +| | +--->BN_MP_GROW_C +| +--->BN_MP_MOD_2D_C +| | +--->BN_MP_CLAMP_C +| +--->BN_MP_RSHD_C | +--->BN_MP_CLAMP_C @@ -18660,6 +18685,29 @@ BN_MP_SET_INT_C BN_MP_SET_LONG_C +BN_MP_SET_LONG_DOUBLE_C ++--->BN_MP_ZERO_C ++--->BN_MP_ADD_D_C +| +--->BN_MP_GROW_C +| +--->BN_MP_SUB_D_C +| | +--->BN_MP_CLAMP_C +| +--->BN_MP_CLAMP_C ++--->BN_MP_MUL_2D_C +| +--->BN_MP_COPY_C +| | +--->BN_MP_GROW_C +| +--->BN_MP_GROW_C +| +--->BN_MP_LSHD_C +| | +--->BN_MP_RSHD_C +| +--->BN_MP_CLAMP_C ++--->BN_MP_DIV_2D_C +| +--->BN_MP_COPY_C +| | +--->BN_MP_GROW_C +| +--->BN_MP_MOD_2D_C +| | +--->BN_MP_CLAMP_C +| +--->BN_MP_RSHD_C +| +--->BN_MP_CLAMP_C + + BN_MP_SET_LONG_LONG_C diff --git a/doc/bn.tex b/doc/bn.tex index 533c623fb..3e38c13b7 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -900,6 +900,57 @@ \subsection{Long Long Constants} This will return the 64 least significant bits of the mp\_int $a$. +\subsection{Floating Point Constants} + +\index{mp\_set\_double} +\begin{alltt} +int mp_set_double (mp_int * a, double b); +\end{alltt} + +This will assign the value of the \texttt{double} variable $b$ to the mp\_int $a$. Only the integer part of $b$ is read, the fraction part is truncated to $-\infty$. This may lead to irritations if the number $x.99999999999999782$ gets printed as $x + 1$ because of some too optimistic rounding in the printing function but the function \texttt{mp\_get\_double()} reads this number as $x$. + +It returns \texttt{MP\_VAL} in case of $b \in {\textrm{qNaN}, \textrm{sNaN}, -\infty, +\infty}$. + +\index{mp\_get\_double} +\begin{alltt} +double mp_get_double (mp_int * a); +\end{alltt} + +It returns the content of the mp\_int $a$ as a \texttt{double}. As noted above for \texttt{mp\_get\_double}, the final comparison in the following sketch will return $b \not= b_{bis}$ for almost all values of $b$ + +\begin{small} \begin{alltt} +int main(int argc, char **argv) +\{ + mp_int a; + double b, b_bis; + + /* all checks and balances omitted! */ + mp_init(&a); + b = strtod(argv[1], NULL); + mp_set_double (&a, b); + b_bis = mp_get_double (&a); + printf("b = \%16.20f\textbackslash n b_bis = \%16.20f\textbackslash n",b,b_bis); + printf("b \%s b_bis\textbackslash n",(b == b_bis)?"=":"!="); + mp_clear(&a); + return EXIT_SUCCESS; +\} +\end{alltt} \end{small} + +All problematic numbers are larger than or equal to $1$; checking the relative error against a limit $\epsilon$ with $\abs\left(a - b\right)/\min\left(a,b\right) < \epsilon$ is sufficient\footnote{The constant \texttt{DBL\_EPSILON} from \texttt{float.h} would be a good candidate for $\epsilon$}. + +\index{mp\_set\_float} \index{mp\_set\_long\_double} +\begin{alltt} +int mp_set_float (mp_int * a, float b); +float mp_get_float (mp_int * a); +int mp_get_long_double (mp_int * a, long double b); +long double mp_get_long_double (mp_int * a); +\end{alltt} + +All functions listed above work like the versions for \texttt{double} with the same caveats and tips adjusted to the respective types. + +The type \texttt{long double} might not be supported for your architecture/compiler which will cause a warning at compile time. It also might be of a different size from \texttt{double} but that does not get tested. + + \subsection{Initialize and Setting Constants} To both initialize and set small constants the following two functions are available. \index{mp\_init\_set} \index{mp\_init\_set\_int} @@ -1233,7 +1284,7 @@ \subsection{Multiplication by two} \begin{alltt} int mp_tc_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); \end{alltt} -The two-co,mplement version of the function above. This can be used to implement arbitrary-precision two-complement integers together with the two-complement bit-wise operations at page \ref{tcbitwiseops}. +The two-complement version of the function above. This can be used to implement arbitrary-precision two-complement integers together with the two-complement bit-wise operations at page \ref{tcbitwiseops}. It is also not very uncommon to need just the power of two $2^b$; for example the startvalue for the Newton method. diff --git a/libtommath_VS2008.vcproj b/libtommath_VS2008.vcproj index 060dd5941..90a17bac7 100644 --- a/libtommath_VS2008.vcproj +++ b/libtommath_VS2008.vcproj @@ -480,6 +480,10 @@ RelativePath="bn_mp_get_double.c" > + + @@ -488,6 +492,10 @@ RelativePath="bn_mp_get_long.c" > + + @@ -732,6 +740,10 @@ RelativePath="bn_mp_set_double.c" > + + @@ -740,6 +752,10 @@ RelativePath="bn_mp_set_long.c" > + + diff --git a/makefile b/makefile index da89364b9..1c4abfb72 100644 --- a/makefile +++ b/makefile @@ -33,26 +33,26 @@ bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o \ bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_exptmod.o \ bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \ -bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \ -bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o \ -bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o \ -bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o \ -bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ -bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \ -bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \ -bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \ -bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \ -bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \ -bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o bn_mp_read_unsigned_bin.o bn_mp_reduce.o \ -bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o \ -bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o bn_mp_set.o \ -bn_mp_set_double.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_long.o bn_mp_shrink.o \ -bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o \ -bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o bn_mp_tc_or.o bn_mp_tc_xor.o \ -bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \ -bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o \ -bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o bn_s_mp_exptmod.o bn_s_mp_mul_digs.o \ -bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o +bn_mp_get_double.o bn_mp_get_float.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_double.o \ +bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o \ +bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o \ +bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o \ +bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o \ +bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o \ +bn_mp_read_unsigned_bin.o bn_mp_reduce.o bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o \ +bn_mp_set.o bn_mp_set_double.o bn_mp_set_float.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_double.o \ +bn_mp_set_long_long.o bn_mp_shrink.o bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o \ +bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o \ +bn_mp_tc_or.o bn_mp_tc_xor.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_unsigned_bin_n.o bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o \ +bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o \ +bn_s_mp_exptmod.o bn_s_mp_mul_digs.o bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o #END_INS diff --git a/makefile.mingw b/makefile.mingw index 5ad880a09..f88451cba 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -36,26 +36,26 @@ bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o \ bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_exptmod.o \ bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \ -bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \ -bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o \ -bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o \ -bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o \ -bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ -bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \ -bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \ -bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \ -bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \ -bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \ -bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o bn_mp_read_unsigned_bin.o bn_mp_reduce.o \ -bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o \ -bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o bn_mp_set.o \ -bn_mp_set_double.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_long.o bn_mp_shrink.o \ -bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o \ -bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o bn_mp_tc_or.o bn_mp_tc_xor.o \ -bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \ -bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o \ -bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o bn_s_mp_exptmod.o bn_s_mp_mul_digs.o \ -bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o +bn_mp_get_double.o bn_mp_get_float.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_double.o \ +bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o \ +bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o \ +bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o \ +bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o \ +bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o \ +bn_mp_read_unsigned_bin.o bn_mp_reduce.o bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o \ +bn_mp_set.o bn_mp_set_double.o bn_mp_set_float.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_double.o \ +bn_mp_set_long_long.o bn_mp_shrink.o bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o \ +bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o \ +bn_mp_tc_or.o bn_mp_tc_xor.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_unsigned_bin_n.o bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o \ +bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o \ +bn_s_mp_exptmod.o bn_s_mp_mul_digs.o bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o HEADERS_PUB=tommath.h tommath_class.h tommath_superclass.h diff --git a/makefile.msvc b/makefile.msvc index 12d571a2e..3ecd7e4dc 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -28,26 +28,26 @@ bn_mp_cmp_mag.obj bn_mp_cnt_lsb.obj bn_mp_complement.obj bn_mp_copy.obj bn_mp_co bn_mp_div_2.obj bn_mp_div_2d.obj bn_mp_div_3.obj bn_mp_div_d.obj bn_mp_dr_is_modulus.obj bn_mp_dr_reduce.obj \ bn_mp_dr_setup.obj bn_mp_exch.obj bn_mp_export.obj bn_mp_expt_d.obj bn_mp_expt_d_ex.obj bn_mp_exptmod.obj \ bn_mp_exptmod_fast.obj bn_mp_exteuclid.obj bn_mp_fread.obj bn_mp_fwrite.obj bn_mp_gcd.obj bn_mp_get_bit.obj \ -bn_mp_get_double.obj bn_mp_get_int.obj bn_mp_get_long.obj bn_mp_get_long_long.obj bn_mp_grow.obj bn_mp_import.obj \ -bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_multi.obj bn_mp_init_set.obj bn_mp_init_set_int.obj bn_mp_init_size.obj \ -bn_mp_invmod.obj bn_mp_invmod_slow.obj bn_mp_is_square.obj bn_mp_iseven.obj bn_mp_isodd.obj bn_mp_jacobi.obj \ -bn_mp_karatsuba_mul.obj bn_mp_karatsuba_sqr.obj bn_mp_kronecker.obj bn_mp_lcm.obj bn_mp_lshd.obj bn_mp_mod.obj \ -bn_mp_mod_2d.obj bn_mp_mod_d.obj bn_mp_montgomery_calc_normalization.obj bn_mp_montgomery_reduce.obj \ -bn_mp_montgomery_setup.obj bn_mp_mul.obj bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj bn_mp_mulmod.obj \ -bn_mp_n_root.obj bn_mp_n_root_ex.obj bn_mp_neg.obj bn_mp_or.obj bn_mp_prime_fermat.obj \ -bn_mp_prime_frobenius_underwood.obj bn_mp_prime_is_divisible.obj bn_mp_prime_is_prime.obj \ -bn_mp_prime_miller_rabin.obj bn_mp_prime_next_prime.obj bn_mp_prime_rabin_miller_trials.obj \ -bn_mp_prime_random_ex.obj bn_mp_prime_strong_lucas_selfridge.obj bn_mp_radix_size.obj bn_mp_radix_smap.obj \ -bn_mp_rand.obj bn_mp_read_radix.obj bn_mp_read_signed_bin.obj bn_mp_read_unsigned_bin.obj bn_mp_reduce.obj \ -bn_mp_reduce_2k.obj bn_mp_reduce_2k_l.obj bn_mp_reduce_2k_setup.obj bn_mp_reduce_2k_setup_l.obj \ -bn_mp_reduce_is_2k.obj bn_mp_reduce_is_2k_l.obj bn_mp_reduce_setup.obj bn_mp_rshd.obj bn_mp_set.obj \ -bn_mp_set_double.obj bn_mp_set_int.obj bn_mp_set_long.obj bn_mp_set_long_long.obj bn_mp_shrink.obj \ -bn_mp_signed_bin_size.obj bn_mp_sqr.obj bn_mp_sqrmod.obj bn_mp_sqrt.obj bn_mp_sqrtmod_prime.obj bn_mp_sub.obj \ -bn_mp_sub_d.obj bn_mp_submod.obj bn_mp_tc_and.obj bn_mp_tc_div_2d.obj bn_mp_tc_or.obj bn_mp_tc_xor.obj \ -bn_mp_to_signed_bin.obj bn_mp_to_signed_bin_n.obj bn_mp_to_unsigned_bin.obj bn_mp_to_unsigned_bin_n.obj \ -bn_mp_toom_mul.obj bn_mp_toom_sqr.obj bn_mp_toradix.obj bn_mp_toradix_n.obj bn_mp_unsigned_bin_size.obj bn_mp_xor.obj \ -bn_mp_zero.obj bn_prime_tab.obj bn_reverse.obj bn_s_mp_add.obj bn_s_mp_exptmod.obj bn_s_mp_mul_digs.obj \ -bn_s_mp_mul_high_digs.obj bn_s_mp_sqr.obj bn_s_mp_sub.obj bncore.obj +bn_mp_get_double.obj bn_mp_get_float.obj bn_mp_get_int.obj bn_mp_get_long.obj bn_mp_get_long_double.obj \ +bn_mp_get_long_long.obj bn_mp_grow.obj bn_mp_import.obj bn_mp_init.obj bn_mp_init_copy.obj bn_mp_init_multi.obj \ +bn_mp_init_set.obj bn_mp_init_set_int.obj bn_mp_init_size.obj bn_mp_invmod.obj bn_mp_invmod_slow.obj \ +bn_mp_is_square.obj bn_mp_iseven.obj bn_mp_isodd.obj bn_mp_jacobi.obj bn_mp_karatsuba_mul.obj bn_mp_karatsuba_sqr.obj \ +bn_mp_kronecker.obj bn_mp_lcm.obj bn_mp_lshd.obj bn_mp_mod.obj bn_mp_mod_2d.obj bn_mp_mod_d.obj \ +bn_mp_montgomery_calc_normalization.obj bn_mp_montgomery_reduce.obj bn_mp_montgomery_setup.obj bn_mp_mul.obj \ +bn_mp_mul_2.obj bn_mp_mul_2d.obj bn_mp_mul_d.obj bn_mp_mulmod.obj bn_mp_n_root.obj bn_mp_n_root_ex.obj bn_mp_neg.obj \ +bn_mp_or.obj bn_mp_prime_fermat.obj bn_mp_prime_frobenius_underwood.obj bn_mp_prime_is_divisible.obj \ +bn_mp_prime_is_prime.obj bn_mp_prime_miller_rabin.obj bn_mp_prime_next_prime.obj \ +bn_mp_prime_rabin_miller_trials.obj bn_mp_prime_random_ex.obj bn_mp_prime_strong_lucas_selfridge.obj \ +bn_mp_radix_size.obj bn_mp_radix_smap.obj bn_mp_rand.obj bn_mp_read_radix.obj bn_mp_read_signed_bin.obj \ +bn_mp_read_unsigned_bin.obj bn_mp_reduce.obj bn_mp_reduce_2k.obj bn_mp_reduce_2k_l.obj bn_mp_reduce_2k_setup.obj \ +bn_mp_reduce_2k_setup_l.obj bn_mp_reduce_is_2k.obj bn_mp_reduce_is_2k_l.obj bn_mp_reduce_setup.obj bn_mp_rshd.obj \ +bn_mp_set.obj bn_mp_set_double.obj bn_mp_set_float.obj bn_mp_set_int.obj bn_mp_set_long.obj bn_mp_set_long_double.obj \ +bn_mp_set_long_long.obj bn_mp_shrink.obj bn_mp_signed_bin_size.obj bn_mp_sqr.obj bn_mp_sqrmod.obj bn_mp_sqrt.obj \ +bn_mp_sqrtmod_prime.obj bn_mp_sub.obj bn_mp_sub_d.obj bn_mp_submod.obj bn_mp_tc_and.obj bn_mp_tc_div_2d.obj \ +bn_mp_tc_or.obj bn_mp_tc_xor.obj bn_mp_to_signed_bin.obj bn_mp_to_signed_bin_n.obj bn_mp_to_unsigned_bin.obj \ +bn_mp_to_unsigned_bin_n.obj bn_mp_toom_mul.obj bn_mp_toom_sqr.obj bn_mp_toradix.obj bn_mp_toradix_n.obj \ +bn_mp_unsigned_bin_size.obj bn_mp_xor.obj bn_mp_zero.obj bn_prime_tab.obj bn_reverse.obj bn_s_mp_add.obj \ +bn_s_mp_exptmod.obj bn_s_mp_mul_digs.obj bn_s_mp_mul_high_digs.obj bn_s_mp_sqr.obj bn_s_mp_sub.obj bncore.obj HEADERS_PUB=tommath.h tommath_class.h tommath_superclass.h diff --git a/makefile.shared b/makefile.shared index ac9bad04f..a5b9f60ae 100644 --- a/makefile.shared +++ b/makefile.shared @@ -30,26 +30,26 @@ bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o \ bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_exptmod.o \ bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \ -bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \ -bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o \ -bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o \ -bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o \ -bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ -bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \ -bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \ -bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \ -bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \ -bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \ -bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o bn_mp_read_unsigned_bin.o bn_mp_reduce.o \ -bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o \ -bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o bn_mp_set.o \ -bn_mp_set_double.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_long.o bn_mp_shrink.o \ -bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o \ -bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o bn_mp_tc_or.o bn_mp_tc_xor.o \ -bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \ -bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o \ -bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o bn_s_mp_exptmod.o bn_s_mp_mul_digs.o \ -bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o +bn_mp_get_double.o bn_mp_get_float.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_double.o \ +bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o \ +bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o \ +bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o \ +bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o \ +bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o \ +bn_mp_read_unsigned_bin.o bn_mp_reduce.o bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o \ +bn_mp_set.o bn_mp_set_double.o bn_mp_set_float.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_double.o \ +bn_mp_set_long_long.o bn_mp_shrink.o bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o \ +bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o \ +bn_mp_tc_or.o bn_mp_tc_xor.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_unsigned_bin_n.o bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o \ +bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o \ +bn_s_mp_exptmod.o bn_s_mp_mul_digs.o bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o #END_INS diff --git a/makefile.unix b/makefile.unix index 6c34ec6fb..a5fb5cb20 100644 --- a/makefile.unix +++ b/makefile.unix @@ -37,26 +37,26 @@ bn_mp_cmp_mag.o bn_mp_cnt_lsb.o bn_mp_complement.o bn_mp_copy.o bn_mp_count_bits bn_mp_div_2.o bn_mp_div_2d.o bn_mp_div_3.o bn_mp_div_d.o bn_mp_dr_is_modulus.o bn_mp_dr_reduce.o \ bn_mp_dr_setup.o bn_mp_exch.o bn_mp_export.o bn_mp_expt_d.o bn_mp_expt_d_ex.o bn_mp_exptmod.o \ bn_mp_exptmod_fast.o bn_mp_exteuclid.o bn_mp_fread.o bn_mp_fwrite.o bn_mp_gcd.o bn_mp_get_bit.o \ -bn_mp_get_double.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o \ -bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o \ -bn_mp_invmod.o bn_mp_invmod_slow.o bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o \ -bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o \ -bn_mp_mod_2d.o bn_mp_mod_d.o bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o \ -bn_mp_montgomery_setup.o bn_mp_mul.o bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o \ -bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o bn_mp_or.o bn_mp_prime_fermat.o \ -bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o bn_mp_prime_is_prime.o \ -bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o bn_mp_prime_rabin_miller_trials.o \ -bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o bn_mp_radix_size.o bn_mp_radix_smap.o \ -bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o bn_mp_read_unsigned_bin.o bn_mp_reduce.o \ -bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o bn_mp_reduce_2k_setup_l.o \ -bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o bn_mp_set.o \ -bn_mp_set_double.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_long.o bn_mp_shrink.o \ -bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o bn_mp_sqrtmod_prime.o bn_mp_sub.o \ -bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o bn_mp_tc_or.o bn_mp_tc_xor.o \ -bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \ -bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o bn_mp_unsigned_bin_size.o bn_mp_xor.o \ -bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o bn_s_mp_exptmod.o bn_s_mp_mul_digs.o \ -bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o +bn_mp_get_double.o bn_mp_get_float.o bn_mp_get_int.o bn_mp_get_long.o bn_mp_get_long_double.o \ +bn_mp_get_long_long.o bn_mp_grow.o bn_mp_import.o bn_mp_init.o bn_mp_init_copy.o bn_mp_init_multi.o \ +bn_mp_init_set.o bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_invmod.o bn_mp_invmod_slow.o \ +bn_mp_is_square.o bn_mp_iseven.o bn_mp_isodd.o bn_mp_jacobi.o bn_mp_karatsuba_mul.o bn_mp_karatsuba_sqr.o \ +bn_mp_kronecker.o bn_mp_lcm.o bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mod_d.o \ +bn_mp_montgomery_calc_normalization.o bn_mp_montgomery_reduce.o bn_mp_montgomery_setup.o bn_mp_mul.o \ +bn_mp_mul_2.o bn_mp_mul_2d.o bn_mp_mul_d.o bn_mp_mulmod.o bn_mp_n_root.o bn_mp_n_root_ex.o bn_mp_neg.o \ +bn_mp_or.o bn_mp_prime_fermat.o bn_mp_prime_frobenius_underwood.o bn_mp_prime_is_divisible.o \ +bn_mp_prime_is_prime.o bn_mp_prime_miller_rabin.o bn_mp_prime_next_prime.o \ +bn_mp_prime_rabin_miller_trials.o bn_mp_prime_random_ex.o bn_mp_prime_strong_lucas_selfridge.o \ +bn_mp_radix_size.o bn_mp_radix_smap.o bn_mp_rand.o bn_mp_read_radix.o bn_mp_read_signed_bin.o \ +bn_mp_read_unsigned_bin.o bn_mp_reduce.o bn_mp_reduce_2k.o bn_mp_reduce_2k_l.o bn_mp_reduce_2k_setup.o \ +bn_mp_reduce_2k_setup_l.o bn_mp_reduce_is_2k.o bn_mp_reduce_is_2k_l.o bn_mp_reduce_setup.o bn_mp_rshd.o \ +bn_mp_set.o bn_mp_set_double.o bn_mp_set_float.o bn_mp_set_int.o bn_mp_set_long.o bn_mp_set_long_double.o \ +bn_mp_set_long_long.o bn_mp_shrink.o bn_mp_signed_bin_size.o bn_mp_sqr.o bn_mp_sqrmod.o bn_mp_sqrt.o \ +bn_mp_sqrtmod_prime.o bn_mp_sub.o bn_mp_sub_d.o bn_mp_submod.o bn_mp_tc_and.o bn_mp_tc_div_2d.o \ +bn_mp_tc_or.o bn_mp_tc_xor.o bn_mp_to_signed_bin.o bn_mp_to_signed_bin_n.o bn_mp_to_unsigned_bin.o \ +bn_mp_to_unsigned_bin_n.o bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix.o bn_mp_toradix_n.o \ +bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_prime_tab.o bn_reverse.o bn_s_mp_add.o \ +bn_s_mp_exptmod.o bn_s_mp_mul_digs.o bn_s_mp_mul_high_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o bncore.o HEADERS_PUB=tommath.h tommath_class.h tommath_superclass.h diff --git a/tommath.h b/tommath.h index e0eb2597c..882a63ec6 100644 --- a/tommath.h +++ b/tommath.h @@ -19,6 +19,8 @@ #include "tommath_class.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -201,9 +203,18 @@ void mp_zero(mp_int *a); /* set to a digit */ void mp_set(mp_int *a, mp_digit b); +#ifdef FLT_MAX +/* set a float */ +int mp_set_float(mp_int *a, float b); +#endif +#if (defined DBL_MAX) /* set a double */ int mp_set_double(mp_int *a, double b); - +#endif +#if (defined LDBL_MAX) +/* set a double */ +int mp_set_long_double(mp_int *a, long double b); +#endif /* set a 32-bit const */ int mp_set_int(mp_int *a, unsigned long b); @@ -212,10 +223,18 @@ int mp_set_long(mp_int *a, unsigned long b); /* set a platform dependent unsigned long long value */ int mp_set_long_long(mp_int *a, unsigned long long b); - +#ifdef FLT_MAX +/* get a float */ +float mp_get_float(const mp_int *a); +#endif +#if (defined DBL_MAX) /* get a double */ double mp_get_double(const mp_int *a); - +#endif +#if (defined LDBL_MAX) +/* get a long double */ +long double mp_get_long_double(const mp_int *a); +#endif /* get a 32-bit value */ unsigned long mp_get_int(const mp_int *a); diff --git a/tommath_class.h b/tommath_class.h index 2702c1ca8..fee9516fc 100644 --- a/tommath_class.h +++ b/tommath_class.h @@ -9,6 +9,7 @@ * * SPDX-License-Identifier: Unlicense */ + #if !(defined(LTM1) && defined(LTM2) && defined(LTM3)) #if defined(LTM2) # define LTM3 @@ -60,8 +61,10 @@ # define BN_MP_GCD_C # define BN_MP_GET_BIT_C # define BN_MP_GET_DOUBLE_C +# define BN_MP_GET_FLOAT_C # define BN_MP_GET_INT_C # define BN_MP_GET_LONG_C +# define BN_MP_GET_LONG_DOUBLE_C # define BN_MP_GET_LONG_LONG_C # define BN_MP_GROW_C # define BN_MP_IMPORT_C @@ -123,8 +126,10 @@ # define BN_MP_RSHD_C # define BN_MP_SET_C # define BN_MP_SET_DOUBLE_C +# define BN_MP_SET_FLOAT_C # define BN_MP_SET_INT_C # define BN_MP_SET_LONG_C +# define BN_MP_SET_LONG_DOUBLE_C # define BN_MP_SET_LONG_LONG_C # define BN_MP_SHRINK_C # define BN_MP_SIGNED_BIN_SIZE_C @@ -440,12 +445,18 @@ #if defined(BN_MP_GET_DOUBLE_C) #endif +#if defined(BN_MP_GET_FLOAT_C) +#endif + #if defined(BN_MP_GET_INT_C) #endif #if defined(BN_MP_GET_LONG_C) #endif +#if defined(BN_MP_GET_LONG_DOUBLE_C) +#endif + #if defined(BN_MP_GET_LONG_LONG_C) #endif @@ -910,11 +921,18 @@ #endif #if defined(BN_MP_SET_DOUBLE_C) -# define BN_MP_SET_LONG_LONG_C -# define BN_MP_DIV_2D_C +# define BN_MP_ZERO_C +# define BN_MP_ADD_D_C # define BN_MP_MUL_2D_C #endif +#if defined(BN_MP_SET_FLOAT_C) +# define BN_MP_ZERO_C +# define BN_MP_ADD_D_C +# define BN_MP_MUL_2D_C +# define BN_MP_DIV_2D_C +#endif + #if defined(BN_MP_SET_INT_C) # define BN_MP_ZERO_C # define BN_MP_MUL_2D_C @@ -924,6 +942,13 @@ #if defined(BN_MP_SET_LONG_C) #endif +#if defined(BN_MP_SET_LONG_DOUBLE_C) +# define BN_MP_ZERO_C +# define BN_MP_ADD_D_C +# define BN_MP_MUL_2D_C +# define BN_MP_DIV_2D_C +#endif + #if defined(BN_MP_SET_LONG_LONG_C) #endif From 77e135ddc645828adc3f4de2f097b13ec0b17082 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Mon, 18 Feb 2019 22:31:44 +0100 Subject: [PATCH 03/21] made minad's code default with fallback to more portable but slower implementation; added bare-metal "long double" alternative --- bn_mp_get_float.c | 1 + bn_mp_get_long_double.c | 2 +- bn_mp_set_double.c | 112 ++++++++++++++++++----- bn_mp_set_float.c | 98 +++++++++++++++++--- bn_mp_set_long_double.c | 198 +++++++++++++++++++++++++++++++++++++--- doc/bn.tex | 10 +- tommath.h | 27 +++--- 7 files changed, 382 insertions(+), 66 deletions(-) diff --git a/bn_mp_get_float.c b/bn_mp_get_float.c index 4096ee230..415d746c6 100644 --- a/bn_mp_get_float.c +++ b/bn_mp_get_float.c @@ -11,6 +11,7 @@ * * SPDX-License-Identifier: Unlicense */ +#include #ifdef FLT_MAX /* This function is independent of the implementation of the floating point type */ float mp_get_float(const mp_int *a) diff --git a/bn_mp_get_long_double.c b/bn_mp_get_long_double.c index fce1eb279..d9bc7bbd5 100644 --- a/bn_mp_get_long_double.c +++ b/bn_mp_get_long_double.c @@ -11,7 +11,7 @@ * * SPDX-License-Identifier: Unlicense */ - +#include #ifdef LDBL_MAX /* This function is independent of the implementation of the floating point type */ long double mp_get_long_double(const mp_int *a) diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index 693253f8f..95616fb94 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -11,20 +11,82 @@ * * SPDX-License-Identifier: Unlicense */ - #include -#if ( (defined DBL_MAX_EXP) && (FLT_RADIX == 2) ) +/* Minimum information needed */ +#if ( (defined DBL_MAX) && (FLT_RADIX == 2) ) + +/* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ +#if (((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) && (defined UINT64_MAX)) + +/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ +/* Bits in mantissa without the implied bit */ +#define SIGNIFICANT (DBL_MANT_DIG - 1) +#define BIAS (DBL_MAX_EXP - 1) +/* Maximal unbiased exponent */ +#define MAX_UNBIASED_EXPONENT ((2*DBL_MAX_EXP) - 1) +/* Length of a binary64 without sign bit */ +#define PAYLOAD 63 +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 >> SIGNIFICANT) & (unsigned)MAX_UNBIASED_EXPONENT); + frac = (cast.bits & ((1ULL << SIGNIFICANT) - 1ULL)) | (1ULL << SIGNIFICANT); + + if (exp == MAX_UNBIASED_EXPONENT) { /* +-inf, NaN */ + return MP_VAL; + } + exp -= BIAS + SIGNIFICANT; + + 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 >> PAYLOAD) != 0ULL) && (mp_iszero(a) == MP_NO)) { + SIGN(a) = MP_NEG; + } + + return MP_OKAY; +} + +#else static double s_math_h_less_frexp(double x, int *exp) { - int exponent = 0; + int exponent = 0, i; + double high = 2.0; + double low = 0.5; - while (x >= 1.0) { - exponent++; - if (exponent > DBL_MAX_EXP) { - break; + if (x >= 1.0) { + for (i = 0; x >= high; i++) { + exponent += (1 << i); + x *= low; + low *= low; + high *= high; + } + if (x < 0.5) { + while (x < 0.5) { + x *= 2.0; + exponent--; + } + } + else { + while (x >= 1.0) { + x /= 2.0; + exponent++; + } } - x /= 2.0; } *exp = exponent; return x; @@ -32,8 +94,10 @@ static double s_math_h_less_frexp(double x, int *exp) int mp_set_double(mp_int *a, double b) { - int exp = 0, res, sign = MP_ZPOS; + int exp = 0, res = MP_OKAY, sign = MP_ZPOS; + /* Check for NaN */ + /* TODO: there might be some ompilers who do not return true in case of NaN */ if (b != b) { return MP_VAL; } @@ -42,18 +106,19 @@ int mp_set_double(mp_int *a, double b) b = b * (-1.0); sign = MP_NEG; } + + /* Check for infinity */ + if ( b > DBL_MAX) { + return MP_VAL; + } + mp_zero(a); /* Numbers smaller than 1 truncate to zero */ - if (b < 1.0) { + if (b < 1.0) {puts("b < 1.0"); a->sign = sign; return MP_OKAY; } - b = s_math_h_less_frexp(b, &exp); - /* +/-inf if exp > DBL_MAX_EXP */ - if (exp > DBL_MAX_EXP) { - return MP_VAL; - } while (exp-- >= 0) { b *= 2.0; @@ -63,7 +128,6 @@ int mp_set_double(mp_int *a, double b) } b -= 1.0; } - if (exp >= 0) { if ((res = mp_mul_2d(a, 1, a)) != MP_OKAY) { return res; @@ -74,20 +138,17 @@ int mp_set_double(mp_int *a, double b) break; } } - 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; } - SIGN(a) = sign; - - return MP_OKAY; + return res; } +#endif #else /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER @@ -97,6 +158,15 @@ int mp_set_double(mp_int *a, double b) # warning "mp_set_double implementation is only available on platforms with IEEE754 floating point format" # warning "At least DBL_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2." # endif +#if (FLT_RADIX == 16) +# ifdef _MSC_VER +# pragma message("No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats") +# pragma message("with the compiler option FLOAT(IEEE)") +# else +# warning "No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats" +# warning "with the compiler option FLOAT(IEEE)" +# endif +#endif #endif #endif diff --git a/bn_mp_set_float.c b/bn_mp_set_float.c index 91a816c26..e1ee751e2 100644 --- a/bn_mp_set_float.c +++ b/bn_mp_set_float.c @@ -11,22 +11,79 @@ * * SPDX-License-Identifier: Unlicense */ +#include +#if ( (defined FLT_MAX_EXP) && (FLT_RADIX == 2) ) +/* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ +#if (((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) && (defined UINT32_MAX)) +/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ +/* Bits in mantissa without the implied bit */ +#define SIGNIFICANT (FLT_MANT_DIG - 1) +#define BIAS (FLT_MAX_EXP - 1) +/* Maximal unbiased exponent */ +#define MAX_UNBIASED_EXPONENT ((2*FLT_MAX_EXP) - 1) +/* Length of a binary32 without sign bit */ +#define PAYLOAD 31 +int mp_set_float(mp_int *a, float b) +{ + uint64_t frac; + int exp, res; + union { + float dbl; + uint32_t bits; + } cast; + cast.dbl = b; + exp = (int)((unsigned)(cast.bits >> SIGNIFICANT) & (unsigned)MAX_UNBIASED_EXPONENT); + frac = (cast.bits & ((1UL << SIGNIFICANT) - 1UL)) | (1UL << SIGNIFICANT); -#include -#if ( (defined FLT_MAX_EXP) && (FLT_RADIX == 2) ) + if (exp == MAX_UNBIASED_EXPONENT) { /* +-inf, NaN */ + return MP_VAL; + } + exp -= BIAS + SIGNIFICANT; + res = mp_set_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 >> PAYLOAD) != 0ULL) && (mp_iszero(a) == MP_NO)) { + SIGN(a) = MP_NEG; + } + + return MP_OKAY; +} +#else static float s_math_h_less_frexp(float x, int *exp) { - int exponent = 0; + int exponent = 0, i; + float high = 2.0f; + float low = 0.5f; - while (x >= 1.0) { - exponent++; - if (exponent > FLT_MAX_EXP) { - break; + if (x >= 1.0f) { + for (i = 0; x >= high; i++) { + exponent += (1 << i); + x *= low; + low *= low; + high *= high; + } + if (x < 0.5f) { + while (x < 0.5f) { + x *= 2.0f; + exponent--; + } + } + else { + while (x >= 1.0f) { + x /= 2.0f; + exponent++; + } } - x /= 2.0; } *exp = exponent; return x; @@ -44,6 +101,12 @@ int mp_set_float(mp_int *a, float b) b = b * (-1.0f); sign = MP_NEG; } + + /* Check for infinity */ + if ( b > FLT_MAX) { + return MP_VAL; + } + mp_zero(a); /* Numbers smaller than 1 truncate to zero */ if (b < 1.0f) { @@ -52,10 +115,6 @@ int mp_set_float(mp_int *a, float b) } b = s_math_h_less_frexp(b, &exp); - /* +/-inf if exp > FLT_MAX_EXP */ - if (exp > FLT_MAX_EXP) { - return MP_VAL; - } while (exp-- >= 0) { b *= 2.0f; @@ -90,6 +149,8 @@ int mp_set_float(mp_int *a, float b) return MP_OKAY; } +#endif + #else /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER @@ -99,8 +160,21 @@ int mp_set_float(mp_int *a, float b) # warning "mp_set_float implementation is only available on platforms with IEEE754 floating point format" # warning "At least FLT_MAX_EXP must be defined and set and, for now, FLT_RADIX must be 2." # endif + +#if (FLT_RADIX == 16) +# ifdef _MSC_VER +# pragma message("No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats") +# pragma message("with the compiler option FLOAT(IEEE)") +# else +# warning "No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats" +# warning "with the compiler option FLOAT(IEEE)" +# endif #endif + + #endif +#endif + /* ref: \$Format:\%D$ */ /* git commit: \$Format:\%H$ */ /* commit time: \$Format:\%ai$ */ diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index 38d93a3c8..44570c455 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -1,18 +1,176 @@ #include "tommath_private.h" - +#ifdef BN_MP_SET_LONG_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 + */ #include #if ( (defined LDBL_MAX_EXP) && (FLT_RADIX == 2) ) +/* + We can work bare-metal with x86's 80 bit doubles because we can test for it + and that architecture (used by Intel and AMD) is the only one using that + type of extended precision and is always little endian. + + Well, that is not completely true. Wikipedia says: + + "The Motorola 6888x math coprocessors and the Motorola 68040 and 68060 processors + support this same 64-bit significand extended precision type (similar to the Intel + format although padded to a 96-bit format with 16 unused bits inserted between the + exponent and significand fields[15]). The follow-on Coldfire processors do not + support this 96-bit extended precision format.[16] + + The x87 and Motorola 68881 80-bit formats meet the requirements of the IEEE 754 + double extended format,[17] as does the IEEE 754 128-bit format." + + There is also the use of implementation defined types in the bit field. That + restricts the range of compilers, too. Currently only GCC and CLANG (generic) + are allowed. It is unknown from which version on (tested with gcc 4.8 and clang + 4.2.1 which are both quite old). + + If there are any other problems: please use the second function here and contact + the authors. + */ +#if ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ + && ((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) \ + && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ + && ( (defined __GNUCC__) || (defined __clang__) ) + ) + +/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ +/* Bits in mantissa without the integer bit */ +#define SIGNIFICANT (LDBL_MANT_DIG - 1) +/* bias */ +#define BIAS (LDBL_MAX_EXP - 1) +/* Maximal unbiased exponent (all ones) */ +#define MAX_UNBIASED_EXPONENT ((2*LDBL_MAX_EXP) - 1) +/* Bitlength of actual exponent */ +#define EXPONENT_BITS 15 +int mp_set_long_double(mp_int * a, long double b) +{ + uint64_t frac; + int exp, res; + + /* + padding + 10-byte double (80 bits): + unused 2 byte on i386, 6 byte on x86_84/ia64 + sign 1 bit 79 + exp 15 bits 78-64 bias 16383 + intbit 1 bit 63 set if normalized + man 63 bits 62-0 + + */ + /* + TODO: + This is not standard C, support of the types + uint64_t and uint16_t are implementation defined + if they do not translate to one of the allowed + types "int", "unsigned int", or "signed int" + (additionally "_Bool" in C11). + */ + union { + long double ldbl; + struct { + uint64_t fraction; + uint16_t exponent:EXPONENT_BITS; + /* A bit large, admitted */ + uint16_t sign:1; + /* fill up (i368: to 12 bytes, x86_64: to 16 bytes */ + uint16_t padding; + } ldbl_guts; + } cast; + + cast.ldbl = b; + + exp = (int)cast.ldbl_guts.exponent; + frac = cast.ldbl_guts.fraction; + + /* + Table from https://en.wikipedia.org/wiki/Extended_precision + + exp ind fract diagnosis + 0 0 zero zero + 0 0 non-zero denormal + 0 1 anything ? (legacy from before the 386) + + ~0 00 zero invalid (legacy from before the 386) + ~0 00 non-zero invalid (legacy from before the 386) + ~0 01 anything invalid (legacy from before the 386) + + ~0 10 zero infinity + ~0 10 non-zero sNaN + ~0 11 zero qNaN + ~0 11 non-zero qNaN + + any 0x anything + */ + + /* +-inf, xNaN and "invalid" */ + if (exp == MAX_UNBIASED_EXPONENT) { + return MP_VAL; + } + + mp_zero(a); + + /* zero and denormals*/ + if (exp == 0 ) { + return MP_OKAY; + } + + /* The format of a "long double" is a bit different */ + + /* normalize exponent */ + exp -= BIAS + SIGNIFICANT; + + res = mp_set_long_long(a, frac); + if (res != MP_OKAY) { puts("CCC"); + 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.ldbl_guts.sign == 1) { + SIGN(a) = MP_NEG; + } + + return MP_OKAY; +} +#else static long double s_math_h_less_frexp(long double x, int *exp) { - int exponent = 0; + int exponent = 0, i; + long double high = 2.0; + long double low = 0.5; - while (x >= 1.0) { - exponent++; - if (exponent > LDBL_MAX_EXP) { - break; + if (x >= 1.0L) { + for (i = 0; x >= high; i++) { + exponent += (1 << i); + x *= low; + low *= low; + high *= high; + } + if (x < 0.5L) { + while (x < 0.5L) { + x *= 2.0L; + exponent--; + } + } + else { + while (x >= 1.0L) { + x /= 2.0L; + exponent++; + } } - x /= 2.0; } *exp = exponent; return x; @@ -30,6 +188,12 @@ int mp_set_long_double(mp_int *a, long double b) b = b * (-1.0L); sign = MP_NEG; } + + /* Check for infinity */ + if ( b > LDBL_MAX) { + return MP_VAL; + } + mp_zero(a); /* Numbers smaller than 1 truncate to zero */ if (b < 1.0L) { @@ -38,10 +202,6 @@ int mp_set_long_double(mp_int *a, long double b) } b = s_math_h_less_frexp(b, &exp); - /* +/-inf if exp > LDBL_MAX_EXP */ - if (exp > LDBL_MAX_EXP) { - return MP_VAL; - } while (exp-- >= 0) { b *= 2.0L; @@ -76,7 +236,7 @@ int mp_set_long_double(mp_int *a, long double b) return MP_OKAY; } - +#endif #else /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER @@ -86,4 +246,18 @@ int mp_set_long_double(mp_int *a, long double b) # warning "The type 'long double' does not seem to be supported on your system." # warning "If that is wrong please contact the team at https://github.com/libtommath/" # endif +#if (FLT_RADIX == 16) +# ifdef _MSC_VER +# pragma message("No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats") +# pragma message("with the compiler option FLOAT(IEEE)") +# else +# warning "No radices other than two are supported. IBM's z/OS uses IEEE-754 compliant floats" +# warning "with the compiler option FLOAT(IEEE)" +# endif +#endif #endif +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/doc/bn.tex b/doc/bn.tex index 3e38c13b7..4677aa99b 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -936,9 +936,7 @@ \subsection{Floating Point Constants} \} \end{alltt} \end{small} -All problematic numbers are larger than or equal to $1$; checking the relative error against a limit $\epsilon$ with $\abs\left(a - b\right)/\min\left(a,b\right) < \epsilon$ is sufficient\footnote{The constant \texttt{DBL\_EPSILON} from \texttt{float.h} would be a good candidate for $\epsilon$}. - -\index{mp\_set\_float} \index{mp\_set\_long\_double} +\index{mp\_set\_float} \index{mp\_set\_long\_double} \index{mp\_get\_float} \index{mp\_get\_long\_double} \begin{alltt} int mp_set_float (mp_int * a, float b); float mp_get_float (mp_int * a); @@ -946,9 +944,9 @@ \subsection{Floating Point Constants} long double mp_get_long_double (mp_int * a); \end{alltt} -All functions listed above work like the versions for \texttt{double} with the same caveats and tips adjusted to the respective types. +All functions listed above work like the versions for teh type \texttt{double} with the same caveats and tips adjusted to the respective types. -The type \texttt{long double} might not be supported for your architecture/compiler which will cause a warning at compile time. It also might be of a different size from \texttt{double} but that does not get tested. +The type \texttt{long double} might not be supported for your architecture/compiler which will cause a warning at compile time. \subsection{Initialize and Setting Constants} @@ -1284,7 +1282,7 @@ \subsection{Multiplication by two} \begin{alltt} int mp_tc_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); \end{alltt} -The two-complement version of the function above. This can be used to implement arbitrary-precision two-complement integers together with the two-complement bit-wise operations at page \ref{tcbitwiseops}. +The two-co,mplement version of the function above. This can be used to implement arbitrary-precision two-complement integers together with the two-complement bit-wise operations at page \ref{tcbitwiseops}. It is also not very uncommon to need just the power of two $2^b$; for example the startvalue for the Newton method. diff --git a/tommath.h b/tommath.h index 882a63ec6..fb95e3209 100644 --- a/tommath.h +++ b/tommath.h @@ -19,12 +19,16 @@ #include "tommath_class.h" -#include - #ifdef __cplusplus extern "C" { #endif +/* Check for a modern-ish MacOS that supports IEEE-754 floating point numbers */ +#if ( (defined __APPLE__) && (defined __MACH__) \ + && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) +# define __STDC_IEC_559__ 1 +#endif + /* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */ #if defined(_MSC_VER) || defined(__LLP64__) || defined(__e2k__) || defined(__LCC__) # define MP_32BIT @@ -203,18 +207,15 @@ void mp_zero(mp_int *a); /* set to a digit */ void mp_set(mp_int *a, mp_digit b); -#ifdef FLT_MAX /* set a float */ int mp_set_float(mp_int *a, float b); -#endif -#if (defined DBL_MAX) + /* set a double */ int mp_set_double(mp_int *a, double b); -#endif -#if (defined LDBL_MAX) + /* set a double */ int mp_set_long_double(mp_int *a, long double b); -#endif + /* set a 32-bit const */ int mp_set_int(mp_int *a, unsigned long b); @@ -223,18 +224,16 @@ int mp_set_long(mp_int *a, unsigned long b); /* set a platform dependent unsigned long long value */ int mp_set_long_long(mp_int *a, unsigned long long b); -#ifdef FLT_MAX + /* get a float */ float mp_get_float(const mp_int *a); -#endif -#if (defined DBL_MAX) + /* get a double */ double mp_get_double(const mp_int *a); -#endif -#if (defined LDBL_MAX) + /* get a long double */ long double mp_get_long_double(const mp_int *a); -#endif + /* get a 32-bit value */ unsigned long mp_get_int(const mp_int *a); From 6975d573dcc5325156ed4f251e928fc242ddc797 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Mon, 18 Feb 2019 22:45:01 +0100 Subject: [PATCH 04/21] reinstalled lost backslash --- bn_mp_set_long_double.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index 44570c455..d3046b906 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -41,7 +41,7 @@ #if ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ && ((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) \ && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ - && ( (defined __GNUCC__) || (defined __clang__) ) + && ( (defined __GNUCC__) || (defined __clang__) ) \ ) /* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ From e57ee21b1366d132cc0aed03e61e1d9bc2bc40be Mon Sep 17 00:00:00 2001 From: czurnieden Date: Wed, 20 Feb 2019 18:39:41 +0100 Subject: [PATCH 05/21] update license in prolog --- bn_mp_iseven.c | 3 +-- bn_mp_isodd.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bn_mp_iseven.c b/bn_mp_iseven.c index 4dc72a474..9532fdd30 100644 --- a/bn_mp_iseven.c +++ b/bn_mp_iseven.c @@ -9,8 +9,7 @@ * Michael Fromberger but has been written from scratch with * additional optimizations in place. * - * The library is free for all purposes without any express - * guarantee it works. + * SPDX-License-Identifier: Unlicense */ int mp_iseven(const mp_int *a) diff --git a/bn_mp_isodd.c b/bn_mp_isodd.c index 4a3942c3b..91b5d4b8f 100644 --- a/bn_mp_isodd.c +++ b/bn_mp_isodd.c @@ -9,10 +9,8 @@ * Michael Fromberger but has been written from scratch with * additional optimizations in place. * - * The library is free for all purposes without any express - * guarantee it works. + * SPDX-License-Identifier: Unlicense */ - int mp_isodd(const mp_int *a) { return IS_ODD(a) ? MP_YES : MP_NO; From a0f73b78cfe1bc6893b6d05cfde1dc3b9d65161c Mon Sep 17 00:00:00 2001 From: czurnieden Date: Wed, 20 Feb 2019 18:49:44 +0100 Subject: [PATCH 06/21] mainly fixes --- bn_mp_get_float.c | 7 +- bn_mp_get_long_double.c | 8 +- bn_mp_set_double.c | 42 +++----- bn_mp_set_float.c | 49 ++++----- bn_mp_set_long_double.c | 229 ++++++++++++++++++++-------------------- tommath.h | 21 +++- 6 files changed, 174 insertions(+), 182 deletions(-) diff --git a/bn_mp_get_float.c b/bn_mp_get_float.c index 415d746c6..bf0380526 100644 --- a/bn_mp_get_float.c +++ b/bn_mp_get_float.c @@ -37,6 +37,7 @@ float mp_get_float(const mp_int *a) # endif #endif #endif -/* ref: \$Format:\%D$ */ -/* git commit: \$Format:\%H$ */ -/* commit time: \$Format:\%ai$ */ + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/bn_mp_get_long_double.c b/bn_mp_get_long_double.c index d9bc7bbd5..1c1d11e2e 100644 --- a/bn_mp_get_long_double.c +++ b/bn_mp_get_long_double.c @@ -36,8 +36,8 @@ long double mp_get_long_double(const mp_int *a) # warning "If that is wrong please contact the team at https://github.com/libtommath/" # endif #endif - #endif -/* ref: \$Format:\%D$ */ -/* git commit: \$Format:\%H$ */ -/* commit time: \$Format:\%ai$ */ + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index 95616fb94..3b5390397 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -16,16 +16,7 @@ #if ( (defined DBL_MAX) && (FLT_RADIX == 2) ) /* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ -#if (((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) && (defined UINT64_MAX)) - -/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ -/* Bits in mantissa without the implied bit */ -#define SIGNIFICANT (DBL_MANT_DIG - 1) -#define BIAS (DBL_MAX_EXP - 1) -/* Maximal unbiased exponent */ -#define MAX_UNBIASED_EXPONENT ((2*DBL_MAX_EXP) - 1) -/* Length of a binary64 without sign bit */ -#define PAYLOAD 63 +#if ( (defined __STDC_IEC_559__) && (defined UINT64_MAX) ) int mp_set_double(mp_int *a, double b) { uint64_t frac; @@ -36,13 +27,13 @@ int mp_set_double(mp_int *a, double b) } cast; cast.dbl = b; - exp = (int)((unsigned)(cast.bits >> SIGNIFICANT) & (unsigned)MAX_UNBIASED_EXPONENT); - frac = (cast.bits & ((1ULL << SIGNIFICANT) - 1ULL)) | (1ULL << SIGNIFICANT); + exp = (int)((unsigned)(cast.bits >> (DBL_MANT_DIG - 1)) & (unsigned)((2*DBL_MAX_EXP) - 1)); + frac = (cast.bits & ((1ULL << (DBL_MANT_DIG - 1)) - 1ULL)) | (1ULL << (DBL_MANT_DIG - 1)); - if (exp == MAX_UNBIASED_EXPONENT) { /* +-inf, NaN */ + if (exp == ((2*DBL_MAX_EXP) - 1)) { /* +-inf, NaN */ return MP_VAL; } - exp -= BIAS + SIGNIFICANT; + exp -= (DBL_MAX_EXP - 1) + (DBL_MANT_DIG - 1); res = mp_set_long_long(a, frac); if (res != MP_OKAY) { @@ -53,9 +44,9 @@ int mp_set_double(mp_int *a, double b) if (res != MP_OKAY) { return res; } - - if (((cast.bits >> PAYLOAD) != 0ULL) && (mp_iszero(a) == MP_NO)) { - SIGN(a) = MP_NEG; + /* 63 = number of bits without sign-bit in binary64 */ + if (((cast.bits >> 63) != 0ULL) && (!IS_ZERO(a))) { + a->sign = MP_NEG; } return MP_OKAY; @@ -76,12 +67,11 @@ static double s_math_h_less_frexp(double x, int *exp) high *= high; } if (x < 0.5) { - while (x < 0.5) { - x *= 2.0; - exponent--; - } - } - else { + while (x < 0.5) { + x *= 2.0; + exponent--; + } + } else { while (x >= 1.0) { x /= 2.0; exponent++; @@ -108,13 +98,13 @@ int mp_set_double(mp_int *a, double b) } /* Check for infinity */ - if ( b > DBL_MAX) { + if (b > DBL_MAX) { return MP_VAL; } mp_zero(a); /* Numbers smaller than 1 truncate to zero */ - if (b < 1.0) {puts("b < 1.0"); + if (b < 1.0) { a->sign = sign; return MP_OKAY; } @@ -145,7 +135,7 @@ int mp_set_double(mp_int *a, double b) if (res != MP_OKAY) { return res; } - SIGN(a) = sign; + a-> = sign; return res; } #endif diff --git a/bn_mp_set_float.c b/bn_mp_set_float.c index e1ee751e2..e72860695 100644 --- a/bn_mp_set_float.c +++ b/bn_mp_set_float.c @@ -13,17 +13,9 @@ */ #include #if ( (defined FLT_MAX_EXP) && (FLT_RADIX == 2) ) + /* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ -#if (((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) && (defined UINT32_MAX)) - -/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ -/* Bits in mantissa without the implied bit */ -#define SIGNIFICANT (FLT_MANT_DIG - 1) -#define BIAS (FLT_MAX_EXP - 1) -/* Maximal unbiased exponent */ -#define MAX_UNBIASED_EXPONENT ((2*FLT_MAX_EXP) - 1) -/* Length of a binary32 without sign bit */ -#define PAYLOAD 31 +#if ( (defined __STDC_IEC_559__) && (defined UINT32_MAX) ) int mp_set_float(mp_int *a, float b) { uint64_t frac; @@ -34,13 +26,13 @@ int mp_set_float(mp_int *a, float b) } cast; cast.dbl = b; - exp = (int)((unsigned)(cast.bits >> SIGNIFICANT) & (unsigned)MAX_UNBIASED_EXPONENT); - frac = (cast.bits & ((1UL << SIGNIFICANT) - 1UL)) | (1UL << SIGNIFICANT); + exp = (int)((unsigned)(cast.bits >> (FLT_MANT_DIG - 1)) & (unsigned)((2*FLT_MAX_EXP) - 1)); + frac = (cast.bits & ((1UL << (FLT_MANT_DIG - 1)) - 1UL)) | (1UL << (FLT_MANT_DIG - 1)); - if (exp == MAX_UNBIASED_EXPONENT) { /* +-inf, NaN */ + if (exp == ((2*FLT_MAX_EXP) - 1)) { /* +-inf, NaN */ return MP_VAL; } - exp -= BIAS + SIGNIFICANT; + exp -= (FLT_MAX_EXP - 1) + (FLT_MANT_DIG - 1); res = mp_set_long(a, frac); if (res != MP_OKAY) { @@ -51,9 +43,9 @@ int mp_set_float(mp_int *a, float b) if (res != MP_OKAY) { return res; } - - if (((cast.bits >> PAYLOAD) != 0ULL) && (mp_iszero(a) == MP_NO)) { - SIGN(a) = MP_NEG; + /* 31 = number of bits without sign-bit in binary32 */ + if (((cast.bits >> 31) != 0ULL) && (!IS_ZERO(a))) { + a->sign = MP_NEG; } return MP_OKAY; @@ -73,12 +65,11 @@ static float s_math_h_less_frexp(float x, int *exp) high *= high; } if (x < 0.5f) { - while (x < 0.5f) { - x *= 2.0f; - exponent--; - } - } - else { + while (x < 0.5f) { + x *= 2.0f; + exponent--; + } + } else { while (x >= 1.0f) { x /= 2.0f; exponent++; @@ -103,7 +94,7 @@ int mp_set_float(mp_int *a, float b) } /* Check for infinity */ - if ( b > FLT_MAX) { + if (b > FLT_MAX) { return MP_VAL; } @@ -145,7 +136,7 @@ int mp_set_float(mp_int *a, float b) return res; } - SIGN(a) = sign; + a->sign = sign; return MP_OKAY; } @@ -170,11 +161,9 @@ int mp_set_float(mp_int *a, float b) # warning "with the compiler option FLOAT(IEEE)" # endif #endif - - #endif #endif -/* ref: \$Format:\%D$ */ -/* git commit: \$Format:\%H$ */ -/* commit time: \$Format:\%ai$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index d3046b906..cb93a621e 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -14,7 +14,7 @@ #include #if ( (defined LDBL_MAX_EXP) && (FLT_RADIX == 2) ) -/* +/* We can work bare-metal with x86's 80 bit doubles because we can test for it and that architecture (used by Intel and AMD) is the only one using that type of extended precision and is always little endian. @@ -35,115 +35,115 @@ are allowed. It is unknown from which version on (tested with gcc 4.8 and clang 4.2.1 which are both quite old). - If there are any other problems: please use the second function here and contact + If there are any other problems: please use the third function here and contact the authors. */ -#if ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ - && ((defined __STDC_IEC_559__) || (defined __GCC_IEC_559)) \ - && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ - && ( (defined __GNUCC__) || (defined __clang__) ) \ - ) - -/* To avoid "magic numbers". Some people don't like them, even if their meaning is obvious */ -/* Bits in mantissa without the integer bit */ -#define SIGNIFICANT (LDBL_MANT_DIG - 1) -/* bias */ -#define BIAS (LDBL_MAX_EXP - 1) -/* Maximal unbiased exponent (all ones) */ -#define MAX_UNBIASED_EXPONENT ((2*LDBL_MAX_EXP) - 1) -/* Bitlength of actual exponent */ -#define EXPONENT_BITS 15 -int mp_set_long_double(mp_int * a, long double b) + +/* + Several architectures use "double" for "long double", we can use a shortcut in that case. +*/ +#if ( (LDBL_MANT_DIG == DBL_MANT_DIG) && (LDBL_MAX_EXP == DBL_MAX_EXP) ) +int mp_set_long_double(mp_int *a, long double b) { - uint64_t frac; - int exp, res; - - /* - padding + 10-byte double (80 bits): - unused 2 byte on i386, 6 byte on x86_84/ia64 - sign 1 bit 79 - exp 15 bits 78-64 bias 16383 - intbit 1 bit 63 set if normalized - man 63 bits 62-0 - - */ - /* - TODO: - This is not standard C, support of the types - uint64_t and uint16_t are implementation defined - if they do not translate to one of the allowed - types "int", "unsigned int", or "signed int" - (additionally "_Bool" in C11). - */ - union { - long double ldbl; - struct { - uint64_t fraction; - uint16_t exponent:EXPONENT_BITS; - /* A bit large, admitted */ - uint16_t sign:1; - /* fill up (i368: to 12 bytes, x86_64: to 16 bytes */ - uint16_t padding; - } ldbl_guts; - } cast; - - cast.ldbl = b; - - exp = (int)cast.ldbl_guts.exponent; - frac = cast.ldbl_guts.fraction; - - /* - Table from https://en.wikipedia.org/wiki/Extended_precision - - exp ind fract diagnosis - 0 0 zero zero - 0 0 non-zero denormal - 0 1 anything ? (legacy from before the 386) - - ~0 00 zero invalid (legacy from before the 386) - ~0 00 non-zero invalid (legacy from before the 386) - ~0 01 anything invalid (legacy from before the 386) - - ~0 10 zero infinity - ~0 10 non-zero sNaN - ~0 11 zero qNaN - ~0 11 non-zero qNaN - - any 0x anything - */ - - /* +-inf, xNaN and "invalid" */ - if (exp == MAX_UNBIASED_EXPONENT) { - return MP_VAL; - } - - mp_zero(a); - - /* zero and denormals*/ - if (exp == 0 ) { - return MP_OKAY; - } - - /* The format of a "long double" is a bit different */ - - /* normalize exponent */ - exp -= BIAS + SIGNIFICANT; - - res = mp_set_long_long(a, frac); - if (res != MP_OKAY) { puts("CCC"); - 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.ldbl_guts.sign == 1) { - SIGN(a) = MP_NEG; - } - - return MP_OKAY; + double _b = (double) b; + return mp_set_double(a, _b); +} +#elif ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ + && (defined __STDC_IEC_559__) \ + && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ + && ( (defined __GNUC__) || (defined __clang__) ) \ + ) +int mp_set_long_double(mp_int *a, long double b) +{ + uint64_t frac; + int exp, res; + + /* + padding + 10-byte double (80 bits): + unused 2 byte on i386, 6 byte on x86_84/ia64 + sign 1 bit 79 + exp 15 bits 78-64 bias 16383 + intbit 1 bit 63 set if normalized + man 63 bits 62-0 + + */ + /* + TODO: + This is not standard C, support of the types + uint64_t and uint16_t are implementation defined + if they do not translate to one of the allowed + types "int", "unsigned int", or "signed int" + (additionally "_Bool" in C11). + */ + union { + long double ldbl; + struct { + uint64_t fraction; + uint16_t exponent:15; + /* A bit large, admitted */ + uint16_t sign:1; + /* fill up (i368: to 12 bytes, x86_64: to 16 bytes */ + uint16_t padding; + } ldbl_guts; + } cast; + + cast.ldbl = b; + + exp = (int)cast.ldbl_guts.exponent; + frac = cast.ldbl_guts.fraction; + + /* + Table from https://en.wikipedia.org/wiki/Extended_precision + + exp ind fract diagnosis + 0 0 zero zero + 0 0 non-zero denormal + 0 1 anything ? (legacy from before the 386) + + ~0 00 zero invalid (legacy from before the 386) + ~0 00 non-zero invalid (legacy from before the 386) + ~0 01 anything invalid (legacy from before the 386) + + ~0 10 zero infinity + ~0 10 non-zero sNaN + ~0 11 zero qNaN + ~0 11 non-zero qNaN + + any 0x anything + */ + + /* +-inf, xNaN and "invalid" */ + if (exp == ((2*LDBL_MAX_EXP) - 1)) { + return MP_VAL; + } + + mp_zero(a); + + /* zero and denormals*/ + if (exp == 0) { + return MP_OKAY; + } + + /* The format of a "long double" is a bit different */ + + /* normalize exponent */ + exp -= (LDBL_MAX_EXP - 1) + (LDBL_MANT_DIG - 1); + + 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.ldbl_guts.sign == 1) { + a->sign = MP_NEG; + } + + return MP_OKAY; } #else static long double s_math_h_less_frexp(long double x, int *exp) @@ -160,12 +160,11 @@ static long double s_math_h_less_frexp(long double x, int *exp) high *= high; } if (x < 0.5L) { - while (x < 0.5L) { - x *= 2.0L; - exponent--; - } - } - else { + while (x < 0.5L) { + x *= 2.0L; + exponent--; + } + } else { while (x >= 1.0L) { x /= 2.0L; exponent++; @@ -190,7 +189,7 @@ int mp_set_long_double(mp_int *a, long double b) } /* Check for infinity */ - if ( b > LDBL_MAX) { + if (b > LDBL_MAX) { return MP_VAL; } @@ -232,7 +231,7 @@ int mp_set_long_double(mp_int *a, long double b) return res; } - SIGN(a) = sign; + a->sign = sign; return MP_OKAY; } diff --git a/tommath.h b/tommath.h index fb95e3209..38554f7e8 100644 --- a/tommath.h +++ b/tommath.h @@ -23,10 +23,23 @@ extern "C" { #endif -/* Check for a modern-ish MacOS that supports IEEE-754 floating point numbers */ -#if ( (defined __APPLE__) && (defined __MACH__) \ - && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) -# define __STDC_IEC_559__ 1 +/* + Even with the standard macro __STDC_IEC_559__ not defined the + implementation can come close enough to IEEE_754 compliance + for our purpose. + */ +#if !(defined __STDC_IEC_559__) + /* + A modern MacOS supports IEEE-754 floating point numbers but it needs a bit + of persuasion to come across with that information. + GCC has a finer grained macro but the limitations of IEEE-754 it can describe + are of no interest here. + */ +# if ( (defined __APPLE__) && (defined __MACH__) \ + && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) \ + || (defined __GCC_IEC_559) +# define __STDC_IEC_559__ 1 +# endif #endif /* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */ From aa6577d980ec77e9d1a26f67d7f298169a1a9eeb Mon Sep 17 00:00:00 2001 From: czurnieden Date: Wed, 20 Feb 2019 20:38:28 +0100 Subject: [PATCH 07/21] renamed macro defining limited IEEE-754 compliance --- bn_mp_set_double.c | 4 ++-- bn_mp_set_float.c | 2 +- bn_mp_set_long_double.c | 2 +- tommath.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index 3b5390397..cbe33c553 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -16,7 +16,7 @@ #if ( (defined DBL_MAX) && (FLT_RADIX == 2) ) /* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ -#if ( (defined __STDC_IEC_559__) && (defined UINT64_MAX) ) +#if ( (defined LTM_NEARLY_IEC_559 ) && (defined UINT64_MAX) ) int mp_set_double(mp_int *a, double b) { uint64_t frac; @@ -135,7 +135,7 @@ int mp_set_double(mp_int *a, double b) if (res != MP_OKAY) { return res; } - a-> = sign; + a->sign = sign; return res; } #endif diff --git a/bn_mp_set_float.c b/bn_mp_set_float.c index e72860695..8544c3c80 100644 --- a/bn_mp_set_float.c +++ b/bn_mp_set_float.c @@ -15,7 +15,7 @@ #if ( (defined FLT_MAX_EXP) && (FLT_RADIX == 2) ) /* We can use a faster method if we have an IEEE compliant machine and a working stdint.h */ -#if ( (defined __STDC_IEC_559__) && (defined UINT32_MAX) ) +#if ( (defined LTM_NEARLY_IEC_559 ) && (defined UINT32_MAX) ) int mp_set_float(mp_int *a, float b) { uint64_t frac; diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index cb93a621e..d5a5059d4 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -49,7 +49,7 @@ int mp_set_long_double(mp_int *a, long double b) return mp_set_double(a, _b); } #elif ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ - && (defined __STDC_IEC_559__) \ + && (defined LTM_NEARLY_IEC_559 ) \ && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ && ( (defined __GNUC__) || (defined __clang__) ) \ ) diff --git a/tommath.h b/tommath.h index 38554f7e8..1f6cc4e6e 100644 --- a/tommath.h +++ b/tommath.h @@ -38,7 +38,7 @@ extern "C" { # if ( (defined __APPLE__) && (defined __MACH__) \ && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) \ || (defined __GCC_IEC_559) -# define __STDC_IEC_559__ 1 +# define LTM_NEARLY_IEC_559 1 # endif #endif From f546d1e641a83c2ba5ef49f93176b2dda4eeb319 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Thu, 21 Feb 2019 17:12:35 +0100 Subject: [PATCH 08/21] corrected check for IEEE-compliance --- tommath.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tommath.h b/tommath.h index 1f6cc4e6e..4366d712f 100644 --- a/tommath.h +++ b/tommath.h @@ -23,25 +23,20 @@ extern "C" { #endif -/* - Even with the standard macro __STDC_IEC_559__ not defined the - implementation can come close enough to IEEE_754 compliance - for our purpose. - */ -#if !(defined __STDC_IEC_559__) /* A modern MacOS supports IEEE-754 floating point numbers but it needs a bit of persuasion to come across with that information. GCC has a finer grained macro but the limitations of IEEE-754 it can describe are of no interest here. */ -# if ( (defined __APPLE__) && (defined __MACH__) \ - && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) \ - || (defined __GCC_IEC_559) -# define LTM_NEARLY_IEC_559 1 -# endif +#if ( (defined __APPLE__) && (defined __MACH__) \ + && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) \ + || (defined __GCC_IEC_559) \ + || (defined __STDC_IEC_559__) +# define LTM_NEARLY_IEC_559 1 #endif + /* MS Visual C++ doesn't have a 128bit type for words, so fall back to 32bit MPI's (where words are 64bit) */ #if defined(_MSC_VER) || defined(__LLP64__) || defined(__e2k__) || defined(__LCC__) # define MP_32BIT From 6255b1c440173f7c3e1bb784a99ba375f82dbbac Mon Sep 17 00:00:00 2001 From: czurnieden Date: Thu, 21 Feb 2019 17:14:11 +0100 Subject: [PATCH 09/21] Valgrind does not support long double --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 647e179a2..48ef740d7 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Tests are located in `demo/` and can be built in two flavors. * `make test` creates a test binary that is intended to be run against `mtest`. `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./test`. `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm * `make test_standalone` creates a stand-alone test binary that executes several test routines. +[Valgrind](http://valgrind.org/) does not support `long double` but does not reset the limits in `float.h` accordingly. Please build `demo.c` with the additional compiler flag `-DLTM_MEMCHECK_VALGRIND`, e.g.: + +`CFLAGS=" -DLTM_MEMCHECK_VALGRIND " make test_standalone` + +It will skip the tests for `long double` and prints a reminder to compile and run the tests without that flag to assure numerical correctness. + ## Building and Installing Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details. From 15444f040d1fa375cc3caaa4760f2e6e4ede64c3 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Sun, 24 Feb 2019 19:53:17 +0100 Subject: [PATCH 10/21] Initialize variable to avoid unnecessary clang warning --- bn_mp_set_double.c | 2 +- bn_mp_set_float.c | 2 +- bn_mp_set_long_double.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bn_mp_set_double.c b/bn_mp_set_double.c index cbe33c553..aad0cfd27 100644 --- a/bn_mp_set_double.c +++ b/bn_mp_set_double.c @@ -20,7 +20,7 @@ int mp_set_double(mp_int *a, double b) { uint64_t frac; - int exp, res; + int exp, res = MP_OKAY; union { double dbl; uint64_t bits; diff --git a/bn_mp_set_float.c b/bn_mp_set_float.c index 8544c3c80..49e4d505d 100644 --- a/bn_mp_set_float.c +++ b/bn_mp_set_float.c @@ -19,7 +19,7 @@ int mp_set_float(mp_int *a, float b) { uint64_t frac; - int exp, res; + int exp, res = MP_OKAY; union { float dbl; uint32_t bits; diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index d5a5059d4..8009160a2 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -56,7 +56,7 @@ int mp_set_long_double(mp_int *a, long double b) int mp_set_long_double(mp_int *a, long double b) { uint64_t frac; - int exp, res; + int exp, res = MP_OKAY; /* padding + 10-byte double (80 bits): From 2570a497b917ab32786ad0c5bc7761bcd188994a Mon Sep 17 00:00:00 2001 From: czurnieden Date: Tue, 26 Feb 2019 23:38:07 +0100 Subject: [PATCH 11/21] full m68k+FPU support for get/set floats --- bn_mp_set_long_double.c | 42 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index 8009160a2..77673fa58 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -13,7 +13,6 @@ */ #include #if ( (defined LDBL_MAX_EXP) && (FLT_RADIX == 2) ) - /* We can work bare-metal with x86's 80 bit doubles because we can test for it and that architecture (used by Intel and AMD) is the only one using that @@ -48,9 +47,12 @@ int mp_set_long_double(mp_int *a, long double b) double _b = (double) b; return mp_set_double(a, _b); } +/* + The "long double" on a Sparc64 is either a quad-precision float with LDBL_MANT_DIG = 113 + and LDBL_MAX_EXP = 16384, although in software only. +*/ #elif ( (LDBL_MANT_DIG == 64) && (LDBL_MAX_EXP == 16384) && (defined UINT64_MAX) \ && (defined LTM_NEARLY_IEC_559 ) \ - && !( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) \ && ( (defined __GNUC__) || (defined __clang__) ) \ ) int mp_set_long_double(mp_int *a, long double b) @@ -58,15 +60,6 @@ int mp_set_long_double(mp_int *a, long double b) uint64_t frac; int exp, res = MP_OKAY; - /* - padding + 10-byte double (80 bits): - unused 2 byte on i386, 6 byte on x86_84/ia64 - sign 1 bit 79 - exp 15 bits 78-64 bias 16383 - intbit 1 bit 63 set if normalized - man 63 bits 62-0 - - */ /* TODO: This is not standard C, support of the types @@ -77,13 +70,34 @@ int mp_set_long_double(mp_int *a, long double b) */ union { long double ldbl; - struct { - uint64_t fraction; + /* + To cite a comment from libquadmath: + "On mingw targets the ms-bitfields option is active by default. + Therefore enforce gnu-bitfield style." + And who are we to ignore the advice of experts? + */ + struct +#ifdef __MINGW32__ + __attribute__((gcc_struct)) +#endif + { + /* Set by GCC and Clang which are the only compilers allowed in here. */ +#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + /* The m68k has some padding in the middle */ +#if ( (defined __m68k__) || (defined __MC68K__) || (defined M68000)) + uint16_t sign:1; + uint16_t exponent:15; + uint16_t pad1:16; + uint64_t fraction:64; + uint16_t padrest; +#endif +#else /* __ORDER_LITTLE_ENDIAN__ */ + uint64_t fraction:64; uint16_t exponent:15; - /* A bit large, admitted */ uint16_t sign:1; /* fill up (i368: to 12 bytes, x86_64: to 16 bytes */ uint16_t padding; +#endif } ldbl_guts; } cast; From 2efbd3aca82ff6986e01c9e4aca5f6a8b4db8987 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Tue, 5 Mar 2019 00:15:36 +0100 Subject: [PATCH 12/21] update tests --- demo/test.c | 417 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 410 insertions(+), 7 deletions(-) diff --git a/demo/test.c b/demo/test.c index e316ef3a6..a83dbdd0d 100644 --- a/demo/test.c +++ b/demo/test.c @@ -1,4 +1,85 @@ #include "shared.h" +#if ((defined __m68k__) || (defined __MC68K__) || (defined M68000)) +/* VERY simpel comparing function, for use in this case and this case only! */ +/* There is such a macro in tommath_private.h which is not include'd in this listing */ +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif +static double s_abs(double s_d){ + return (s_d < 0.0)?-s_d:s_d; +} +static float s_absf(float s_d){ + return (s_d < 0.0f)?-s_d:s_d; +} +#include +static int s_compare_doubles(double s_a, double s_b){ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'double# test %g != %g, using fallback test\n", s_a, s_b); +#endif + abs_a = s_abs(s_a); + abs_b = s_abs(s_b); + delta = s_abs(s_a - s_b); + + return ( (delta/MIN(abs_a, abs_b)) < DBL_EPSILON); +} + +static int s_compare_floats(float s_a, float s_b){ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'float' test %g != %g, using fallback test\n", s_a, s_b); +#endif + abs_a = s_absf(s_a); + abs_b = s_absf(s_b); + delta = s_absf(s_a - s_b); + + return ( (delta/MIN(abs_a, abs_b)) < FLT_EPSILON); +} + +static int s_compare_long_double(long double s_a, long double s_b){ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'long double' test %Lg != %Lg, using fallback test \n", s_a, s_b); +#endif + abs_a = s_absf(s_a); + abs_b = s_absf(s_b); + delta = s_absf(s_a - s_b); + + return ( (delta/MIN(abs_a, abs_b)) < LDBL_EPSILON); +} +#define S_COMPARE_DOUBLE(x,y) s_compare_doubles((x),(y)) +#define S_COMPARE_FLOAT(x,y) s_compare_floats((x),(y)) +#define S_COMPARE_LONG_DOUBLE(x,y) s_compare_long_double((x),(y)) +#else +#define S_COMPARE_FLOAT(x,y) ( (x) == (y) ) +#define S_COMPARE_DOUBLE(x,y) ( (x) == (y) ) +#define S_COMPARE_LONG_DOUBLE(x,y) ( (x) == (y) ) +#endif + + float flt_count; + double dbl_count; +#include +#if ( !(defined LTM_MEMCHECK_VALGRIND) && (defined LDBL_MAX)) + long double ldbl_count; +#endif static int test_trivial_stuff(void) { mp_int a, b, c, d; @@ -448,8 +529,10 @@ static int test_mp_set_double(void) { return EXIT_FAILURE; } - /* test mp_get_double/mp_set_double */ -#if defined(__STDC_IEC_559__) || defined(__GCC_IEC_559) + /* test floating point functions */ +#ifdef DBL_MAX + + if (mp_set_double(&a, +1.0/0.0) != MP_VAL) { printf("\nmp_set_double should return MP_VAL for +inf"); goto LBL_ERR; @@ -467,27 +550,347 @@ static int test_mp_set_double(void) { goto LBL_ERR; } + if (mp_set_double(&a, DBL_MAX) != MP_OKAY) { + printf("\nmp_set_double(DBL_MAX) failed"); + goto LBL_ERR; + } + + if (DBL_MAX != mp_get_double(&a)) { + printf("\nmp_get_double(DBL_MAX) bad result! %20.20f != %20.20f \n", DBL_MAX, mp_get_double(&a)); + goto LBL_ERR; + } + if (mp_set_double(&a, DBL_MIN) != MP_OKAY) { + printf("\nmp_set_double(DBL_MIN) failed"); + goto LBL_ERR; + } + if (0.0 != mp_get_double(&a)) { + printf("\nmp_get_double(DBL_MIN) bad result! %20.20f != %20.20f \n", DBL_MAX, mp_get_double(&a)); + goto LBL_ERR; + } + + dbl_count = 1.0; + if (mp_set_double(&a, dbl_count) != MP_OKAY) { + printf("\nmp_set_double(dbl_count) failed"); + goto LBL_ERR; + } + if (dbl_count != mp_get_double(&a)) { + printf("\nmp_get_double(+dbl_count) bad result! %20.20f != %20.20f\n", + dbl_count, mp_get_double(&a)); + goto LBL_ERR; + } + + /* + Test some edge cases to check for rounding errors. + These tests may fail on e.g.: the M68K FPU architecture which + uses more precision for computation than it says it does. That + does cause some curious behaviour. + */ + dbl_count = 2.0; + for (i = 0; i < DBL_MAX_10_EXP; ++i) { + if (mp_set_double(&a, dbl_count) != MP_OKAY) { + printf("\nmp_set_double(dbl_count) failed"); + goto LBL_ERR; + } + if (dbl_count != mp_get_double(&a)) { + printf("\nmp_get_double(+dbl_count) at i = %d bad result! %20.20f != %20.20f\n", + i, dbl_count, mp_get_double(&a)); + goto LBL_ERR; + } + dbl_count = (dbl_count * 2.0); + } + dbl_count = 2.0; + for (i = 0; i < DBL_MAX_10_EXP; ++i) { + if (mp_set_double(&a, dbl_count) != MP_OKAY) { + printf("\nmp_set_double(+dbl_count -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_DOUBLE(dbl_count, mp_get_double(&a))) { + printf("\nmp_get_double(+dbl_count - 1) at i = %d bad result! %20.20f != %20.20f\n", + i, dbl_count, mp_get_double(&a)); + goto LBL_ERR; + } + dbl_count = (dbl_count * 2.0)-1; + } + dbl_count = 2.0; + + for (i = 0; i < DBL_MAX_10_EXP; ++i) { + if (mp_set_double(&a, -dbl_count) != MP_OKAY) { + printf("\nmp_set_double((-dbl_count) -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_DOUBLE(-dbl_count, mp_get_double(&a))) { + printf("\nmp_get_double((-dbl_count) - 1) at i = %d bad result! %20.20f != %20.20f\n", + i, dbl_count, mp_get_double(&a)); + goto LBL_ERR; + } + dbl_count = (dbl_count * 2.0)-1; + } + + /* Take care that everyone gets the same input */ + srand(0xdeadbeefl); for (i = 0; i < 1000; ++i) { int tmp = rand(); - double dbl = (double)tmp * rand() + 1; + double dbl = (double) tmp * rand() + 1.0; if (mp_set_double(&a, dbl) != MP_OKAY) { printf("\nmp_set_double() failed"); goto LBL_ERR; } - if (dbl != mp_get_double(&a)) { - printf("\nmp_get_double() bad result!"); + if (!S_COMPARE_DOUBLE(dbl, mp_get_double(&a))) { + printf("\nmp_get_double(+dbl) at i = %d bad result! %20.20f != %20.20f ",i, -dbl, mp_get_double(&a)); goto LBL_ERR; } if (mp_set_double(&a, -dbl) != MP_OKAY) { printf("\nmp_set_double() failed"); goto LBL_ERR; } - if (-dbl != mp_get_double(&a)) { - printf("\nmp_get_double() bad result!"); + if (!S_COMPARE_DOUBLE(-dbl,mp_get_double(&a))) { + printf("\nmp_get_double(-dbl) at i = %d bad result! %20.20f != %20.20f ",i, -dbl, mp_get_double(&a)); + goto LBL_ERR; + } + } + + printf("\n\nTesting: mp_get_float"); + if (mp_set_float(&a, +1.0f/0.0f) != MP_VAL) { + printf("\nmp_set_float should return MP_VAL for +inf"); + goto LBL_ERR; + } + if (mp_set_float(&a, -1.0f/0.0f) != MP_VAL) { + printf("\nmp_set_float should return MP_VAL for -inf"); + goto LBL_ERR; + } + if (mp_set_float(&a, +0.0f/0.0f) != MP_VAL) { + printf("\nmp_set_float should return MP_VAL for NaN"); + goto LBL_ERR; + } + if (mp_set_float(&a, -0.0f/0.0f) != MP_VAL) { + printf("\nmp_set_float should return MP_VAL for NaN"); + goto LBL_ERR; + } + + if (mp_set_float(&a, FLT_MAX) != MP_OKAY) { + printf("\nmp_set_float(FLT_MAX) failed"); + goto LBL_ERR; + } + + if (!S_COMPARE_FLOAT(FLT_MAX, mp_get_float(&a))) { + printf("\nmp_get_float(FLT_MAX) bad result! %20.20f != %20.20f \n", FLT_MAX, mp_get_float(&a)); + goto LBL_ERR; + } + if (mp_set_float(&a, FLT_MIN) != MP_OKAY) { + printf("\nmp_set_float(FLT_MIN) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(0.0f, mp_get_float(&a))) { + printf("\nmp_get_float(FLT_MIN) bad result! %20.20f != %20.20f \n", FLT_MIN, mp_get_float(&a)); + goto LBL_ERR; + } + + flt_count = 1.0f; + if (mp_set_float(&a, flt_count) != MP_OKAY) { + printf("\nmp_set_float(flt_count) failed 1"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(flt_count,mp_get_float(&a))) { + printf("\nmp_get_float(+flt_count) at i = %d bad result! %20.20f != %20.20f\n", + i, flt_count, mp_get_float(&a)); + goto LBL_ERR; + } + flt_count = 2.0f; + for (i = 0; i < FLT_MAX_10_EXP; ++i) { + if (mp_set_float(&a, flt_count) != MP_OKAY) { + printf("\nmp_set_float(+flt_count) at i = %d bad result! %20.20f != %20.20f\n", + i, flt_count, mp_get_float(&a)); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(flt_count, mp_get_float(&a))) { + printf("\nmp_get_float(+flt_count) at i = %d bad result! %20.20f != %20.20f\n", + i, flt_count, mp_get_float(&a)); + goto LBL_ERR; + } + flt_count = (flt_count * 2.0f); + } + + flt_count = 2.0f; + for (i = 0; i < FLT_MAX_10_EXP; ++i) { + if (mp_set_float(&a, flt_count) != MP_OKAY) { + printf("\nmp_set_float(+flt_count -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(flt_count, mp_get_float(&a))) { + printf("\nmp_get_float(+flt_count - 1) at i = %d bad result! %20.20f != %20.20f\n", + i, flt_count, mp_get_float(&a)); + goto LBL_ERR; + } + flt_count = (flt_count * 2.0f) - 1.0f; + } + + flt_count = 2.0f; + for (i = 0; i < FLT_MAX_10_EXP; ++i) { + if (mp_set_float(&a, -flt_count) != MP_OKAY) { + printf("\nmp_set_float((-flt_count) -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(-flt_count, mp_get_float(&a))) { + printf("\nmp_get_float((-flt_count) - 1) at i = %d bad result! %20.20f != %20.20f\n", + i, flt_count, mp_get_float(&a)); + goto LBL_ERR; + } + flt_count = (flt_count * 2.0f) - 1.0f; + } + + srand(0xdeadbeefl); + for (i = 0; i < 1000; ++i) { + /* Sorry for the implicit but an explicit conversion results in an error with -Wbad-function-cast */ + float dbl = rand() + 1.0f; + if (mp_set_float(&a, dbl) != MP_OKAY) { + printf("\nmp_set_float() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(dbl, mp_get_float(&a))) { + printf("\nmp_get_float(+dbl) at i = %d bad result! %a != %a ",i, -dbl, mp_get_float(&a)); + goto LBL_ERR; + } + if (mp_set_float(&a, -dbl) != MP_OKAY) { + printf("\nmp_set_float() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_FLOAT(-dbl,mp_get_float(&a))) { + printf("\nmp_get_float(-dbl) at i = %d bad result! %a != %a ",i, -dbl, mp_get_float(&a)); + goto LBL_ERR; + } + } + +/* Valgrind does not support "long double" sufficiently */ +#ifdef LTM_MEMCHECK_VALGRIND +# ifdef _MSC_VER +# pragma message("The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!.") +# pragma message("Please run tests outside of valgrind, too!") +# else +# warning "The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!." +# warning "Please run tests outside of valgrind, too!" +# endif +#endif +#if ( !(defined LTM_MEMCHECK_VALGRIND) && (defined LDBL_MAX)) + printf("\n\nTesting: mp_get_long_double"); + if (mp_set_long_double(&a, +1.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for +inf"); + goto LBL_ERR; + } + if (mp_set_long_double(&a, -1.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for -inf"); + goto LBL_ERR; + } + if (mp_set_long_double(&a, +0.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for NaN"); + goto LBL_ERR; + } + if (mp_set_long_double(&a, -0.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for NaN"); + goto LBL_ERR; + } + if (mp_set_long_double(&a, LDBL_MAX) != MP_OKAY) { + printf("\nmp_set_long_double(LDBL_MAX) failed"); + goto LBL_ERR; + } + + if (!S_COMPARE_LONG_DOUBLE(LDBL_MAX, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(LDBL_MAX) bad result! %20.20Lf != %20.20Lf \n", + LDBL_MAX, mp_get_long_double(&a)); + goto LBL_ERR; + } + if (mp_set_long_double(&a, LDBL_MIN) != MP_OKAY) { + printf("\nmp_set_long_double(LDBL_MIN) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(0.0L, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(LDBL_MIN) bad result! %20.20Lf != %20.20Lf \n", + LDBL_MIN, mp_get_long_double(&a)); + goto LBL_ERR; + } + + ldbl_count = 1.0L; + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(ldbl_count) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + + ldbl_count = 2.0L; + /* + We need to use LDBL_MAX_10_EXP because some compilers accept "long double" + but use "double" instead. + */ + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(ldbl_count) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L); + } + ldbl_count = 2.0L; + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(+ldbl_count -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L) - 1.0L; + } + ldbl_count = 2.0L; + + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, -ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double((-ldbl_count) -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(-ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double((-ldbl_count) - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L) - 1.0L; + } + + + srand(0xdeadbeefl); + for (i = 0; i < 1000; ++i) { + int tmp = rand(); + long double dbl = (long double) tmp * rand() + 1.0L; + if (mp_set_long_double(&a, dbl) != MP_OKAY) { + printf("\nmp_set_long_double() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(dbl, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", + i, -dbl, mp_get_long_double(&a)); + goto LBL_ERR; + } + if (mp_set_long_double(&a, -dbl) != MP_OKAY) { + printf("\nmp_set_long_double() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(-dbl,mp_get_long_double(&a))) { + printf("\nmp_get_long_double(-dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", + i, -dbl, mp_get_long_double(&a)); goto LBL_ERR; } } #endif +#endif + mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; From af9580768b62e9f794104791787aa83b7d6f3eab Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 14:14:04 +0100 Subject: [PATCH 13/21] run `make astyle` --- bn_mp_set_long_double.c | 2 +- demo/main.c | 2 +- demo/opponent.c | 2 +- demo/test.c | 172 ++++++++++++++++++++++++---------------- tommath.h | 12 +-- 5 files changed, 111 insertions(+), 79 deletions(-) diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index 77673fa58..1adc12f53 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -47,7 +47,7 @@ int mp_set_long_double(mp_int *a, long double b) double _b = (double) b; return mp_set_double(a, _b); } -/* +/* The "long double" on a Sparc64 is either a quad-precision float with LDBL_MANT_DIG = 113 and LDBL_MAX_EXP = 16384, although in software only. */ diff --git a/demo/main.c b/demo/main.c index 561a3d2cd..fafb61d42 100644 --- a/demo/main.c +++ b/demo/main.c @@ -3,7 +3,7 @@ int mtest_opponent(void); int unit_tests(void); -void ndraw(mp_int* a, const char* name) +void ndraw(mp_int *a, const char *name) { char *buf; int size; diff --git a/demo/opponent.c b/demo/opponent.c index b52ff72ff..d7013250c 100644 --- a/demo/opponent.c +++ b/demo/opponent.c @@ -379,7 +379,7 @@ int mtest_opponent(void) printf("\n"); return 0; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, &e, &f, NULL); printf("\n"); return EXIT_FAILURE; diff --git a/demo/test.c b/demo/test.c index a83dbdd0d..81fae61ba 100644 --- a/demo/test.c +++ b/demo/test.c @@ -5,14 +5,17 @@ #ifndef MIN #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif -static double s_abs(double s_d){ +static double s_abs(double s_d) +{ return (s_d < 0.0)?-s_d:s_d; } -static float s_absf(float s_d){ +static float s_absf(float s_d) +{ return (s_d < 0.0f)?-s_d:s_d; } #include -static int s_compare_doubles(double s_a, double s_b){ +static int s_compare_doubles(double s_a, double s_b) +{ double abs_a, abs_b, delta; /* NaN, inf's and subnormals ignored, not needed in this case*/ @@ -27,10 +30,11 @@ static int s_compare_doubles(double s_a, double s_b){ abs_b = s_abs(s_b); delta = s_abs(s_a - s_b); - return ( (delta/MIN(abs_a, abs_b)) < DBL_EPSILON); + return ((delta/MIN(abs_a, abs_b)) < DBL_EPSILON); } -static int s_compare_floats(float s_a, float s_b){ +static int s_compare_floats(float s_a, float s_b) +{ double abs_a, abs_b, delta; /* NaN, inf's and subnormals ignored, not needed in this case*/ @@ -45,10 +49,11 @@ static int s_compare_floats(float s_a, float s_b){ abs_b = s_absf(s_b); delta = s_absf(s_a - s_b); - return ( (delta/MIN(abs_a, abs_b)) < FLT_EPSILON); + return ((delta/MIN(abs_a, abs_b)) < FLT_EPSILON); } -static int s_compare_long_double(long double s_a, long double s_b){ +static int s_compare_long_double(long double s_a, long double s_b) +{ double abs_a, abs_b, delta; /* NaN, inf's and subnormals ignored, not needed in this case*/ @@ -57,13 +62,14 @@ static int s_compare_long_double(long double s_a, long double s_b){ return 1; } #ifdef LTM_WARN_X87_EXT_PREC - fprintf(stderr, "Warning: extended precision detected for 'long double' test %Lg != %Lg, using fallback test \n", s_a, s_b); + fprintf(stderr, "Warning: extended precision detected for 'long double' test %Lg != %Lg, using fallback test \n", s_a, + s_b); #endif abs_a = s_absf(s_a); abs_b = s_absf(s_b); delta = s_absf(s_a - s_b); - return ( (delta/MIN(abs_a, abs_b)) < LDBL_EPSILON); + return ((delta/MIN(abs_a, abs_b)) < LDBL_EPSILON); } #define S_COMPARE_DOUBLE(x,y) s_compare_doubles((x),(y)) #define S_COMPARE_FLOAT(x,y) s_compare_floats((x),(y)) @@ -74,14 +80,15 @@ static int s_compare_long_double(long double s_a, long double s_b){ #define S_COMPARE_LONG_DOUBLE(x,y) ( (x) == (y) ) #endif - float flt_count; - double dbl_count; +float flt_count; +double dbl_count; #include #if ( !(defined LTM_MEMCHECK_VALGRIND) && (defined LDBL_MAX)) - long double ldbl_count; +long double ldbl_count; #endif -static int test_trivial_stuff(void) { +static int test_trivial_stuff(void) +{ mp_int a, b, c, d; if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { return EXIT_FAILURE; @@ -92,7 +99,7 @@ static int test_trivial_stuff(void) { /* a: 5-> b: -5 */ mp_neg(&a, &b); if (mp_cmp(&a, &b) != MP_GT) { - goto LBL_ERR; + goto LBL_ERR; } if (mp_cmp(&b, &a) != MP_LT) { goto LBL_ERR; @@ -143,12 +150,13 @@ static int test_trivial_stuff(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_jacobi(void) { +static int test_mp_jacobi(void) +{ struct mp_jacobi_st { unsigned long n; int c[16]; @@ -202,12 +210,13 @@ static int test_mp_jacobi(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_kronecker(void) { +static int test_mp_kronecker(void) +{ struct mp_kronecker_st { long n; int c[21]; @@ -284,12 +293,13 @@ static int test_mp_kronecker(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_complement(void) { +static int test_mp_complement(void) +{ int i; mp_int a, b, c; @@ -317,12 +327,13 @@ static int test_mp_complement(void) { mp_clear_multi(&a, &b, &c, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, NULL); return EXIT_FAILURE; } -static int test_mp_tc_div_2d(void) { +static int test_mp_tc_div_2d(void) +{ int i; mp_int a, b, d; @@ -353,13 +364,14 @@ static int test_mp_tc_div_2d(void) { mp_clear_multi(&a, &b, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &d, NULL); return EXIT_FAILURE; } -static int test_mp_tc_xor(void) { +static int test_mp_tc_xor(void) +{ int i; mp_int a, b, c, d; @@ -393,13 +405,14 @@ static int test_mp_tc_xor(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_tc_or(void) { +static int test_mp_tc_or(void) +{ int i; mp_int a, b, c, d; @@ -433,12 +446,13 @@ static int test_mp_tc_or(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_tc_and(void) { +static int test_mp_tc_and(void) +{ int i; mp_int a, b, c, d; @@ -472,12 +486,13 @@ static int test_mp_tc_and(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_invmod(void) { +static int test_mp_invmod(void) +{ mp_int a, b, c, d; if (mp_init_multi(&a, &b, &c, &d, NULL)!= MP_OKAY) { return EXIT_FAILURE; @@ -515,13 +530,14 @@ static int test_mp_invmod(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_set_double(void) { +static int test_mp_set_double(void) +{ int i; mp_int a, b; @@ -575,7 +591,7 @@ static int test_mp_set_double(void) { } if (dbl_count != mp_get_double(&a)) { printf("\nmp_get_double(+dbl_count) bad result! %20.20f != %20.20f\n", - dbl_count, mp_get_double(&a)); + dbl_count, mp_get_double(&a)); goto LBL_ERR; } @@ -593,7 +609,7 @@ static int test_mp_set_double(void) { } if (dbl_count != mp_get_double(&a)) { printf("\nmp_get_double(+dbl_count) at i = %d bad result! %20.20f != %20.20f\n", - i, dbl_count, mp_get_double(&a)); + i, dbl_count, mp_get_double(&a)); goto LBL_ERR; } dbl_count = (dbl_count * 2.0); @@ -606,7 +622,7 @@ static int test_mp_set_double(void) { } if (!S_COMPARE_DOUBLE(dbl_count, mp_get_double(&a))) { printf("\nmp_get_double(+dbl_count - 1) at i = %d bad result! %20.20f != %20.20f\n", - i, dbl_count, mp_get_double(&a)); + i, dbl_count, mp_get_double(&a)); goto LBL_ERR; } dbl_count = (dbl_count * 2.0)-1; @@ -620,7 +636,7 @@ static int test_mp_set_double(void) { } if (!S_COMPARE_DOUBLE(-dbl_count, mp_get_double(&a))) { printf("\nmp_get_double((-dbl_count) - 1) at i = %d bad result! %20.20f != %20.20f\n", - i, dbl_count, mp_get_double(&a)); + i, dbl_count, mp_get_double(&a)); goto LBL_ERR; } dbl_count = (dbl_count * 2.0)-1; @@ -760,7 +776,7 @@ static int test_mp_set_double(void) { } } -/* Valgrind does not support "long double" sufficiently */ + /* Valgrind does not support "long double" sufficiently */ #ifdef LTM_MEMCHECK_VALGRIND # ifdef _MSC_VER # pragma message("The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!.") @@ -894,13 +910,14 @@ static int test_mp_set_double(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_get_int(void) { +static int test_mp_get_int(void) +{ unsigned long t; int i; @@ -930,12 +947,13 @@ static int test_mp_get_int(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_get_long(void) { +static int test_mp_get_long(void) +{ unsigned long s, t; int i; @@ -965,12 +983,13 @@ static int test_mp_get_long(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_get_long_long(void) { +static int test_mp_get_long_long(void) +{ unsigned long long q, r; int i; @@ -1000,13 +1019,14 @@ static int test_mp_get_long_long(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_sqrt(void) { +static int test_mp_sqrt(void) +{ int i, n; mp_int a, b, c, d; @@ -1037,12 +1057,13 @@ static int test_mp_sqrt(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_is_square(void) { +static int test_mp_is_square(void) +{ int i, n; mp_int a, b; @@ -1083,12 +1104,13 @@ static int test_mp_is_square(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_sqrtmod_prime(void) { +static int test_mp_sqrtmod_prime(void) +{ struct mp_sqrtmod_prime_st { unsigned long p; unsigned long n; @@ -1124,7 +1146,7 @@ static int test_mp_sqrtmod_prime(void) { mp_clear_multi(&a, &b, &c, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, NULL); return EXIT_FAILURE; } @@ -1154,7 +1176,8 @@ static int myrng(unsigned char *dst, int len, void *dat) return len; } -static int test_mp_prime_random_ex(void) { +static int test_mp_prime_random_ex(void) +{ int ix, err; mp_int a, b; @@ -1182,12 +1205,13 @@ static int test_mp_prime_random_ex(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_prime_is_prime(void) { +static int test_mp_prime_is_prime(void) +{ int ix, err, cnt; mp_int a, b; @@ -1288,13 +1312,14 @@ static int test_mp_prime_is_prime(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_montgomery_reduce(void) { +static int test_mp_montgomery_reduce(void) +{ mp_digit mp; int ix, i, n; char buf[4096]; @@ -1351,13 +1376,14 @@ static int test_mp_montgomery_reduce(void) { mp_clear_multi(&a, &b, &c, &d, &e, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, &e, NULL); return EXIT_FAILURE; } -static int test_mp_read_radix(void) { +static int test_mp_read_radix(void) +{ char buf[4096]; mp_int a; @@ -1387,7 +1413,8 @@ static int test_mp_read_radix(void) { return EXIT_SUCCESS; } -static int test_mp_cnt_lsb(void) { +static int test_mp_cnt_lsb(void) +{ int ix; mp_int a, b; @@ -1406,13 +1433,14 @@ static int test_mp_cnt_lsb(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; } -static int test_mp_reduce_2k(void) { +static int test_mp_reduce_2k(void) +{ int ix, cnt; mp_int a, b, c, d; @@ -1449,12 +1477,13 @@ static int test_mp_reduce_2k(void) { mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, NULL); return EXIT_FAILURE; } -static int test_mp_div_3(void) { +static int test_mp_div_3(void) +{ int cnt; mp_int a, b, c, d, e; @@ -1484,12 +1513,13 @@ static int test_mp_div_3(void) { mp_clear_multi(&a, &b, &c, &d, &e, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, &d, &e, NULL); return EXIT_FAILURE; } -static int test_mp_dr_reduce(void) { +static int test_mp_dr_reduce(void) +{ mp_digit mp; int cnt; unsigned rr; @@ -1539,12 +1569,13 @@ static int test_mp_dr_reduce(void) { mp_clear_multi(&a, &b, &c, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, &c, NULL); return EXIT_FAILURE; } -static int test_mp_reduce_2k_l(void) { +static int test_mp_reduce_2k_l(void) +{ # if LTM_DEMO_TEST_REDUCE_2K_L mp_int a, b; if (mp_init_multi(&a, &b, NULL)!= MP_OKAY) { @@ -1600,7 +1631,7 @@ static int test_mp_reduce_2k_l(void) { mp_clear_multi(&a, &b, NULL); return EXIT_SUCCESS; - LBL_ERR: +LBL_ERR: mp_clear_multi(&a, &b, NULL); return EXIT_FAILURE; #else @@ -1608,9 +1639,10 @@ static int test_mp_reduce_2k_l(void) { # endif /* LTM_DEMO_TEST_REDUCE_2K_L */ } -int unit_tests(void) { +int unit_tests(void) +{ static const struct { - const char* name; + const char *name; int (*fn)(void); } test[] = { #define T(n) { #n, test_##n } @@ -1651,7 +1683,7 @@ int unit_tests(void) { } #endif - for (i = 0; i < sizeof (test) / sizeof (test[0]); ++i) { + for (i = 0; i < sizeof(test) / sizeof(test[0]); ++i) { printf("TEST %s\n\n", test[i].name); if (test[i].fn() != EXIT_SUCCESS) { printf("\n\nFAIL %s\n\n", test[i].name); diff --git a/tommath.h b/tommath.h index 4366d712f..25a1a2e9a 100644 --- a/tommath.h +++ b/tommath.h @@ -23,12 +23,12 @@ extern "C" { #endif - /* - A modern MacOS supports IEEE-754 floating point numbers but it needs a bit - of persuasion to come across with that information. - GCC has a finer grained macro but the limitations of IEEE-754 it can describe - are of no interest here. - */ +/* + A modern MacOS supports IEEE-754 floating point numbers but it needs a bit + of persuasion to come across with that information. + GCC has a finer grained macro but the limitations of IEEE-754 it can describe + are of no interest here. + */ #if ( (defined __APPLE__) && (defined __MACH__) \ && ( (defined __DBL_HAS_DENORM__) && ( defined __DBL_HAS_INFINITY__) ) ) \ || (defined __GCC_IEC_559) \ From d608d3826955745521f139645753bfa7f09124ae Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 15:01:45 +0100 Subject: [PATCH 14/21] allow filtering of tests executed --- demo/main.c | 6 +++--- demo/test.c | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/demo/main.c b/demo/main.c index fafb61d42..fe660a463 100644 --- a/demo/main.c +++ b/demo/main.c @@ -1,7 +1,7 @@ #include "shared.h" int mtest_opponent(void); -int unit_tests(void); +int unit_tests(int argc, char **argv); void ndraw(mp_int *a, const char *name) { @@ -24,7 +24,7 @@ void ndraw(mp_int *a, const char *name) free(buf); } -int main(void) +int main(int argc, char **argv) { srand(LTM_DEMO_RAND_SEED); @@ -48,7 +48,7 @@ int main(void) if (LTM_DEMO_TEST_VS_MTEST) { return mtest_opponent(); } - return unit_tests(); + return unit_tests(argc, argv); } /* ref: $Format:%D$ */ diff --git a/demo/test.c b/demo/test.c index 81fae61ba..e254140ad 100644 --- a/demo/test.c +++ b/demo/test.c @@ -1639,7 +1639,7 @@ static int test_mp_reduce_2k_l(void) # endif /* LTM_DEMO_TEST_REDUCE_2K_L */ } -int unit_tests(void) +int unit_tests(int argc, char **argv) { static const struct { const char *name; @@ -1674,7 +1674,7 @@ int unit_tests(void) #undef T }; unsigned long i; - int res = EXIT_SUCCESS; + int res = EXIT_SUCCESS, j; #if defined(LTM_DEMO_REAL_RAND) && !defined(_WIN32) fd_urandom = fopen("/dev/urandom", "r"); @@ -1684,6 +1684,14 @@ int unit_tests(void) #endif for (i = 0; i < sizeof(test) / sizeof(test[0]); ++i) { + if (argc > 1) { + for (j = 1; j < argc; ++j) { + if (strstr(test[i].name, argv[j]) != NULL) { + break; + } + } + if (j == argc) continue; + } printf("TEST %s\n\n", test[i].name); if (test[i].fn() != EXIT_SUCCESS) { printf("\n\nFAIL %s\n\n", test[i].name); From ce8548e63791529f92f932d6db524bc2980f0213 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 15:03:32 +0100 Subject: [PATCH 15/21] move double/float-related stuff right over test_mp_set_double() --- demo/test.c | 175 ++++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 88 deletions(-) diff --git a/demo/test.c b/demo/test.c index e254140ad..22652c90b 100644 --- a/demo/test.c +++ b/demo/test.c @@ -1,91 +1,4 @@ #include "shared.h" -#if ((defined __m68k__) || (defined __MC68K__) || (defined M68000)) -/* VERY simpel comparing function, for use in this case and this case only! */ -/* There is such a macro in tommath_private.h which is not include'd in this listing */ -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif -static double s_abs(double s_d) -{ - return (s_d < 0.0)?-s_d:s_d; -} -static float s_absf(float s_d) -{ - return (s_d < 0.0f)?-s_d:s_d; -} -#include -static int s_compare_doubles(double s_a, double s_b) -{ - double abs_a, abs_b, delta; - - /* NaN, inf's and subnormals ignored, not needed in this case*/ - - if (s_a == s_b) { - return 1; - } -#ifdef LTM_WARN_X87_EXT_PREC - fprintf(stderr, "Warning: extended precision detected for 'double# test %g != %g, using fallback test\n", s_a, s_b); -#endif - abs_a = s_abs(s_a); - abs_b = s_abs(s_b); - delta = s_abs(s_a - s_b); - - return ((delta/MIN(abs_a, abs_b)) < DBL_EPSILON); -} - -static int s_compare_floats(float s_a, float s_b) -{ - double abs_a, abs_b, delta; - - /* NaN, inf's and subnormals ignored, not needed in this case*/ - - if (s_a == s_b) { - return 1; - } -#ifdef LTM_WARN_X87_EXT_PREC - fprintf(stderr, "Warning: extended precision detected for 'float' test %g != %g, using fallback test\n", s_a, s_b); -#endif - abs_a = s_absf(s_a); - abs_b = s_absf(s_b); - delta = s_absf(s_a - s_b); - - return ((delta/MIN(abs_a, abs_b)) < FLT_EPSILON); -} - -static int s_compare_long_double(long double s_a, long double s_b) -{ - double abs_a, abs_b, delta; - - /* NaN, inf's and subnormals ignored, not needed in this case*/ - - if (s_a == s_b) { - return 1; - } -#ifdef LTM_WARN_X87_EXT_PREC - fprintf(stderr, "Warning: extended precision detected for 'long double' test %Lg != %Lg, using fallback test \n", s_a, - s_b); -#endif - abs_a = s_absf(s_a); - abs_b = s_absf(s_b); - delta = s_absf(s_a - s_b); - - return ((delta/MIN(abs_a, abs_b)) < LDBL_EPSILON); -} -#define S_COMPARE_DOUBLE(x,y) s_compare_doubles((x),(y)) -#define S_COMPARE_FLOAT(x,y) s_compare_floats((x),(y)) -#define S_COMPARE_LONG_DOUBLE(x,y) s_compare_long_double((x),(y)) -#else -#define S_COMPARE_FLOAT(x,y) ( (x) == (y) ) -#define S_COMPARE_DOUBLE(x,y) ( (x) == (y) ) -#define S_COMPARE_LONG_DOUBLE(x,y) ( (x) == (y) ) -#endif - -float flt_count; -double dbl_count; -#include -#if ( !(defined LTM_MEMCHECK_VALGRIND) && (defined LDBL_MAX)) -long double ldbl_count; -#endif static int test_trivial_stuff(void) { @@ -536,8 +449,95 @@ static int test_mp_invmod(void) } +#include + +#if ((defined __m68k__) || (defined __MC68K__) || (defined M68000)) +/* VERY simple comparing function, for use in this case and this case only! */ +/* There is such a macro in tommath_private.h which is not include'd in this listing */ +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif +static double s_abs(double s_d) +{ + return (s_d < 0.0)?-s_d:s_d; +} +static float s_absf(float s_d) +{ + return (s_d < 0.0f)?-s_d:s_d; +} +static int s_compare_doubles(double s_a, double s_b) +{ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'double# test %g != %g, using fallback test\n", s_a, s_b); +#endif + abs_a = s_abs(s_a); + abs_b = s_abs(s_b); + delta = s_abs(s_a - s_b); + + return ((delta/MIN(abs_a, abs_b)) < DBL_EPSILON); +} + +static int s_compare_floats(float s_a, float s_b) +{ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'float' test %g != %g, using fallback test\n", s_a, s_b); +#endif + abs_a = s_absf(s_a); + abs_b = s_absf(s_b); + delta = s_absf(s_a - s_b); + + return ((delta/MIN(abs_a, abs_b)) < FLT_EPSILON); +} + +static int s_compare_long_double(long double s_a, long double s_b) +{ + double abs_a, abs_b, delta; + + /* NaN, inf's and subnormals ignored, not needed in this case*/ + + if (s_a == s_b) { + return 1; + } +#ifdef LTM_WARN_X87_EXT_PREC + fprintf(stderr, "Warning: extended precision detected for 'long double' test %Lg != %Lg, using fallback test \n", s_a, + s_b); +#endif + abs_a = s_absf(s_a); + abs_b = s_absf(s_b); + delta = s_absf(s_a - s_b); + + return ((delta/MIN(abs_a, abs_b)) < LDBL_EPSILON); +} +#define S_COMPARE_DOUBLE(x,y) s_compare_doubles((x),(y)) +#define S_COMPARE_FLOAT(x,y) s_compare_floats((x),(y)) +#define S_COMPARE_LONG_DOUBLE(x,y) s_compare_long_double((x),(y)) +#else +#define S_COMPARE_FLOAT(x,y) ( (x) == (y) ) +#define S_COMPARE_DOUBLE(x,y) ( (x) == (y) ) +#define S_COMPARE_LONG_DOUBLE(x,y) ( (x) == (y) ) +#endif + static int test_mp_set_double(void) { + float flt_count; + double dbl_count; +#if (defined LDBL_MAX) + long double ldbl_count; +#endif int i; mp_int a, b; @@ -548,7 +548,6 @@ static int test_mp_set_double(void) /* test floating point functions */ #ifdef DBL_MAX - if (mp_set_double(&a, +1.0/0.0) != MP_VAL) { printf("\nmp_set_double should return MP_VAL for +inf"); goto LBL_ERR; From 37b8cdecb7fb8d4c885eed1c10b46e458f4292be Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 15:22:24 +0100 Subject: [PATCH 16/21] improve valgrind-related stuff a bit --- README.md | 14 +++- demo/test.c | 236 ++++++++++++++++++++++++++++------------------------ 2 files changed, 140 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index 48ef740d7..6db34a852 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,22 @@ Tests are located in `demo/` and can be built in two flavors. * `make test` creates a test binary that is intended to be run against `mtest`. `mtest` can be built with `make mtest` and test execution is done like `./mtest/mtest | ./test`. `mtest` is creating test vectors using an alternative MPI library and `test` is consuming these vectors to verify correct behavior of ltm * `make test_standalone` creates a stand-alone test binary that executes several test routines. -[Valgrind](http://valgrind.org/) does not support `long double` but does not reset the limits in `float.h` accordingly. Please build `demo.c` with the additional compiler flag `-DLTM_MEMCHECK_VALGRIND`, e.g.: +[Valgrind](http://valgrind.org/) does not support `long double` but does not reset the limits in `float.h` accordingly. +Please build `test.c` with the additional compiler flag `-DLTM_MEMCHECK_VALGRIND`, e.g.: -`CFLAGS=" -DLTM_MEMCHECK_VALGRIND " make test_standalone` +``` +CFLAGS=" -DLTM_MEMCHECK_VALGRIND " make test_standalone +```` It will skip the tests for `long double` and prints a reminder to compile and run the tests without that flag to assure numerical correctness. +In case your platform doesn't provide Valgrind at all and the auto-detection fails, please build `test.c` with the additional compiler flag `-DLTM_NO_VALGRIND`, e.g.: + +``` +CFLAGS=" -DLTM_NO_VALGRIND " make test_standalone +```` + + ## Building and Installing Building is straightforward for GNU Linux only, the section "Building LibTomMath" in the documentation in `doc/bn.pdf` has the details. diff --git a/demo/test.c b/demo/test.c index 22652c90b..9e8640b12 100644 --- a/demo/test.c +++ b/demo/test.c @@ -531,6 +531,32 @@ static int s_compare_long_double(long double s_a, long double s_b) #define S_COMPARE_LONG_DOUBLE(x,y) ( (x) == (y) ) #endif +#if (defined LDBL_MAX) + +/* ToDo this needs some work :-) */ +#if (!defined __linux__) +#define LTM_NO_VALGRIND +#endif + +#if (defined LTM_MEMCHECK_VALGRIND) +/* Valgrind does not support "long double" sufficiently */ +# ifdef _MSC_VER +# pragma message("The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!.") +# pragma message("Please run tests outside of valgrind, too!") +# else +# warning "The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!." +# warning "Please run tests outside of valgrind, too!" +# endif +#define LTM_RUNNING_ON_VALGRIND 1 +#elif (defined LTM_NO_VALGRIND) +/* Valgrind is not available */ +#define LTM_RUNNING_ON_VALGRIND 0 +#else +#include +#define LTM_RUNNING_ON_VALGRIND (RUNNING_ON_VALGRIND) +#endif +#endif /* LDBL_MAX */ + static int test_mp_set_double(void) { float flt_count; @@ -775,136 +801,130 @@ static int test_mp_set_double(void) } } - /* Valgrind does not support "long double" sufficiently */ -#ifdef LTM_MEMCHECK_VALGRIND -# ifdef _MSC_VER -# pragma message("The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!.") -# pragma message("Please run tests outside of valgrind, too!") -# else -# warning "The type 'long double' is not sufficiently supported by Valgrind. Tests skipped!." -# warning "Please run tests outside of valgrind, too!" -# endif -#endif -#if ( !(defined LTM_MEMCHECK_VALGRIND) && (defined LDBL_MAX)) - printf("\n\nTesting: mp_get_long_double"); - if (mp_set_long_double(&a, +1.0L/0.0L) != MP_VAL) { - printf("\nmp_set_long_double should return MP_VAL for +inf"); - goto LBL_ERR; - } - if (mp_set_long_double(&a, -1.0L/0.0L) != MP_VAL) { - printf("\nmp_set_long_double should return MP_VAL for -inf"); - goto LBL_ERR; - } - if (mp_set_long_double(&a, +0.0L/0.0L) != MP_VAL) { - printf("\nmp_set_long_double should return MP_VAL for NaN"); - goto LBL_ERR; - } - if (mp_set_long_double(&a, -0.0L/0.0L) != MP_VAL) { - printf("\nmp_set_long_double should return MP_VAL for NaN"); - goto LBL_ERR; - } - if (mp_set_long_double(&a, LDBL_MAX) != MP_OKAY) { - printf("\nmp_set_long_double(LDBL_MAX) failed"); - goto LBL_ERR; - } - - if (!S_COMPARE_LONG_DOUBLE(LDBL_MAX, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(LDBL_MAX) bad result! %20.20Lf != %20.20Lf \n", - LDBL_MAX, mp_get_long_double(&a)); - goto LBL_ERR; - } - if (mp_set_long_double(&a, LDBL_MIN) != MP_OKAY) { - printf("\nmp_set_long_double(LDBL_MIN) failed"); - goto LBL_ERR; - } - if (!S_COMPARE_LONG_DOUBLE(0.0L, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(LDBL_MIN) bad result! %20.20Lf != %20.20Lf \n", - LDBL_MIN, mp_get_long_double(&a)); - goto LBL_ERR; - } - - ldbl_count = 1.0L; - if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { - printf("\nmp_set_long_double(ldbl_count) failed"); - goto LBL_ERR; - } - if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", - i, ldbl_count, mp_get_long_double(&a)); - goto LBL_ERR; - } +#if (defined LDBL_MAX) - ldbl_count = 2.0L; - /* - We need to use LDBL_MAX_10_EXP because some compilers accept "long double" - but use "double" instead. - */ - for (i = 0; i < LDBL_MAX_10_EXP; ++i) { - if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { - printf("\nmp_set_long_double(ldbl_count) failed"); + if (LTM_RUNNING_ON_VALGRIND == 0) { +#undef LTM_RUNNING_ON_VALGRIND + printf("\n\nTesting: mp_get_long_double"); + if (mp_set_long_double(&a, +1.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for +inf"); goto LBL_ERR; } - if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", - i, ldbl_count, mp_get_long_double(&a)); + if (mp_set_long_double(&a, -1.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for -inf"); goto LBL_ERR; } - ldbl_count = (ldbl_count * 2.0L); - } - ldbl_count = 2.0L; - for (i = 0; i < LDBL_MAX_10_EXP; ++i) { - if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { - printf("\nmp_set_long_double(+ldbl_count -1) failed"); + if (mp_set_long_double(&a, +0.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for NaN"); goto LBL_ERR; } - if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(+ldbl_count - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", - i, ldbl_count, mp_get_long_double(&a)); + if (mp_set_long_double(&a, -0.0L/0.0L) != MP_VAL) { + printf("\nmp_set_long_double should return MP_VAL for NaN"); goto LBL_ERR; } - ldbl_count = (ldbl_count * 2.0L) - 1.0L; - } - ldbl_count = 2.0L; - - for (i = 0; i < LDBL_MAX_10_EXP; ++i) { - if (mp_set_long_double(&a, -ldbl_count) != MP_OKAY) { - printf("\nmp_set_long_double((-ldbl_count) -1) failed"); + if (mp_set_long_double(&a, LDBL_MAX) != MP_OKAY) { + printf("\nmp_set_long_double(LDBL_MAX) failed"); goto LBL_ERR; } - if (!S_COMPARE_LONG_DOUBLE(-ldbl_count, mp_get_long_double(&a))) { - printf("\nmp_get_long_double((-ldbl_count) - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", - i, ldbl_count, mp_get_long_double(&a)); + + if (!S_COMPARE_LONG_DOUBLE(LDBL_MAX, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(LDBL_MAX) bad result! %20.20Lf != %20.20Lf \n", + LDBL_MAX, mp_get_long_double(&a)); goto LBL_ERR; } - ldbl_count = (ldbl_count * 2.0L) - 1.0L; - } - - - srand(0xdeadbeefl); - for (i = 0; i < 1000; ++i) { - int tmp = rand(); - long double dbl = (long double) tmp * rand() + 1.0L; - if (mp_set_long_double(&a, dbl) != MP_OKAY) { - printf("\nmp_set_long_double() failed"); + if (mp_set_long_double(&a, LDBL_MIN) != MP_OKAY) { + printf("\nmp_set_long_double(LDBL_MIN) failed"); goto LBL_ERR; } - if (!S_COMPARE_LONG_DOUBLE(dbl, mp_get_long_double(&a))) { - printf("\nmp_get_long_double(+dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", - i, -dbl, mp_get_long_double(&a)); + if (!S_COMPARE_LONG_DOUBLE(0.0L, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(LDBL_MIN) bad result! %20.20Lf != %20.20Lf \n", + LDBL_MIN, mp_get_long_double(&a)); goto LBL_ERR; } - if (mp_set_long_double(&a, -dbl) != MP_OKAY) { - printf("\nmp_set_long_double() failed"); + + ldbl_count = 1.0L; + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(ldbl_count) failed"); goto LBL_ERR; } - if (!S_COMPARE_LONG_DOUBLE(-dbl,mp_get_long_double(&a))) { - printf("\nmp_get_long_double(-dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", - i, -dbl, mp_get_long_double(&a)); + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); goto LBL_ERR; } + + ldbl_count = 2.0L; + /* + We need to use LDBL_MAX_10_EXP because some compilers accept "long double" + but use "double" instead. + */ + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(ldbl_count) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L); + } + ldbl_count = 2.0L; + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double(+ldbl_count -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+ldbl_count - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L) - 1.0L; + } + ldbl_count = 2.0L; + + for (i = 0; i < LDBL_MAX_10_EXP; ++i) { + if (mp_set_long_double(&a, -ldbl_count) != MP_OKAY) { + printf("\nmp_set_long_double((-ldbl_count) -1) failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(-ldbl_count, mp_get_long_double(&a))) { + printf("\nmp_get_long_double((-ldbl_count) - 1) at i = %d bad result! %20.20Lf != %20.20Lf\n", + i, ldbl_count, mp_get_long_double(&a)); + goto LBL_ERR; + } + ldbl_count = (ldbl_count * 2.0L) - 1.0L; + } + + + srand(0xdeadbeefl); + for (i = 0; i < 1000; ++i) { + int tmp = rand(); + long double dbl = (long double) tmp * rand() + 1.0L; + if (mp_set_long_double(&a, dbl) != MP_OKAY) { + printf("\nmp_set_long_double() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(dbl, mp_get_long_double(&a))) { + printf("\nmp_get_long_double(+dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", + i, -dbl, mp_get_long_double(&a)); + goto LBL_ERR; + } + if (mp_set_long_double(&a, -dbl) != MP_OKAY) { + printf("\nmp_set_long_double() failed"); + goto LBL_ERR; + } + if (!S_COMPARE_LONG_DOUBLE(-dbl,mp_get_long_double(&a))) { + printf("\nmp_get_long_double(-dbl) at i = %d bad result! %20.20Lf != %20.20Lf ", + i, -dbl, mp_get_long_double(&a)); + goto LBL_ERR; + } + } } -#endif -#endif +#endif /* LDBL_MAX */ +#endif /* DBL_MAX */ mp_clear_multi(&a, &b, NULL); From c495a3cc3c69a6a8f01b52751bf33adc36af3e69 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 15:33:10 +0100 Subject: [PATCH 17/21] minor changes --- bn_mp_get_float.c | 4 ++-- bn_mp_get_long_double.c | 4 ++-- bn_mp_set_long_double.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bn_mp_get_float.c b/bn_mp_get_float.c index bf0380526..5dada3a49 100644 --- a/bn_mp_get_float.c +++ b/bn_mp_get_float.c @@ -30,10 +30,10 @@ float mp_get_float(const mp_int *a) /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER # pragma message("The type 'float' does not seem to be supported on your system.") -# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# pragma message("If that is wrong please contact the team at https://github.com/libtom/libtommath") # else # warning "The type 'float' does not seem to be supported on your system." -# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# warning "If that is wrong please contact the team at https://github.com/libtom/libtommath" # endif #endif #endif diff --git a/bn_mp_get_long_double.c b/bn_mp_get_long_double.c index 1c1d11e2e..05945f02c 100644 --- a/bn_mp_get_long_double.c +++ b/bn_mp_get_long_double.c @@ -30,10 +30,10 @@ long double mp_get_long_double(const mp_int *a) /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER # pragma message("The type 'long double' does not seem to be supported on your system.") -# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# pragma message("If that is wrong please contact the team at https://github.com/libtom/libtommath") # else # warning "The type 'long double' does not seem to be supported on your system." -# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# warning "If that is wrong please contact the team at https://github.com/libtom/libtommath" # endif #endif #endif diff --git a/bn_mp_set_long_double.c b/bn_mp_set_long_double.c index 1adc12f53..3bc4ce8a1 100644 --- a/bn_mp_set_long_double.c +++ b/bn_mp_set_long_double.c @@ -254,10 +254,10 @@ int mp_set_long_double(mp_int *a, long double b) /* pragma message() not supported by several compilers (in mostly older but still used versions) */ # ifdef _MSC_VER # pragma message("The type 'long double' does not seem to be supported on your system.") -# pragma message("If that is wrong please contact the team at https://github.com/libtommath/") +# pragma message("If that is wrong please contact the team at https://github.com/libtom/libtommath") # else # warning "The type 'long double' does not seem to be supported on your system." -# warning "If that is wrong please contact the team at https://github.com/libtommath/" +# warning "If that is wrong please contact the team at https://github.com/libtom/libtommath" # endif #if (FLT_RADIX == 16) # ifdef _MSC_VER From 67ae060c3c793e0d4307b05496efe90e1f743813 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 7 Mar 2019 19:27:11 +0100 Subject: [PATCH 18/21] add pre-commit hook --- hooks/pre-commit | 47 +++++++++++++++++++++++++++++++++++++++++++++ makefile | 2 +- makefile_include.mk | 3 +++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100755 hooks/pre-commit diff --git a/hooks/pre-commit b/hooks/pre-commit new file mode 100755 index 000000000..47374dac6 --- /dev/null +++ b/hooks/pre-commit @@ -0,0 +1,47 @@ +#!/bin/sh +# + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +if make astyle | grep Formatted ; then + echo "astyle had to do something, please check if you should add those changes" + exit 1 +fi +perl helper.pl --check-all diff --git a/makefile b/makefile index 1c4abfb72..614f7109f 100644 --- a/makefile +++ b/makefile @@ -156,4 +156,4 @@ perlcritic: perlcritic *.pl doc/*.pl astyle: - astyle --options=astylerc $(OBJECTS:.o=.c) tommath*.h demo/*.c etc/*.c mtest/mtest.c + @astyle --options=astylerc --formatted $(OBJECTS:.o=.c) tommath*.h demo/*.c etc/*.c mtest/mtest.c diff --git a/makefile_include.mk b/makefile_include.mk index 421c113dd..a96dd19e1 100644 --- a/makefile_include.mk +++ b/makefile_include.mk @@ -146,3 +146,6 @@ clean: rm -rf .libs/ ${MAKE} -C etc/ clean MAKE=${MAKE} ${MAKE} -C doc/ clean MAKE=${MAKE} + +install_hooks: + for s in `ls hooks/`; do ln -s ../../hooks/$$s .git/hooks/$$s; done From 59c1375a89219e4ac8f9d54ae30b82b7678c9c15 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Thu, 7 Mar 2019 23:47:03 +0100 Subject: [PATCH 19/21] added documentation re x87 warning macro --- doc/bn.tex | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/bn.tex b/doc/bn.tex index 4677aa99b..093ce822d 100644 --- a/doc/bn.tex +++ b/doc/bn.tex @@ -228,6 +228,19 @@ \subsection{Testing} that is being performed. The numbers represent how many times the test was invoked. If an error is detected the program will exit with a dump of the relevant numbers it was working with. +\subsubsection{Testing the Floating-Point Functions} + +If the functions using floating-point are included the tests check for exact equality. The domains and ranges of LibTomMath's floating-point functions are carefully choosen in a way such that an exact check for equality is possible. There are some exemptions for some hardware based on the x87 FPU that work with extended precision. Not in the IEEE meaning (e.g.: a \texttt{long double}) but hidden from the user. In this case the exact equality fails because it is not equal anymore, the hidden extra precision bits differ. The floating-point test-functions in \texttt{demo/test.c} do have a fallback in that case, comparing against \texttt{*\_EPSILON} in the usual manner. The numbers triggering the fallback can be printed to \texttt{stderr}by setting the macro \texttt{LTM\_WARN\_X87\_EXT\_PREC} but be aware that it is either no output at all or a lot of lines. + +The format of the output is (it is one line, broken up for typographical reasons only): +\begin{alltt} +Warning: extended precision detected for \textbackslash + '\$TYPE' test \$NUMBER != \$NUMBER,\textbackslash + using fallback test +\end{alltt} +where \texttt{\$TYPE} is the type of the floating-point number and \texttt{\$NUMBER} the actual value. + + \section{Build Configuration} LibTomMath can configured at build time in three phases we shall call ``depends'', ``tweaks'' and ``trims''. Each phase changes how the library is built and they are applied one after another respectively. From 3de7a5ef0f054010b76a8ebd8be1479655003b76 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Sat, 9 Mar 2019 20:30:57 +0100 Subject: [PATCH 20/21] switched valgrind off in Travis (not installed in Travis) --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37fe211e4..005af53ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,13 +19,13 @@ script: - ./testme.sh --with-cc=$CC ${BUILDOPTIONS} env: - | - BUILDOPTIONS="--test-vs-mtest=333333" + BUILDOPTIONS="--test-vs-mtest=333333 --cflags=-DLTM_NO_VALGRIND" - | - BUILDOPTIONS="--test-vs-mtest=333333 --mtest-real-rand" + BUILDOPTIONS="--test-vs-mtest=333333 --mtest-real-rand --cflags=-DLTM_NO_VALGRIND" - | - BUILDOPTIONS="--with-low-mp" + BUILDOPTIONS="--with-low-mp --cflags=-DLTM_NO_VALGRIND" - | - BUILDOPTIONS="--with-m64 --with-m32 --with-mx32" + BUILDOPTIONS="--with-m64 --with-m32 --with-mx32 --cflags=-DLTM_NO_VALGRIND" after_failure: - cat test_*.log From 40b46f717ffeb35c7f0f67d3afdba2e1d6427c96 Mon Sep 17 00:00:00 2001 From: czurnieden Date: Sat, 9 Mar 2019 22:04:25 +0100 Subject: [PATCH 21/21] added valgrind test --- .travis.yml | 11 +++++++---- testme.sh | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 005af53ca..e2e4ccd95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: c install: - sudo apt-get update -qq + - sudo apt-get install -qq valgrind - sudo apt-get install gcc-multilib matrix: @@ -19,13 +20,15 @@ script: - ./testme.sh --with-cc=$CC ${BUILDOPTIONS} env: - | - BUILDOPTIONS="--test-vs-mtest=333333 --cflags=-DLTM_NO_VALGRIND" + BUILDOPTIONS="--test-vs-mtest=333333" - | - BUILDOPTIONS="--test-vs-mtest=333333 --mtest-real-rand --cflags=-DLTM_NO_VALGRIND" + BUILDOPTIONS="--test-vs-mtest=333333 --mtest-real-rand" - | - BUILDOPTIONS="--with-low-mp --cflags=-DLTM_NO_VALGRIND" + BUILDOPTIONS="--with-low-mp" - | - BUILDOPTIONS="--with-m64 --with-m32 --with-mx32 --cflags=-DLTM_NO_VALGRIND" + BUILDOPTIONS="--with-m64 --with-m32 --with-mx32" + - | + BUILDOPTIONS="--with-valgrind" after_failure: - cat test_*.log diff --git a/testme.sh b/testme.sh index a8180bdc9..b409f5516 100755 --- a/testme.sh +++ b/testme.sh @@ -17,6 +17,9 @@ fi ret=0 TEST_CFLAGS="" +VAGRIND_BIN="" +VALGRIND_OPT=" --track-origins=yes --leak-check=full --show-leak-kinds=all --error-exitcode=1 " + _help() { echo "Usage options for $(basename $0) [--with-cc=arg [other options]]" @@ -50,6 +53,15 @@ _help() echo echo " --mtest-real-rand Use real random data when running mtest." echo + echo " --with-valgrind Run in valgrind (slow!)." + echo " Default options are:" + echo " --track-origins=yes" + echo " --leak-check=full" + echo " --show-leak-kinds=all" + echo " --error-exitcode=1" + echo + echo " --valgrind-options Additional Valgrind options" + echo echo "Godmode:" echo echo " --all Choose all architectures and gcc and clang as compilers" @@ -97,6 +109,17 @@ _runtest() $_timeout ./test > test_${suffix}.log || _die "running tests" $? } +_runvalgrind() +{ + make clean > /dev/null + _make "$1" "$2" "test_standalone" + local _timeout="" + which timeout >/dev/null && _timeout="timeout --foreground 600" + echo -e "\rRun test $1 $2" + $_timeout $VALGRIND_BIN $VALGRIND_OPTS ./test > test_${suffix}.log || _die "running tests" $? +} + + _banner() { echo "uname="$(uname -a) @@ -134,6 +157,12 @@ do --cflags=*) CFLAGS="$CFLAGS ${1#*=}" ;; + --valgrind-options=*) + VALGRIND_OPTS="${1#*=} $VALGRIND_OPTS" + ;; + --with-valgrind) + VALGRIND_BIN="valgrind" + ;; --make-option=*) MAKE_OPTIONS="$MAKE_OPTIONS ${1#*=}" ;; @@ -170,11 +199,16 @@ if [[ "$COMPILERS" == "" ]] && [[ "$ARCHFLAGS$MAKE_OPTIONS$CFLAGS" != "" ]] then COMPILERS="gcc" # default to gcc and run only default config if no option is given -elif [[ "$COMPILERS" == "" ]] +elif [[ "$COMPILERS" == "" ]] && [[ "$VALGRIND_BIN" == "" ]] then _banner gcc _runtest "gcc" "" _exit +elif [[ "$VALGRIND_BIN" != "" ]] +then + _banner "$COMPILERS" + _runvalgrind "$COMPILERS" "$CFLAGS" + _exit fi archflags=( $ARCHFLAGS )