/** * float_range_function2d: * @val0: * @val1: * @ei: * @func: (scope call): * @flags: * @func_error: * * Returns: (transfer full): **/ GnmValue * float_range_function2d (GnmValue const *val0, GnmValue const *val1, GnmFuncEvalInfo *ei, float_range_function2d_t func, CollectFlags flags, GnmStdError func_error, gpointer data) { gnm_float *vals0, *vals1; int n; GnmValue *res; gnm_float fres; gboolean constp = FALSE; res = collect_float_pairs (val0, val1, ei->pos, flags, &vals0, &vals1, &n, &constp); if (res) return res; if (n <= 0) return value_new_error_std (ei->pos, func_error); if (func (vals0, vals1, n, &fres, data)) res = value_new_error_std (ei->pos, func_error); else res = value_new_float (fres); if (!constp) { g_free (vals0); g_free (vals1); } return res; }
/** * float_range_function: * @argc: * @argv: * @ei: * @func: (scope call): * @flags: * @func_error: * * Returns: (transfer full): **/ GnmValue * float_range_function (int argc, GnmExprConstPtr const *argv, GnmFuncEvalInfo *ei, float_range_function_t func, CollectFlags flags, GnmStdError func_error) { GnmValue *error = NULL; gnm_float *vals, res; int n, err; gboolean constp; vals = collect_floats (argc, argv, ei->pos, flags, &n, &error, NULL, &constp); if (!vals) return error; err = func (vals, n, &res); if (!constp) g_free (vals); if (err) return value_new_error_std (ei->pos, func_error); else return value_new_float (res); }
/** * string_range_function: * @argc: * @argv: * @ei: * @func: (scope call): * @flags: * @func_error: * * Returns: (transfer full): **/ GnmValue * string_range_function (int argc, GnmExprConstPtr const *argv, GnmFuncEvalInfo *ei, string_range_function_t func, CollectFlags flags, GnmStdError func_error) { GnmValue *error = NULL; GPtrArray *vals; char *res = NULL; int err; vals = collect_strings (argc, argv, ei->pos, flags, &error); if (!vals) return error; err = func (vals, &res); collect_strings_free (vals); if (err) { g_free (res); return value_new_error_std (ei->pos, func_error); } else { return value_new_string_nocopy (res); } }
GnmValue * gnm_ifs_func (GPtrArray *data, GPtrArray *crits, GnmValue const *vals, float_range_function_t fun, GnmStdError err, GnmEvalPos const *ep, CollectFlags flags) { int sx, sy, x, y; unsigned ui, N = 0, nalloc = 0; gnm_float *xs = NULL; GnmValue *res = NULL; gnm_float fres; g_return_val_if_fail (data->len == crits->len, NULL); if (flags & ~(COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_ERRORS)) { g_warning ("unsupported flags in gnm_ifs_func %x", flags); } sx = value_area_get_width (vals, ep); sy = value_area_get_height (vals, ep); for (ui = 0; ui < data->len; ui++) { GnmValue const *datai = g_ptr_array_index (data, ui); if (value_area_get_width (datai, ep) != sx || value_area_get_height (datai, ep) != sy) return value_new_error_VALUE (ep); } for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { GnmValue const *v; gboolean match = TRUE; for (ui = 0; match && ui < crits->len; ui++) { GnmCriteria *crit = g_ptr_array_index (crits, ui); GnmValue const *datai = g_ptr_array_index (data, ui); v = value_area_get_x_y (datai, x, y, ep); match = crit->fun (v, crit); } if (!match) continue; // Match. Maybe collect the data point. v = value_area_get_x_y (vals, x, y, ep); if ((flags & COLLECT_IGNORE_STRINGS) && VALUE_IS_STRING (v)) continue; if ((flags & COLLECT_IGNORE_BOOLS) && VALUE_IS_BOOLEAN (v)) continue; if ((flags & COLLECT_IGNORE_BLANKS) && VALUE_IS_EMPTY (v)) continue; if ((flags & COLLECT_IGNORE_ERRORS) && VALUE_IS_ERROR (v)) continue; if (VALUE_IS_ERROR (v)) { res = value_dup (v); goto out; } if (N >= nalloc) { nalloc = (2 * nalloc) + 100; xs = g_renew (gnm_float, xs, nalloc); } xs[N++] = value_get_as_float (v); } } if (fun (xs, N, &fres)) { res = value_new_error_std (ep, err); } else res = value_new_float (fres); out: g_free (xs); return res; }
static GnmValue * new_gnm_value_from_xloper (const XLOPER*x) { GnmValue * g = NULL; if (NULL != x) { switch (x->xltype & xltypeType) { case xltypeNum: g = value_new_float (x->val.num); break; case xltypeStr: { char *o = NULL; const char *s = x->val.str; if (NULL != s) { guint m = ((unsigned char)s[0]) + 1U; o = g_new (char, m); g_strlcpy (o, s + 1, m); } g = value_new_string_nocopy (o); break; } case xltypeBool: g = value_new_bool (x->val.boolean); break; case xltypeRef: unsupported_xloper_type (x); break; case xltypeErr: g = value_new_error_std (NULL, gnm_value_error_from_xloper (x)); break; case xltypeFlow: unsupported_xloper_type (x); break; case xltypeMulti: { guint m = x->val.array.columns; guint n = x->val.array.rows; if (m > 0 && n > 0) { guint i; g = value_new_array_empty (m,n); for (i = 0; i < m; ++i) { guint j; for (j = 0; j < n; ++j) { g->v_array.vals[i][j] = new_gnm_value_from_xloper (x->val.array.lparray + i + j * m); } } } else { g = value_new_error_std (NULL, GNM_ERROR_VALUE); } break; } case xltypeMissing: break; case xltypeNil: g = value_new_empty (); break; case xltypeSRef: unsupported_xloper_type (x); break; case xltypeInt: g = value_new_int (x->val.w); break; default: unsupported_xloper_type (x); } } else {
static GnmValue * gnumeric_periodogram (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float *ord, *absc; int filter, interp; int n0, n1, nb; GnmValue *error = NULL; GnmValue *res; CollectFlags flags; GnmEvalPos const * const ep = ei->pos; GnmValue const * const Pt = argv[0]; int i; GSList *missing0 = NULL, *missing1 = NULL; gnm_complex *in, *out = NULL; int const cols = value_area_get_width (Pt, ep); int const rows = value_area_get_height (Pt, ep); if (cols == 1) nb=rows; else { if (rows == 1) nb=cols; else nb=0; } if (nb == 0) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } flags=COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS; ord = collect_floats_value_with_info (argv[0], ei->pos, flags, &n0, &missing0, &error); if (error) { g_slist_free (missing0); return error; } if (n0 == 0) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } if (argv[1]) { filter = (int) gnm_floor (value_get_as_float (argv[1])); if (filter < 0 || filter > FILTER_WELCH) { g_slist_free (missing0); g_free (ord); res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } } else filter = FILTER_NONE; if (argv[2]) { gnm_float *interpolated, *new_ord, start, incr; int n2; INTERPPROC(interpproc) = NULL; absc = collect_floats_value_with_info (argv[2], ei->pos, flags, &n1, &missing1, &error); if (n1 == 1) { g_slist_free (missing1); g_free (absc); goto no_absc; } if (error) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); return error; } if (n1 == 0) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } if (argv[3]) { interp = (int) gnm_floor (value_get_as_float (argv[3])); if (interp < 0 || interp > INTERPOLATION_SPLINE_AVG) { g_slist_free (missing0); g_slist_free (missing1); g_free (absc); g_free (ord); return error; } } else interp = INTERPOLATION_LINEAR; if (missing0 || missing1) { GSList *missing = gnm_slist_sort_merge (missing0, missing1); gnm_strip_missing (ord, &n0, missing); gnm_strip_missing (absc, &n1, missing); g_slist_free (missing); if (n0 != n1) g_warning ("This should not happen. n0=%d n1=%d\n", n0, n1); } n0 = n1 = MIN (n0, n1); /* here we test if there is abscissas are always increasing, if not, an error is returned */ if (n0 < 2 || !gnm_range_increasing (absc, n0) || n0 == 0) { g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } if (argv[4]) { n1 = (int) gnm_floor (value_get_as_float (argv[4])); if (n1 < n0) { g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } nb = 1; while (nb < n1) nb *= 2; } else { n1 = 1; while (n1 < n0) n1 *= 2; nb = n1; } incr = (absc[n0 - 1] - absc[0]) / n1; switch (interp) { case INTERPOLATION_LINEAR: interpproc = linear_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_LINEAR_AVG: interpproc = linear_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; case INTERPOLATION_STAIRCASE: interpproc = staircase_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_STAIRCASE_AVG: interpproc = staircase_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; case INTERPOLATION_SPLINE: interpproc = spline_interpolation; start = absc[0]; n2 = n1; break; case INTERPOLATION_SPLINE_AVG: interpproc = spline_averaging; start = absc[0] - incr / 2.; n2 = n1 + 1; break; default: g_free (absc); g_free (ord); return value_new_error_std (ei->pos, GNM_ERROR_NA); } interpolated = g_new (gnm_float, n1); for (i = 0; i < n2; i++) interpolated[i] = start + i * incr; new_ord = interpproc (absc, ord, n0, interpolated, n1); g_free (ord); ord = new_ord; if (ord == NULL) { g_free (absc); g_free (interpolated); return value_new_error_std (ei->pos, GNM_ERROR_NA); } n0 = n1; } else { no_absc: /* we have no interpolation to apply, so just take the values */ if (missing0) { gnm_strip_missing (ord, &n0, missing0); g_slist_free (missing0); } nb = 1; while (nb < n0) nb *= 2; } /* Now apply the filter if any */ if (filter != FILTER_NONE) { gnm_float factor; switch (filter) { case FILTER_BARTLETT: factor = n0 / 2.; for (i = 0; i < n0; i++) ord[i] *= 1. - gnm_abs ((i / factor - 1)); break; case FILTER_HANN: factor = 2. * M_PIgnum / n0; for (i = 0; i < n0; i++) ord[i] *= 0.5 * (1 - gnm_cos (factor * i)); break; case FILTER_WELCH: factor = n0 / 2.; for (i = 0; i < n0; i++) ord[i] *= 1. - (i / factor - 1.) * (i / factor - 1.); break; } } /* Transform and return the result */ in = g_new0 (gnm_complex, nb); for (i = 0; i < n0; i++){ in[i].re = ord[i]; } g_free (ord); gnm_fourier_fft (in, nb, 1, &out, FALSE); g_free (in); nb /= 2; if (out && nb > 0) { res = value_new_array_non_init (1 , nb); res->v_array.vals[0] = g_new (GnmValue *, nb); for (i = 0; i < nb; i++) res->v_array.vals[0][i] = value_new_float (gnm_sqrt ( out[i].re * out[i].re + out[i].im * out[i].im)); g_free (out); } else
static GnmValue * gnumeric_interpolation (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float *vals0, *vals1, *vals2, *fres; int n0, n2; int interp; GnmValue *error = NULL; GnmValue *res; CollectFlags flags; GnmEvalPos const * const ep = ei->pos; GnmValue const * const PtInterpolation = argv[2]; int r, i; GSList *missing2 = NULL, *missing; INTERPPROC interpproc = NULL; gboolean constp = FALSE; /* argv[2] */ int const cols = value_area_get_width (PtInterpolation, ep); int const rows = value_area_get_height (PtInterpolation, ep); if (rows == 0 || cols != 1) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_ERRORS; vals2 = collect_floats_value_with_info (PtInterpolation, ei->pos, flags, &n2, &missing2, &error); if (error) { g_slist_free (missing2); return error; } /* argv[3] */ if (argv[3]) { interp = (int) gnm_floor (value_get_as_float (argv[3])); if (interp < 0 || interp > INTERPOLATION_SPLINE_AVG) { g_slist_free (missing2); g_free (vals2); return value_new_error_VALUE (ei->pos); } } else interp = INTERPOLATION_LINEAR; switch (interp) { case INTERPOLATION_LINEAR: interpproc = linear_interpolation; break; case INTERPOLATION_LINEAR_AVG: interpproc = linear_averaging; n2--; break; case INTERPOLATION_STAIRCASE: interpproc = staircase_interpolation; break; case INTERPOLATION_STAIRCASE_AVG: interpproc = staircase_averaging; n2--; break; case INTERPOLATION_SPLINE: interpproc = spline_interpolation; break; case INTERPOLATION_SPLINE_AVG: interpproc = spline_averaging; n2--; break; } if (n2 <= 0) { g_slist_free (missing2); g_free (vals2); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } /* argv[0] & argv[1] */ flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS; error = collect_float_pairs (argv[0], argv[1], ei->pos, flags, &vals0, &vals1, &n0, &constp); if (error) { g_slist_free (missing2); g_free (vals2); return error; } /* Check whether the abscissae are increasing, if not order them */ if (!gnm_range_increasing (vals0, n0)) { gboolean switched = TRUE; if (constp) { vals0 = g_memdup (vals0, sizeof(gnm_float) * n0); vals1 = g_memdup (vals1, sizeof(gnm_float) * n0); constp = FALSE; } while (switched) { gnm_float *val; switched = FALSE; for (i = 1, val = vals0; i < n0; i++, val++) { if (*val == *(val + 1)) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE) ; goto done; } if (*val > *(val + 1)) { gnm_float v = *val; *val = *(val + 1); *(val + 1) = v; v = *(vals1 + i); *(vals1 + i) = *(vals1 + i - 1); *(vals1 + i - 1) = v; switched = TRUE; } } } } { int n = n2; if (missing2) gnm_strip_missing (vals2, &n, missing2); res = value_new_array_non_init (1 , n2); i = 0; res->v_array.vals[0] = g_new (GnmValue *, n2); fres = interpproc (vals0, vals1, n0, vals2, n); missing = missing2; if (fres) { i = 0; for (r = 0 ; r < n2; ++r) if (missing && r == GPOINTER_TO_INT (missing->data)) { missing = missing->next; res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } else res->v_array.vals[0][r] = value_new_float (fres[i++]); g_free (fres); } else { for( r = 0 ; r < n2; ++r) res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } } done: g_slist_free (missing2); if (!constp) { g_free (vals0); g_free (vals1); } g_free (vals2); return res; }