Skip to content

Implementation of mp_printf #550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,34 @@ if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
list(APPEND LTM_C_FLAGS -no-undefined)
endif()

#-----------------------------------------------------------------------------
# Check for floating point intrinsics
#-----------------------------------------------------------------------------

# TODO: add checks to mp_[gs]et_double if this works well
include(CheckTypeSize)
CHECK_TYPE_SIZE("float" FLOAT_SIZE)
CHECK_TYPE_SIZE("double" DOUBLE_SIZE)
CHECK_TYPE_SIZE("long double" LONG_DOUBLE_SIZE)

# Do we have anything even vaguely resembling floating points at all?
if(FLOAT_SIZE GREATER 0)
list(APPEND LTM_C_FLAGS -DLTM_HAVE_FLOAT_TYPE)
# float.h may or may not exist, even with floats avaibl
list(APPEND LTM_C_FLAGS -DLTM_FLOAT_SIZE=${FLOAT_SIZE})
endif()

if(DOUBLE_SIZE GREATER 0)
list(APPEND LTM_C_FLAGS -DLTM_HAVE_DOUBLE_TYPE)
list(APPEND LTM_C_FLAGS -DLTM_DOUBLE_SIZE=${DOUBLE_SIZE})
endif()

if(LONG_DOUBLE_SIZE GREATER 0)
list(APPEND LTM_C_FLAGS -DLTM_HAVE_LONG_DOUBLE_TYPE)
list(APPEND LTM_C_FLAGS -DLTM_LONG_DOUBLE_SIZE=${LONG_DOUBLE_SIZE})
endif()


# TODO: coverage (lgcov)

# If the user set the environment variables at generate-time, append them
Expand Down
229 changes: 229 additions & 0 deletions demo/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2436,6 +2436,234 @@ static int test_mp_pack_unpack(void)
return EXIT_FAILURE;
}

#ifndef MP_NO_FILE

