static void mps_context_init (mps_context * s) { mpf_t test; /* Set default streams */ s->instr = stdin; s->outstr = stdout; s->logstr = stdout; /* Allocate space for the configurations */ s->input_config = (mps_input_configuration*)mps_malloc (sizeof(mps_input_configuration)); s->output_config = (mps_output_configuration*)mps_malloc (sizeof(mps_output_configuration)); mps_set_default_values (s); /* Find minimum GMP supported precision */ mpf_init2 (test, 1); s->minimum_gmp_precision = mpf_get_prec (test); mpf_clear (test); /* Set standard precision */ s->output_config->prec = (int)(0.9 * DBL_DIG * LOG2_10); MPS_DEBUG (s, "Setting prec_out to %ld digits", s->output_config->prec); mps_mp_set_prec (s, DBL_DIG * LOG2_10 + 1); s->initialized = false; s->exit_required = false; }
/** * @brief Allocate a new mps_context struct with default * options. */ mps_context * mps_context_new () { mps_context * ctx = NULL; /* Try to get a low cost context from the factory */ pthread_mutex_lock (&context_factory_mutex); if (context_factory_size > 0) { /* Pop out a context */ ctx = context_factory[--context_factory_size]; if (context_factory_size) context_factory = mps_realloc (context_factory, sizeof(mps_context*) * context_factory_size); else { free (context_factory); context_factory = NULL; } } pthread_mutex_unlock (&context_factory_mutex); /* Allocate the new mps_context and load default options */ if (!ctx) { ctx = (mps_context*)mps_malloc (sizeof(mps_context)); mps_context_init (ctx); } return ctx; }
/** * @brief Allocate a new mps_context struct with default * options. */ mps_context * mps_context_new () { /* Allocate the new mps_context and load default options */ mps_context * s = (mps_context*) mps_malloc (sizeof (mps_context)); mps_context_init (s); return s; }
char * cplx_get_str (char *s, const cplx_t x) /* output to string as (re , im) */ { if (s == NULL && (s = (char*)mps_malloc (DEF_STR_SIZE)) == NULL) return NULL; sprintf (s, CPLX_OUT_FMT, cplx_Re (x), cplx_Im (x)); return s; }
void mps_context_init (mps_context * s) { /* Set default streams */ s->instr = stdin; s->outstr = stdout; s->logstr = stdout; /* Allocate space for the configurations */ s->input_config = (mps_input_configuration *) mps_malloc (sizeof (mps_input_configuration)); s->output_config = (mps_output_configuration *) mps_malloc (sizeof (mps_output_configuration)); mps_set_default_values (s); /* Set standard precision */ s->output_config->prec = (int) (0.9 * DBL_DIG * LOG2_10); MPS_DEBUG (s, "Setting prec_out to %ld digits", s->output_config->prec); mps_mp_set_prec (s, DBL_DIG * LOG2_10 + 1); s->initialized = false; }
char * rdpe_get_str (char *s, const rdpe_t e) /* output to string */ { double d; long int l; if (s == NULL && (s = (char*)mps_malloc (DEF_STR_SIZE)) == NULL) return NULL; rdpe_get_dl (&d, &l, e); sprintf (s, RDPE_OUT_FMT, d, l); return s; }
char * cdpe_get_str (char *s, const cdpe_t c) /* output to string as (re , im) */ { double dr, di; long int lr, li; if (s == NULL && (s = (char*)mps_malloc (DEF_STR_SIZE)) == NULL) return NULL; rdpe_get_dl (&dr, &lr, cdpe_Re (c)); rdpe_get_dl (&di, &li, cdpe_Im (c)); sprintf (s, CDPE_OUT_FMT, dr, lr, di, li); return s; }
/** * @brief Parse command line options in a similar way of getopts. * * @param opt_ptr A pointer to a previous used mps_opts that can * be re-used, or NULL. If this is NULL it will be allocated. * When this function return false the opt_ptr is automatically * freed. * @param argc_ptr The address in memory of the argc variable * obtained by the operating system. * @param argv_ptr The address in memory of the argv variable * obtained by the operating system. * @param opt_format The option that <code>mps_getopts()</code> * has to look for. It is passed as a string like * <code>"ab:n"</code> where the <code>":"</code> means that the preceding * character needs an argument, while single characters not followed * by <code>":"</code> don't expect one. In this case a correct call * to the program would be * @code * ./myprogram -a -n -b 7 * @endcode * or even * @code * ./myprogam -a * @endcode * * The option are parsed from argc_ptr and argv_ptr and these * are modified taking options away (as the program has been * called wihtout these options) so after option parsing the program * can still parse other options such as filenames or similar, without * worrying about options switch. */ mps_boolean mps_getopts (mps_opt ** opt_ptr, int *argc_ptr, char ***argv_ptr, const char *opt_format) { char **argv = *argv_ptr; int argc = *argc_ptr; char *tmp; mps_opt *opt; int i, l = strlen (opt_format), steps; if ((*opt_ptr) == NULL) { (*opt_ptr) = (mps_opt*)mps_malloc (sizeof(mps_opt)); } opt = *opt_ptr; /* Check if there are other arguments to parse */ if (!argc) { free (opt); return false; } if (argc == 1) { free (opt); return false; } /* Scan for right offset */ steps = 0; while (argv[1][0] != '-') { /* If we get here then argv[1] is a parameter string * that must be preserved, so we should put it on the end * of argv. */ tmp = argv[1]; for (i = 1; i < argc - 1; i++) { (*argv_ptr)[i] = argv[i + 1]; } (*argv_ptr)[argc - 1] = tmp; steps++; /* Check if argc permutation was performed */ if (steps == argc - 1) { free (opt); return false; } } /* Search argv[0][1] in opt_format */ for (i = 0; i < l; i++) { if (opt_format[i] == ':') continue; else if (argv[1][1] == opt_format[i]) { opt->optchar = opt_format[i]; /* If there is no argument we are done */ if (i == l || opt_format[i + 1] != ':') { opt->optvalue = NULL; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; } /* Check if the parameter has an optional argument. If that's the * case, don't bother if there are no arguments. */ if (i <= l + 2 && (opt_format[i + 1] == ':' && opt_format[i + 2] == ':')) { if (argv[1][2] == '\0') { opt->optvalue = NULL; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; } } /* If the string is not terminated than we should * expect to find the parameter attached to it */ if (argv[1][2] != '\0') { if (argv[1][2] == '=') { opt->optvalue = argv[1] + 3; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; } else { opt->optvalue = argv[1] + 2; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; } } /* If the parameter should be in argv[1] but is not * there return an error */ if (argc == 2) { opt->optvalue = NULL; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; } /* Otherwise we can set the argument in the struct */ opt->optvalue = argv[2]; (*argc_ptr) -= 2; (*argv_ptr)[2] = argv[0]; (*argv_ptr) += 2; return true; } } /* Fallback case, we haven't recognized the input */ opt->optchar = '?'; (*argc_ptr)--; (*argv_ptr)[1] = argv[0]; (*argv_ptr)++; return true; }
/** * @brief Drop-in threaded replacement for the stock mpolzer. */ MPS_PRIVATE void mps_thread_mpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { int i, nzeros = 0, n_threads = s->n_threads; *it = 0; *excep = false; /* Check if we have already approxmiated roots */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) { return; } /* Lower the number of threads if there are a lot of approximated roots */ if (s->n_threads > (s->n - nzeros)) n_threads = s->n - nzeros; else n_threads = s->n_threads; MPS_DEBUG_WITH_INFO (s, "Spawning %d worker", n_threads); mps_thread_worker_data *data; /* Allocate and the init mutexes needed by the routine */ pthread_mutex_t *roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t *aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t global_aberth_mutex = PTHREAD_MUTEX_INITIALIZER; for (i = 0; i < s->n; i++) { pthread_mutex_init (&aberth_mutex[i], NULL); pthread_mutex_init (&roots_mutex[i], NULL); } /* Create a new work queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * n_threads); /* Set data to be passed to every thread and actually spawn the threads. */ for (i = 0; i < n_threads; i++) { data[i].it = it; data[i].nzeros = &nzeros; data[i].s = s; data[i].excep = excep; data[i].thread = i; data[i].n_threads = n_threads; data[i].aberth_mutex = aberth_mutex; data[i].global_aberth_mutex = &global_aberth_mutex; data[i].queue = queue; data[i].roots_mutex = roots_mutex; data[i].required_zeros = required_zeros; mps_thread_pool_assign (s, s->pool, mps_thread_mpolzer_worker, data + i); } /* Wait for the threads to complete */ mps_thread_pool_wait (s, s->pool); /* Free data and exit */ free (data); for (i = 0; i < s->n; i++) { pthread_mutex_destroy (&roots_mutex[i]); pthread_mutex_destroy (&aberth_mutex[i]); } free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); }
/** * @brief Multithread version of mps_dpolzer (). */ MPS_PRIVATE void mps_thread_dpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { mps_thread_worker_data *data; pthread_mutex_t *aberth_mutex, *roots_mutex; int i, nzeros = 0; /* initialize the iteration counter */ *it = 0; *excep = false; /* count the number of approximations in the root neighbourhood */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) return; /* Prepare queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); /* Allocate space for thread data */ data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * s->n_threads); /* Allocate mutexes and init them */ aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); for (i = 0; i < s->n; i++) { if (s->pool->n > 1) { pthread_mutex_init (&aberth_mutex[i], NULL); pthread_mutex_init (&roots_mutex[i], NULL); } } /* Start spawning thread */ for (i = 0; i < s->n_threads; i++) { data[i].aberth_mutex = aberth_mutex; data[i].excep = excep; data[i].it = it; data[i].n_threads = s->n_threads; data[i].nzeros = &nzeros; data[i].queue = queue; data[i].roots_mutex = roots_mutex; data[i].s = s; data[i].thread = i; data[i].required_zeros = required_zeros; mps_thread_pool_assign (s, s->pool, mps_thread_dpolzer_worker, data + i); } /* Wait for the thread to complete */ mps_thread_pool_wait (s, s->pool); free (aberth_mutex); free (roots_mutex); free (data); mps_thread_job_queue_free (queue); }
/** * @brief Drop-in replacement for the stock fpolzer routine. * This version adds multithread support. */ MPS_PRIVATE void mps_thread_fpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { int i, nzeros = 0, n_threads = s->n_threads; mps_thread_worker_data *data; pthread_mutex_t *aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t *roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); for (i = 0; i < s->n; i++) { pthread_mutex_init (roots_mutex + i, NULL); pthread_mutex_init (aberth_mutex + i, NULL); } /* Create a new job queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); *it = 0; *excep = false; /* count the number of approximations in the root neighbourhood */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) { free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); return; } data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * n_threads); for (i = 0; i < n_threads; i++) { data[i].it = it; data[i].nzeros = &nzeros; data[i].s = s; data[i].excep = excep; data[i].thread = i; data[i].n_threads = n_threads; data[i].aberth_mutex = aberth_mutex; data[i].roots_mutex = roots_mutex; data[i].queue = queue; data[i].required_zeros = required_zeros; /* pthread_create (&threads[i], NULL, &mps_thread_fpolzer_worker, */ /* data + i); */ mps_thread_pool_assign (s, s->pool, mps_thread_fpolzer_worker, data + i); } mps_thread_pool_wait (s, s->pool); free (data); free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); }