ref: aa7834eae6417772a8d2e6752913c6e4874db0a8
parent: 728bf756970e75ca3217776c23dad1637d0f6f2c
author: S. Gilles <sgilles@math.umd.edu>
date: Sat Jul 14 20:56:09 EDT 2018
Update triple-generate to also compute tables for tan and cot.
--- a/lib/math/ancillary/generate-triples-for-GB91.c
+++ b/lib/math/ancillary/generate-triples-for-GB91.c
@@ -1,7 +1,11 @@
/* cc -o generate-triples-for-GB91 generate-triples-for-GB91.c -lmpfr # -fno-strict-aliasing */
+#include <errno.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
+#include <unistd.h>
#include <mpfr.h>
@@ -11,10 +15,9 @@
of calculating these, which we don't follow.
The idea is that, by good fortune (or more persuasive arguments),
- there exist floating-point numbers xi that are very close to
- numbers of the form (i/N)(π/4). They are so close, in fact, that
- the exact binary expansion of (i/N)(π/4) is xi, followed by a
- bunch of zeroes, then the irrational, unpredictable part.
+ there exist floating-point numbers xi that are close to numbers
+ of the form (i/N)(π/4), such that, letting f(xi) = yi, the binary
+ expansion of yi has a bunch of zeroes after the 53rd bit.
Then, when we discretize the input for sin(x) to some xi + delta,
the precomputed sin(xi) and cos(xi) can be stored as single
@@ -32,10 +35,13 @@
#define EXP_OF_FLT64(f) (((FLT64_TO_UINT64(f)) >> 52) & 0x7ff)
+typedef int (*mpfr_fn)(mpfr_ptr, mpfr_srcptr, mpfr_rnd_t);
+
static int N = 256;
/* Returns >= zero iff successful */
-static int find_triple_64(int i, int min_leeway, int perfect_leeway)
+static int find_triple_64(int i, int min_leeway, int perfect_leeway, mpfr_fn
+ sin_fn, mpfr_fn cos_fn)
{
/*
Using mpfr is not entirely overkill for this; [Lut95]
@@ -93,7 +99,7 @@
mpfr_set_d(xi, xi_current, MPFR_RNDN);
/* Test if cos(xi) has enough zeroes */
- mpfr_cos(cos, xi, MPFR_RNDN);
+ cos_fn(cos, xi, MPFR_RNDN);
t = mpfr_get_d(cos, MPFR_RNDN);
cos_u = FLT64_TO_UINT64(t);
e1 = EXP_OF_FLT64(t);
@@ -114,7 +120,7 @@
ml = xmax(min_leeway, e1 - e2 - 52);
/* Test if sin(xi) has enough zeroes */
- mpfr_sin(sin, xi, MPFR_RNDN);
+ sin_fn(sin, xi, MPFR_RNDN);
t = mpfr_get_d(sin, MPFR_RNDN);
sin_u = FLT64_TO_UINT64(t);
e1 = EXP_OF_FLT64(t);
@@ -183,19 +189,104 @@
}
}
-int main(void)
+static void usage(void)
{
- for (int i = 190; i <= N; ++i) {
- if (find_triple_64(i, 11, 20) < 0) {
- /*
- For some reason, i = 190 requires special
- handling; drop the range limitations on
- r and come back in a week.
+ printf("generate-triples-for-GB91\n");
+ printf(" [-i start_idx]\n");
+ printf(" [-j end_idx]\n");
+ printf(" -f sin|tan\n");
+}
- Other indices (4, 47, 74, &c) also benefit
- from this special handling, so the
- contents of sin-impl.myr might not exactly
- match the output of this particular file.
+int main(int argc, char **argv)
+{
+ int c = 0;
+ long i_start_arg = 1;
+ long i_end_arg = N;
+ int i_start = 1;
+ int i_end = N;
+ mpfr_fn sin_fn = 0;
+ mpfr_fn cos_fn = 0;
+
+ for (int k = 0; k < argc; ++k) {
+ printf("%s ", argv[k]);
+ }
+
+ printf("\n");
+
+ while ((c = getopt(argc, argv, "i:j:f:")) != -1) {
+ switch (c) {
+ case 'i':
+ errno = 0;
+ i_start_arg = strtoll(optarg, 0, 0);
+
+ if (errno) {
+ fprintf(stderr, "bad start index %s\n", optarg);
+
+ return 1;
+ }
+
+ break;
+ case 'j':
+ errno = 0;
+ i_end_arg = strtoll(optarg, 0, 0);
+
+ if (errno) {
+ fprintf(stderr, "bad end index %s\n", optarg);
+
+ return 1;
+ }
+
+ break;
+ case 'f':
+
+ if (!strcmp(optarg, "sin")) {
+ sin_fn = mpfr_sin;
+ cos_fn = mpfr_cos;
+ } else if (!strcmp(optarg, "tan")) {
+ sin_fn = mpfr_tan;
+ cos_fn = mpfr_cot;
+ } else {
+ fprintf(stderr, "unknown function %s\n",
+ optarg);
+
+ return 1;
+ }
+
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (i_start_arg <= 0 ||
+ i_end_arg > N) {
+ printf("truncating start to (0, %d]\n", N);
+ i_start_arg = xmin(xmax(i_start_arg, 1), N);
+ }
+
+ if (i_end_arg <= 0 ||
+ i_end_arg > N) {
+ printf("truncating end to (0, %d]\n", N);
+ i_end_arg = xmin(xmax(i_end_arg, 1), N);
+ }
+
+ i_start = i_start_arg;
+ i_end = i_end_arg;
+
+ if (!sin_fn ||
+ !cos_fn) {
+ fprintf(stderr, "-f required\n");
+
+ return 1;
+ }
+
+ for (int i = i_start; i <= i_end; ++i) {
+ if (find_triple_64(i, 11, 20, sin_fn, cos_fn) < 0) {
+ /*
+ This indicates you should drop the range
+ limitations on r, re-run, and come back
+ in a week.
*/
printf("CANNOT FIND SUITABLE CANDIDATE FOR i = %03d\n",
i);