#define LTM_TEST_BUFSIZ 4096
#include <string.h>
static int test_mp_fprintf(void)
{
FILE *test_file = NULL;

char line_buffer[LTM_TEST_BUFSIZ] = {0};
int i;
bool write_only = false;
size_t slen = 0;
int characters_printed = 0;
char *fgets_return;

const char *test_values[2] = {
"4DDCFDE0D20EF8663B34D19F829FDD",
"-51D9769BDAE5B38121F2A31D881E5F"
};

const char *test_strings[] = {
#ifdef LTM_HAVE_FLOAT_TYPE
"START 0x0000007b 123.123 -424986725583297217766029037085924959 0x4DDCFDE0D20EF8663B34D19F829FDD END\n",
#endif
"START -0b10100011101100101110110100110111101101011100101101100111000000100100001111100101010001100011101100010000001111001011111 END\n",
"START @ -KTbsczhbiu4XygCTY1vV @ END\n",
#if (MP_DIGIT_BIT == 60)
"START 0x63b34d19f829fdd,0x4ddcfde0d20ef86 END\n",
#elif (MP_DIGIT_BIT == 31)
"START 0x1f829fdd,0x4c7669a3,0x3483be1,0x26ee7ef END\n",
#elif (MP_DIGIT_BIT == 28)
"START 0xf829fdd,0x3b34d19,0x20ef866,0xdcfde0d,0x4d END\n",
#elif (MP_DIGIT_BIT == 15)
"START 0x1fdd,0x3f05,0x5346,0x31d9,0x6f86,0x1a41,0x3f78,0x26ee END\n",
#else
"undefined limb size\n",
#endif


#if (MP_DIGIT_BIT == 60)
"START 0x000000000000063b34d19f829fdd END\n"
#elif (MP_DIGIT_BIT == 31)
"START 0x000000000000000000001f829fdd END\n"
#elif (MP_DIGIT_BIT == 28)
"START 0x000000000000000000000f829fdd END\n"
#elif (MP_DIGIT_BIT == 15)
"START 0x0000000000000000000000001fdd END\n"
#else
"undefined limb size\n"
#endif
};

mp_int p, q;
int n;
/* Only stream printing available, no mp_sprintf or the like. File needs a path for repeated truncating */
test_file = fopen("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a", "w+");
if (test_file == NULL) {
/* use logfile instead to have at least sth. in case of an error */
test_file = stdout;
write_only = true;
}

DOR(mp_init_multi(&p, &q, NULL));

DO(mp_read_radix(&p, test_values[0], 16));
DO(mp_read_radix(&q, test_values[1], 16));

/* No loop here, too much hassle */
i = 0;
/* Defined by CMake and is not in any of the generic Makefiles */
#ifdef LTM_HAVE_FLOAT_TYPE
characters_printed = mp_fprintf(test_file, "START %#010x %12.12g %10Zd %#10Zx END\n",123,123.123,&q,&p,&q);
slen = strlen(test_strings[i]);
if ((characters_printed - (int)slen) != 0) {
fprintf(stderr, "0 test_mp_fprintf: failed to print o:%zu t:%d\n", slen, characters_printed);
goto LBL_ERR;
}
if (!write_only) {
rewind(test_file);
fgets_return = fgets(line_buffer, LTM_TEST_BUFSIZ, test_file);
if (fgets_return == NULL) {
fprintf(stderr, "1 test_mp_fprintf: failed to read from file\n");
goto LBL_ERR;
}
if (strcmp(line_buffer, test_strings[i]) != 0) {
fprintf(stderr, "test_mp_fprintf: file content is not equal to test string #%d\n",i);
goto LBL_ERR;
}
}
i++;
/* Clear file content */
test_file = freopen("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a","w+", test_file);
if (test_file == NULL) {
/* use logfile instead to have at least sth. in case of an error */
test_file = stdout;
write_only = true;
}
#endif

characters_printed = mp_fprintf(test_file, "START %#Zb END\n",&q);
slen = strlen(test_strings[i]);
if ((characters_printed - (int)slen) != 0) {
fprintf(stderr, "1 test_mp_fprintf: failed to print o:%zu t:%d\n", slen, characters_printed);
goto LBL_ERR;
}
if (!write_only) {
rewind(test_file);
fgets_return = fgets(line_buffer, LTM_TEST_BUFSIZ, test_file);
if (fgets_return == NULL) {
fprintf(stderr, "test_mp_fprintf: failed to read from file\n");
goto LBL_ERR;
}
if (strcmp(line_buffer, test_strings[i]) != 0) {
fprintf(stderr, "test_mp_fprintf: file content is not equal to test string #%d\n",i);
goto LBL_ERR;
}
}
i++;
/* Clear file content */
test_file = freopen("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a","w+", test_file);
if (test_file == NULL) {
/* use logfile instead to have at least sth. in case of an error */
test_file = stdout;
write_only = true;
}

characters_printed = mp_fprintf(test_file, "START @ %#Z@ @ END\n",&q);
slen = strlen(test_strings[i]);
if ((characters_printed - (int)slen) != 0) {
fprintf(stderr, "1 test_mp_fprintf: failed to print o:%zu t:%d\n", slen, characters_printed);
goto LBL_ERR;
}
if (!write_only) {
rewind(test_file);
fgets_return = fgets(line_buffer, LTM_TEST_BUFSIZ, test_file);
if (fgets_return == NULL) {
fprintf(stderr, "test_mp_fprintf: failed to read from file\n");
goto LBL_ERR;
}
if (strcmp(line_buffer, test_strings[i]) != 0) {
fprintf(stderr, "test_mp_fprintf: file content is not equal to test string #%d\n",i);
goto LBL_ERR;
}
}
i++;
/* Clear file content */
test_file = freopen("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a","w+", test_file);
if (test_file == NULL) {
/* use logfile instead to have at least sth. in case of an error */
test_file = stdout;
write_only = true;
}

/* TODO: add entries for the smaller mp_digits */
characters_printed = mp_fprintf(test_file,"START %#Nx END\n",&p);
slen = strlen(test_strings[i]);
if ((characters_printed - (int)slen) != 0) {
fprintf(stderr, "2 test_mp_fprintf: failed to print o:%zu t:%d\n", slen, characters_printed);
goto LBL_ERR;
}
if (!write_only) {
rewind(test_file);
fgets_return = fgets(line_buffer, LTM_TEST_BUFSIZ, test_file);
if (fgets_return == NULL) {
fprintf(stderr, "test_mp_fprintf: failed to read from file\n");
goto LBL_ERR;
}
if (strcmp(line_buffer, test_strings[i]) != 0) {
fprintf(stderr, "test_mp_fprintf: file content is not equal to test string #%d\n",i);
goto LBL_ERR;
}
}
i++;
/* Clear file content */
test_file = freopen("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a","w+", test_file);
if (test_file == NULL) {
/* use logfile instead to have at least sth. in case of an error */
test_file = stdout;
write_only = true;
}

characters_printed = mp_fprintf(test_file,"START %0#30Mx END\n",p.dp[0]);
slen = strlen(test_strings[i]);
if ((characters_printed - (int)slen) != 0) {
fprintf(stderr, "3 test_mp_fprintf: failed to print o:%zu t:%d\n", slen, characters_printed);
goto LBL_ERR;
}
if (!write_only) {
rewind(test_file);
fgets_return = fgets(line_buffer, LTM_TEST_BUFSIZ, test_file);
if (fgets_return == NULL) {
fprintf(stderr, "test_mp_fprintf: failed to read from file\n");
goto LBL_ERR;
}
if (strcmp(line_buffer, test_strings[i]) != 0) {
fprintf(stderr, "test_mp_fprintf: file content is not equal to test string #%d\n",i);
goto LBL_ERR;
}
}

/* It's more or less implementation defined but must be the same. */
characters_printed = mp_fprintf(stdout,"START %p END\n",&p);
i = fprintf(stdout,"START %p END\n",&p);
if ((characters_printed - i) != 0) {
fprintf(stderr, "test_mp_fprintf: failed to print pointer\n");
goto LBL_ERR;
}

characters_printed = mp_fprintf(stdout,"START %n END\n",&n);
if (n != 6) {
fprintf(stderr, "test_mp_fprintf: failed to count 6 characters properly\n");
goto LBL_ERR;
}

mp_clear_multi(&p, &q, NULL);
fclose(test_file);
if (remove("ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a") != 0) {
fprintf(stderr, "Could not delete file ltm_testing_mp_fprintf_88a43603fcfc2f7e7c6646cd4b89180a\n");
}
return EXIT_SUCCESS;
LBL_ERR:
mp_clear_multi(&p, &q, NULL);
fclose(test_file);
/* We don't delete the testfile in case of error, conrtent might be helpful. */
return EXIT_FAILURE;
}
#endif

