From 57f4739e438356217da1b07a6be8bacb6c261f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Sat, 5 Oct 2019 17:51:27 +0200 Subject: [PATCH] Add serialization arb/arf/mag_load/dump_str/file --- arb.h | 8 ++++ arb/dump_file.c | 30 ++++++++++++ arb/dump_str.c | 39 ++++++++++++++++ arb/load_file.c | 30 ++++++++++++ arb/load_str.c | 61 ++++++++++++++++++++++++ arb/test/t-dump-file.c | 94 +++++++++++++++++++++++++++++++++++++ arb/test/t-dump-str.c | 73 +++++++++++++++++++++++++++++ arf.h | 8 ++++ arf/dump-file.c | 27 +++++++++++ arf/dump-str.c | 63 +++++++++++++++++++++++++ arf/load.c | 103 +++++++++++++++++++++++++++++++++++++++++ arf/test/t-dump-file.c | 93 +++++++++++++++++++++++++++++++++++++ arf/test/t-dump-str.c | 74 +++++++++++++++++++++++++++++ doc/source/arb.rst | 25 ++++++++++ doc/source/arf.rst | 25 ++++++++++ doc/source/mag.rst | 25 ++++++++++ mag.h | 8 ++++ mag/dump_file.c | 30 ++++++++++++ mag/dump_str.c | 25 ++++++++++ mag/load.c | 97 ++++++++++++++++++++++++++++++++++++++ mag/test/t-dump-file.c | 94 +++++++++++++++++++++++++++++++++++++ mag/test/t-dump-str.c | 73 +++++++++++++++++++++++++++++ 22 files changed, 1105 insertions(+) create mode 100644 arb/dump_file.c create mode 100644 arb/dump_str.c create mode 100644 arb/load_file.c create mode 100644 arb/load_str.c create mode 100644 arb/test/t-dump-file.c create mode 100644 arb/test/t-dump-str.c create mode 100644 arf/dump-file.c create mode 100644 arf/dump-str.c create mode 100644 arf/load.c create mode 100644 arf/test/t-dump-file.c create mode 100644 arf/test/t-dump-str.c create mode 100644 mag/dump_file.c create mode 100644 mag/dump_str.c create mode 100644 mag/load.c create mode 100644 mag/test/t-dump-file.c create mode 100644 mag/test/t-dump-str.c diff --git a/arb.h b/arb.h index fb80313a..6979d9ca 100644 --- a/arb.h +++ b/arb.h @@ -1007,6 +1007,14 @@ _arb_vec_estimate_allocated_bytes(slong len, slong prec) return size; } +int arb_load_str(arb_t res, const char * data); + +char * arb_dump_str(const arb_t x); + +int arb_load_file(arb_t res, FILE *stream); + +int arb_dump_file(FILE* stream, const arb_t x); + #ifdef __cplusplus } #endif diff --git a/arb/dump_file.c b/arb/dump_file.c new file mode 100644 index 00000000..8a32a216 --- /dev/null +++ b/arb/dump_file.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include + +#include "arb.h" + +int +arb_dump_file(FILE* stream, const arb_t x) +{ + int nwrite; + char* pos; + char* data = arb_dump_str(x); + + nwrite = fputs(data, stream); + if (nwrite == EOF) + return nwrite; + + flint_free(data); + return 0; +} diff --git a/arb/dump_str.c b/arb/dump_str.c new file mode 100644 index 00000000..1109c417 --- /dev/null +++ b/arb/dump_str.c @@ -0,0 +1,39 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include + +#include "arb.h" +#include "arf.h" +#include "mag.h" + +char * +arb_dump_str(const arb_t x) +{ + char * mid; + char * mag; + size_t res_len; + char * res; + + mid = arf_dump_str(arb_midref(x)); + mag = mag_dump_str(arb_radref(x)); + + res_len = strlen(mid) + 1 + strlen(mag); + res = (char*)flint_malloc(res_len + 1); + strcpy(res, mid); + strcat(res, " "); + strcat(res, mag); + + flint_free(mid); + flint_free(mag); + + return res; +} diff --git a/arb/load_file.c b/arb/load_file.c new file mode 100644 index 00000000..ec4ee581 --- /dev/null +++ b/arb/load_file.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include + +#include "arb.h" + +int +arb_load_file(arb_t x, FILE* stream) +{ + int err; + + err = arf_load_file(arb_midref(x), stream); + + if (err) return err; + + err = mag_load_file(arb_radref(x), stream); + + return err; +} + diff --git a/arb/load_str.c b/arb/load_str.c new file mode 100644 index 00000000..e0b626a4 --- /dev/null +++ b/arb/load_str.c @@ -0,0 +1,61 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include + +#include "arb.h" +#include "arf.h" +#include "mag.h" + +int +arb_load_str(arb_t x, const char* data) +{ + size_t midlen, maglen; + char * mid; + char * mag; + int err = 0; + + const char* split = strchr(data, ' '); + if (split == NULL) + { + return 1; + } + split = strchr(split + 1, ' '); + if (split == NULL) + { + return 1; + } + + midlen = (size_t)(split - data); + mid = (char*)flint_malloc(midlen + 1); + strncpy(mid, data, midlen); + mid[midlen] = '\0'; + + maglen = strlen(data) - midlen - 1; + mag = (char*)flint_malloc(maglen + 1); + strncpy(mag, split + 1, maglen); + mag[maglen] = '\0'; + + err = arf_load_str(arb_midref(x), mid); + if (err) + { + flint_free(mid); + flint_free(mag); + return err; + } + + err = mag_load_str(arb_radref(x), mag); + + flint_free(mid); + flint_free(mag); + + return err; +} diff --git a/arb/test/t-dump-file.c b/arb/test/t-dump-file.c new file mode 100644 index 00000000..de6d10a6 --- /dev/null +++ b/arb/test/t-dump-file.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "arb.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_file/load_file...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + arb_t x; + FILE* tmp; + + arb_init(x); + + arb_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + tmp = tmpfile(); + arb_dump_file(tmp, x); + fflush(tmp); + rewind(tmp); + arb_load_file(x, tmp); + fclose(tmp); + + arb_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + arb_t x, y, z; + int conversion_error; + FILE* tmp; + + arb_init(x); + arb_init(y); + arb_init(z); + + arb_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arb_randtest_special(y, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arb_randtest_special(z, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + tmp = tmpfile(); + arb_dump_file(tmp, x); + fputc(' ', tmp); + arb_dump_file(tmp, y); + fflush(tmp); + rewind(tmp); + + conversion_error = arb_load_file(z, tmp); + if (conversion_error || !arb_equal(x, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); arb_printd(x, 50); flint_printf("\n\n"); + flint_printf("z = "); arb_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + conversion_error = arb_load_file(z, tmp); + if (conversion_error || !arb_equal(y, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("y = "); arb_printd(y, 50); flint_printf("\n\n"); + flint_printf("z = "); arb_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + fclose(tmp); + arb_clear(x); + arb_clear(y); + arb_clear(z); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} diff --git a/arb/test/t-dump-str.c b/arb/test/t-dump-str.c new file mode 100644 index 00000000..b9fae513 --- /dev/null +++ b/arb/test/t-dump-str.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "arb.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_str/load_str...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + arb_t x; + char * s; + + arb_init(x); + + arb_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + s = arb_dump_str(x); + + flint_free(s); + arb_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + arb_t x, y; + char * s; + int conversion_error; + + arb_init(x); + arb_init(y); + + arb_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arb_randtest_special(y, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + s = arb_dump_str(x); + conversion_error = arb_load_str(y, s); + + if (conversion_error || !arb_equal(x, y)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); arb_printd(x, 50); flint_printf("\n\n"); + flint_printf("s = %s", s); flint_printf("\n\n"); + flint_printf("y = "); arb_printd(y, 50); flint_printf("\n\n"); + flint_abort(); + } + + flint_free(s); + arb_clear(x); + arb_clear(y); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} diff --git a/arf.h b/arf.h index 63badded..fe083a35 100644 --- a/arf.h +++ b/arf.h @@ -1287,6 +1287,14 @@ arf_allocated_bytes(const arf_t x) return size; } +int arf_load_str(arf_t res, const char * data); + +char * arf_dump_str(const arf_t x); + +int arf_load_file(arf_t res, FILE *stream); + +int arf_dump_file(FILE* stream, const arf_t x); + #ifdef __cplusplus } #endif diff --git a/arf/dump-file.c b/arf/dump-file.c new file mode 100644 index 00000000..05e9dd6e --- /dev/null +++ b/arf/dump-file.c @@ -0,0 +1,27 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include + +#include "arf.h" + +int +arf_dump_file(FILE* stream, const arf_t x) +{ + int nwrite; + char* data = arf_dump_str(x); + nwrite = fputs(data, stream); + if (nwrite == EOF) + return nwrite; + + flint_free(data); + return 0; +} diff --git a/arf/dump-str.c b/arf/dump-str.c new file mode 100644 index 00000000..fd457606 --- /dev/null +++ b/arf/dump-str.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include + +#include "arf.h" + +static void +arf_get_fmpz_2exp_dump(fmpz_t m, fmpz_t e, const arf_t x) { + if (arf_is_special(x)) + { + fmpz_zero(m); + if (arf_is_zero(x)) fmpz_zero(e); + else if (arf_is_pos_inf(x)) fmpz_set_si(e, -1); + else if (arf_is_neg_inf(x)) fmpz_set_si(e, -2); + else if (arf_is_nan(x)) fmpz_set_si(e, -3); + else + { + /* Impossible to happen; all the special values have been treated above. */ + flint_abort(); + } + return; + } + + arf_get_fmpz_2exp(m, e, x); +} + +char * +arf_dump_str(const arf_t x) +{ + size_t res_len; + char * res; + + fmpz_t mantissa, exponent; + + fmpz_init(mantissa); + fmpz_init(exponent); + + arf_get_fmpz_2exp_dump(mantissa, exponent, x); + + res_len = (fmpz_sgn(mantissa) < 0) + fmpz_sizeinbase(mantissa, 16) + 1 + + (fmpz_sgn(exponent) < 0) + fmpz_sizeinbase(exponent, 16); + res = (char*)flint_malloc(res_len + 1); + + fmpz_get_str(res, 16, mantissa); + strcat(res, " "); + fmpz_get_str(res + strlen(res), 16, exponent); + + fmpz_clear(mantissa); + fmpz_clear(exponent); + + if(strlen(res) != res_len) flint_abort(); /* assert */ + + return res; +} diff --git a/arf/load.c b/arf/load.c new file mode 100644 index 00000000..019c3f8a --- /dev/null +++ b/arf/load.c @@ -0,0 +1,103 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include + +#include "arf.h" + +static void +arf_set_fmpz_2exp_dump(arf_t x, const fmpz_t m, const fmpz_t e) { + if (fmpz_is_zero(m)) { + if (fmpz_get_si(e) == 0) arf_zero(x); + else if (fmpz_get_si(e) == -1) arf_pos_inf(x); + else if (fmpz_get_si(e) == -2) arf_neg_inf(x); + else if (fmpz_get_si(e) == -3) arf_nan(x); + else { + /* Impossible to happen; all the special values have been treated above. */ + flint_abort(); + } + return; + } + + arf_set_fmpz_2exp(x, m, e); +} + +int +arf_load_str(arf_t x, const char* data) +{ + int err = 0; + + fmpz_t mantissa, exponent; + char * e_str; + char * m_str; + + fmpz_init(mantissa); + fmpz_init(exponent); + + e_str = strchr(data, ' '); + if (e_str == NULL) return 1; + + m_str = (char*)flint_malloc(e_str - data + 1); + strncpy(m_str, data, e_str - data); + m_str[e_str - data] = '\0'; + e_str++; + + err = fmpz_set_str(mantissa, m_str, 16); + + flint_free(m_str); + + if (err) + { + fmpz_clear(exponent); + fmpz_clear(mantissa); + return err; + } + + err = fmpz_set_str(exponent, e_str, 16); + + if (err) + { + fmpz_clear(exponent); + fmpz_clear(mantissa); + return err; + } + + arf_set_fmpz_2exp_dump(x, mantissa, exponent); + + fmpz_clear(exponent); + fmpz_clear(mantissa); + + return err; +} + +int arf_load_file(arf_t x, FILE* stream) +{ + mpz_t mantissa, exponent; + + mpz_init(mantissa); + mpz_init(exponent); + + if (mpz_inp_str(mantissa, stream, 16) == 0) return 1; + if (mpz_inp_str(exponent, stream, 16) == 0) return 1; + + fmpz_t mantissa_, exponent_; + + fmpz_init_set_readonly(mantissa_, mantissa); + fmpz_init_set_readonly(exponent_, exponent); + + arf_set_fmpz_2exp_dump(x, mantissa_, exponent_); + + mpz_clear(mantissa); + mpz_clear(exponent); + + return 0; +} + diff --git a/arf/test/t-dump-file.c b/arf/test/t-dump-file.c new file mode 100644 index 00000000..3ff41b11 --- /dev/null +++ b/arf/test/t-dump-file.c @@ -0,0 +1,93 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "arb.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_file/load_file...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + arf_t x; + FILE* tmp; + + arf_init(x); + + arf_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + tmp = tmpfile(); + arf_dump_file(tmp, x); + fflush(tmp); + rewind(tmp); + arf_load_file(x, tmp); + fclose(tmp); + + arf_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + arf_t x, y, z; + int conversion_error; + + arf_init(x); + arf_init(y); + arf_init(z); + + arf_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arf_randtest_special(y, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arf_randtest_special(z, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + FILE* tmp = tmpfile(); + arf_dump_file(tmp, x); + fputc(' ', tmp); + arf_dump_file(tmp, y); + fflush(tmp); + rewind(tmp); + + conversion_error = arf_load_file(z, tmp); + if (conversion_error || !arf_equal(x, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); arf_printd(x, 50); flint_printf("\n\n"); + flint_printf("z = "); arf_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + conversion_error = arf_load_file(z, tmp); + if (conversion_error || !arf_equal(y, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("y = "); arf_printd(y, 50); flint_printf("\n\n"); + flint_printf("z = "); arf_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + fclose(tmp); + arf_clear(x); + arf_clear(y); + arf_clear(z); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} diff --git a/arf/test/t-dump-str.c b/arf/test/t-dump-str.c new file mode 100644 index 00000000..eb9edd58 --- /dev/null +++ b/arf/test/t-dump-str.c @@ -0,0 +1,74 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "arf.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_str/load_str...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + arf_t x; + char * s; + + arf_init(x); + + arf_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + s = arf_dump_str(x); + + flint_free(s); + arf_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + arf_t x, y; + char * s; + int conversion_error; + + arf_init(x); + arf_init(y); + + arf_randtest_special(x, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + arf_randtest_special(y, state, 1 + n_randint(state, 1000), 1 + n_randint(state, 100)); + + s = arf_dump_str(x); + conversion_error = arf_load_str(y, s); + + if (conversion_error || !arf_equal(x, y)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); arf_printd(x, 50); flint_printf("\n\n"); + flint_printf("s = %s", s); flint_printf("\n\n"); + flint_printf("y = "); arf_printd(y, 50); flint_printf("\n\n"); + flint_abort(); + } + + flint_free(s); + arf_clear(x); + arf_clear(y); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} + diff --git a/doc/source/arb.rst b/doc/source/arb.rst index 6598e1bc..0ea8e5f3 100644 --- a/doc/source/arb.rst +++ b/doc/source/arb.rst @@ -275,6 +275,31 @@ The *arb_print...* functions print to standard output, while enclose *x*. See :func:`arb_get_str` for details. +.. function:: char* arb_dump_str(const arb_t x) + + Allocates a string and writes a binary representation of *x* to it that can + be read by :func:`arb_load_str`. The returned string needs to be + deallocated with *flint_free*. + +.. function:: int arb_load_str(arb_t x, const char* str) + + Parses *str* into *x*. Returns a nonzero value if *str* is not formatted + correctly. + +.. function:: int arb_dump_file(FILE* stream, const arb_t x) + + Writes a binary representation of *x* to *stream* that can be read by + :func:`arb_load_file`. Returns a nonzero value if the data could not be + written. + +.. function:: int arb_load_file(arb_t x, FILE* stream) + + Reads *x* from *stream*. Returns a nonzero value if the data is not + formatted correctly or the read failed. Note that the data is assumed to be + delimited by a whitespace or end-of-file, i.e., when writing multiple + values with :func:`arb_dump_file` make sure to insert a whitespace to + separate consecutive values. + Random number generation ------------------------------------------------------------------------------- diff --git a/doc/source/arf.rst b/doc/source/arf.rst index e9a0e698..f8c09857 100644 --- a/doc/source/arf.rst +++ b/doc/source/arf.rst @@ -499,6 +499,31 @@ Input and output rounding to *d* digits. This function is currently implemented using MPFR, and does not support large exponents. +.. function:: char* arf_dump_str(const arf_t x) + + Allocates a string and writes a binary representation of *x* to it that can + be read by :func:`arf_load_str`. The returned string needs to be + deallocated with *flint_free*. + +.. function:: int arf_load_str(arf_t x, const char* str) + + Parses *str* into *x*. Returns a nonzero value if *str* is not formatted + correctly. + +.. function:: int arf_dump_file(FILE* stream, const arf_t x) + + Writes a binary representation of *x* to *stream* that can be read by + :func:`arf_load_file`. Returns a nonzero value if the data could not be + written. + +.. function:: int arf_load_file(arf_t x, FILE* stream) + + Reads *x* from *stream*. Returns a nonzero value if the data is not + formatted correctly or the read failed. Note that the data is assumed to be + delimited by a whitespace or end-of-file, i.e., when writing multiple + values with :func:`arf_dump_file` make sure to insert a whitespace to + separate consecutive values. + Addition and multiplication ------------------------------------------------------------------------------- diff --git a/doc/source/mag.rst b/doc/source/mag.rst index 766350bc..51880996 100644 --- a/doc/source/mag.rst +++ b/doc/source/mag.rst @@ -221,6 +221,31 @@ Input and output Prints *x* to the stream *file*. +.. function:: char* mag_dump_str(const mag_t x) + + Allocates a string and writes a binary representation of *x* to it that can + be read by :func:`mag_load_str`. The returned string needs to be + deallocated with *flint_free*. + +.. function:: int mag_load_str(mag_t x, const char* str) + + Parses *str* into *x*. Returns a nonzero value if *str* is not formatted + correctly. + +.. function:: int mag_dump_file(FILE* stream, const mag_t x) + + Writes a binary representation of *x* to *stream* that can be read by + :func:`mag_load_file`. Returns a nonzero value if the data could not be + written. + +.. function:: int mag_load_file(mag_t x, FILE* stream) + + Reads *x* from *stream*. Returns a nonzero value if the data is not + formatted correctly or the read failed. Note that the data is assumed to be + delimited by a whitespace or end-of-file, i.e., when writing multiple + values with :func:`mag_dump_file` make sure to insert a whitespace to + separate consecutive values. + Random generation ------------------------------------------------------------------------------- diff --git a/mag.h b/mag.h index c3aed044..00eb44fa 100644 --- a/mag.h +++ b/mag.h @@ -726,6 +726,14 @@ MAG_INLINE slong mag_allocated_bytes(const mag_t x) return fmpz_allocated_bytes(MAG_EXPREF(x)); } +int mag_load_str(mag_t res, const char * data); + +char * mag_dump_str(const mag_t x); + +int mag_load_file(mag_t res, FILE *stream); + +int mag_dump_file(FILE* stream, const mag_t x); + #ifdef __cplusplus } #endif diff --git a/mag/dump_file.c b/mag/dump_file.c new file mode 100644 index 00000000..73041e73 --- /dev/null +++ b/mag/dump_file.c @@ -0,0 +1,30 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include + +#include "mag.h" + +int +mag_dump_file(FILE* stream, const mag_t x) +{ + int nwrite; + char* pos; + char* data = mag_dump_str(x); + + nwrite = fputs(data, stream); + if (nwrite == EOF) + return nwrite; + + flint_free(data); + return 0; +} diff --git a/mag/dump_str.c b/mag/dump_str.c new file mode 100644 index 00000000..8a81dbd7 --- /dev/null +++ b/mag/dump_str.c @@ -0,0 +1,25 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include "arf.h" +#include "mag.h" + +char * +mag_dump_str(const mag_t x) +{ + char * res; + arf_t y; + + arf_init_set_mag_shallow(y, x); + + res = arf_dump_str(y); + return res; +} diff --git a/mag/load.c b/mag/load.c new file mode 100644 index 00000000..644b3590 --- /dev/null +++ b/mag/load.c @@ -0,0 +1,97 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include + +#include "mag.h" +#include "arf.h" + +static void +mag_set_arf_dump(mag_t x, const arf_t y) +{ + if (arf_is_special(y)) + { + if (arf_is_zero(y)) + { + mag_zero(x); + } + else if (arf_is_pos_inf(y)) + { + mag_inf(x); + } + else + { + /* a mag cannot be negative infinity or NaN */ + flint_abort(); + } + } + else + { + fmpz_t mantissa, exponent; + fmpz_init(mantissa); + fmpz_init(exponent); + + arf_get_fmpz_2exp(mantissa, exponent, y); + + if(fmpz_cmp_ui(mantissa, 1 << MAG_BITS) >= 0) flint_abort(); /* assert */ + + mag_set_ui(x, fmpz_get_ui(mantissa)); + + mag_mul_2exp_fmpz(x, x, exponent); + + fmpz_clear(exponent); + fmpz_clear(mantissa); + } +} + +int +mag_load_str(mag_t x, const char* data) +{ + int err = 0; + arf_t y; + + arf_init(y); + + err = arf_load_str(y, data); + if (err) + { + arf_clear(y); + return err; + } + + mag_set_arf_dump(x, y); + + arf_clear(y); + return err; +} + +int +mag_load_file(mag_t x, FILE* stream) +{ + int err = 0; + arf_t y; + + arf_init(y); + + err = arf_load_file(y, stream); + + if (err) + { + arf_clear(y); + return err; + } + + mag_set_arf_dump(x, y); + + arf_clear(y); + return err; +} diff --git a/mag/test/t-dump-file.c b/mag/test/t-dump-file.c new file mode 100644 index 00000000..3407407a --- /dev/null +++ b/mag/test/t-dump-file.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include +#include "arb.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_file/load_file...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + mag_t x; + FILE* tmp; + + mag_init(x); + + mag_randtest_special(x, state, 1 + n_randint(state, 100)); + + tmp = tmpfile(); + mag_dump_file(tmp, x); + fflush(tmp); + rewind(tmp); + mag_load_file(x, tmp); + fclose(tmp); + + mag_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + mag_t x, y, z; + int conversion_error; + FILE* tmp; + + mag_init(x); + mag_init(y); + mag_init(z); + + mag_randtest_special(x, state, 1 + n_randint(state, 100)); + mag_randtest_special(y, state, 1 + n_randint(state, 100)); + mag_randtest_special(z, state, 1 + n_randint(state, 100)); + + tmp = tmpfile(); + mag_dump_file(tmp, x); + fputc(' ', tmp); + mag_dump_file(tmp, y); + fflush(tmp); + rewind(tmp); + + conversion_error = mag_load_file(z, tmp); + if (conversion_error || !mag_equal(x, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); mag_printd(x, 50); flint_printf("\n\n"); + flint_printf("z = "); mag_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + conversion_error = mag_load_file(z, tmp); + if (conversion_error || !mag_equal(y, z)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("y = "); mag_printd(y, 50); flint_printf("\n\n"); + flint_printf("z = "); mag_printd(z, 50); flint_printf("\n\n"); + flint_abort(); + } + + fclose(tmp); + mag_clear(x); + mag_clear(y); + mag_clear(z); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +} diff --git a/mag/test/t-dump-str.c b/mag/test/t-dump-str.c new file mode 100644 index 00000000..4252732e --- /dev/null +++ b/mag/test/t-dump-str.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2019 Julian Rüth + + This file is part of Arb. + + Arb is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. See . +*/ + +#include +#include "mag.h" + +int main() +{ + flint_rand_t state; + slong iter; + + flint_printf("dump_str/load_str...."); + fflush(stdout); + flint_randinit(state); + + /* just test no crashing... */ + for (iter = 0; iter < 10000 * arb_test_multiplier(); iter++) + { + mag_t x; + char * s; + + mag_init(x); + + mag_randtest_special(x, state, 1 + n_randint(state, 100)); + + s = mag_dump_str(x); + + flint_free(s); + mag_clear(x); + } + + for (iter = 0; iter < 100000 * arb_test_multiplier(); iter++) + { + mag_t x, y; + char * s; + int conversion_error; + + mag_init(x); + mag_init(y); + + mag_randtest_special(x, state, 1 + n_randint(state, 100)); + mag_randtest_special(y, state, 1 + n_randint(state, 100)); + + s = mag_dump_str(x); + conversion_error = mag_load_str(y, s); + + if (conversion_error || !mag_equal(x, y)) + { + flint_printf("FAIL (roundtrip) iter = %wd\n", iter); + flint_printf("x = "); mag_printd(x, 50); flint_printf("\n\n"); + flint_printf("s = %s", s); flint_printf("\n\n"); + flint_printf("y = "); mag_printd(y, 50); flint_printf("\n\n"); + flint_abort(); + } + + flint_free(s); + mag_clear(x); + mag_clear(y); + } + + flint_randclear(state); + flint_cleanup(); + flint_printf("PASS\n"); + return EXIT_SUCCESS; +}