#ifndef LTM_TEST_DYNAMIC
#define ONLY_PUBLIC_API_C
#endif
Expand Down Expand Up @@ -2463,6 +2691,7 @@ static int unit_tests(int argc, char **argv)
T1(mp_dr_reduce, MP_DR_REDUCE),
T2(mp_pack_unpack,MP_PACK, MP_UNPACK),
T2(mp_fread_fwrite, MP_FREAD, MP_FWRITE),
T1(mp_fprintf, S_MP_FPRINTF),
T1(mp_get_u32, MP_GET_I32),
T1(mp_get_u64, MP_GET_I64),
T1(mp_get_ul, MP_GET_L),
Expand Down
42 changes: 41 additions & 1 deletion doc/bn.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2414,12 +2414,52 @@ \subsection{To ASCII}
The result is \emph{always} either exact or too large but it is \emph{never} too small.


If \texttt{MP\_NO\_FILE} is not defined a function to write to a file is also available.
If \texttt{MP\_NO\_FILE} is not defined several functions to write to a file are also available.

\index{mp\_fwrite}
\begin{alltt}
mp_err mp_fwrite(const mp_int *a, int radix, FILE *stream);
\end{alltt}
The function \texttt{mp\_fwrite} writes the radix \texttt{radix} representation of \texttt{a}
to the file stream \texttt{stream}.


\index{mp\_fprintf}
\begin{alltt}
int mp_fprintf(FILE *stream, const char *format, ...);
\end{alltt}

\index{mp\_printf}
\begin{alltt}
int mp_fprintf(FILE *stream, const char *format, ...);
\end{alltt}

The functions \texttt{mp\_fprintf} and \texttt{mp\_printf} behave like \texttt{(f)printf} with
the additional type modifiers \texttt{Z} for a big integer, \texttt{M} for a single limb, and
\texttt{N} for a comma separated list of the raw limb-array of an \texttt{mp\_int} in the order
it comes in.

Most of the functions of \texttt{printf} are implemented except thousands-separators for big
integers because they are locale dependent and zero-padding for big integers is also missing.

If there is no floating point available (the check for type \texttt{float} failed) trying to
print one fails silently\footnot{The compiler should have complained in the first place, though.}.

If there is no type \texttt{long double} available the modifier \texttt{L} will silently
print a \texttt{double} instead.

If there is no type \texttt{double} available either, the modifier \texttt{L} will silently
print a \texttt{float} instead.

If there is no type \texttt{double} available when printing without the modifier \texttt{L}
this function will silently print a \texttt{float} instead.

It is quite useful for debugging to have a binary representation of the big integers and their
innards, so the type modifier \texttt{b} had been added to print all of \texttt{Z, M, N} with
zeros and ones only.

Printing the big integer in base-64 is done with \texttt{%Z@}.


\subsection{From ASCII}
\index{mp\_read\_radix}
Expand Down
12 changes: 12 additions & 0 deletions libtommath_VS2008.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,10 @@
RelativePath="mp_exteuclid.c"
>
</File>
<File
RelativePath="mp_fprintf.c"
>
</File>
<File
RelativePath="mp_fread.c"
>
Expand Down Expand Up @@ -644,6 +648,10 @@
RelativePath="mp_prime_strong_lucas_selfridge.c"
>
</File>
<File
RelativePath="mp_printf.c"
>
</File>
<File
RelativePath="mp_radix_size.c"
>
Expand Down Expand Up @@ -840,6 +848,10 @@
RelativePath="s_mp_fp_log_d.c"
>
</File>
<File
RelativePath="s_mp_fprintf.c"
>
</File>
<File
RelativePath="s_mp_get_bit.c"
>
Expand Down
Loading