示例#1
0
static GnmValue *
gnumeric_hdate_year (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
{
	int year, month, day;
	int hyear, hmonth, hday;

	gnumeric_hdate_get_date (argv, &year, &month, &day);

	if (0 != hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear))
		return value_new_error_VALUE (ei->pos);

	return value_new_int (hyear);
}
示例#2
0
static GnmValue *
callback_function_and (GnmEvalPos const *ep, GnmValue const *value, void *closure)
{
	int *result = closure;

	if (!VALUE_IS_STRING (value)) {
		gboolean err;
		*result = value_get_as_bool (value, &err) && *result;
		if (err)
			return value_new_error_VALUE (ep);
	}

	return NULL;
}
示例#3
0
static GnmValue *
gnumeric_hdate_heb (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
{
	int year, month, day;
	int hyear, hmonth, hday;
	GString *res;

	gnumeric_hdate_get_date (argv, &year, &month, &day);

	if (0 != hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear))
		return value_new_error_VALUE (ei->pos);

	res = g_string_new (NULL);
	build_hdate (res, hyear, hmonth, hday);

	return value_new_string_nocopy (g_string_free (res, FALSE));
}
示例#4
0
/*
 * We need a horizontal strip of 5 cells containing:
 *
 * 0. Formula cell.
 * 1: X value cell.
 * 2: Y target value.
 * 3: Min value.
 * 4: Max value.
 */
static void
dialog_goal_seek_test (Sheet *sheet, const GnmRange *range)
{
	GoalSeekState state;
	GnmCell *cell;
	int r, c;
	GoalSeekStatus status;

	g_return_if_fail (range->start.row == range->end.row);
	g_return_if_fail (range->start.col + 4 == range->end.col);

	memset (&state, 0, sizeof (state));
	r = range->start.row;
	c = range->start.col;

	state.wb = sheet->workbook;
	state.sheet = sheet;

	state.set_cell = sheet_cell_fetch (sheet, c + 0, r);
	state.change_cell = sheet_cell_fetch (sheet, c + 1, r);
	state.old_value = value_dup (state.change_cell->value);

	cell = sheet_cell_fetch (sheet, c + 2, r);
	state.target_value = value_get_as_float (cell->value);

	cell = sheet_cell_fetch (sheet, c + 3, r);
	state.xmin = VALUE_IS_EMPTY (cell->value)
		? -max_range_val
		: value_get_as_float (cell->value);

	cell = sheet_cell_fetch (sheet, c + 4, r);
	state.xmax = VALUE_IS_EMPTY (cell->value)
		? max_range_val
		: value_get_as_float (cell->value);

	status = gnumeric_goal_seek (&state);
	if (status == GOAL_SEEK_OK) {
		/* Nothing */
	} else {
		sheet_cell_set_value (state.change_cell,
				      value_new_error_VALUE (NULL));
	}

	value_release (state.old_value);
}
示例#5
0
static GnmValue *
gnumeric_and (GnmFuncEvalInfo *ei, int argc, GnmExprConstPtr const *argv)
{
	int result = -1;

	/* Yes, AND is actually strict.  */
	GnmValue *v = function_iterate_argument_values
		(ei->pos, callback_function_and, &result,
		 argc, argv, TRUE, CELL_ITER_IGNORE_BLANK);
	if (v != NULL)
		return v;

	/* See if there was any value worth using */
	if (result == -1)
		return value_new_error_VALUE (ei->pos);

	return value_new_bool (result);
}
示例#6
0
static GnmValue *
gnumeric_hdate (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
{
	int year, month, day;
	int hyear, hmonth, hday;
	char *res;

	gnumeric_hdate_get_date (argv, &year, &month, &day);

	if (0 != hdate_gdate_to_hdate (day, month, year, &hday, &hmonth, &hyear))
		return value_new_error_VALUE (ei->pos);

	res = g_strdup_printf ("%d %s %d",
			       hday + 1,
			       hdate_get_hebrew_month_name (hmonth),
			       hyear);

	return value_new_string_nocopy (res);
}
示例#7
0
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;
}
示例#8
0
/**
 * collect_float_pairs:
 * @v0: value describing first data range
 * @v1: value describing second data range
 * @ep: evaluation position
 * @flags: flags describing how to handle value types
 * @xs0: return location for first data vector
 * @xs1: return location for second data vector
 * @n: return location for number of data points
 * @constp: optional return location for an indicator of the return vectors
 * being owned by this function as opposed to the normal copy owned by the
 * caller.
 *
 * If @n is not positive upon return, no data has been allocated.
 * If @n is negative upon return, the two ranges had different
 * sizes.
 */
GnmValue *
collect_float_pairs (GnmValue const *vx, GnmValue const *vy,
		     GnmEvalPos const *ep, CollectFlags flags,
		     gnm_float **xs0, gnm_float **xs1, int *n,
		     gboolean *constp)
{
	GnmValue *key_x = NULL;
	GnmValue *key_y = NULL;
	PairsFloatsCacheEntry *ce = NULL;
	gboolean use_cache, free_keys = TRUE;

	if (vx->type == VALUE_CELLRANGE)
		key_x = get_single_cache_key_from_value (vx, ep);
	if (vy->type == VALUE_CELLRANGE)
		key_y = get_single_cache_key_from_value (vy, ep);

	if ((use_cache = (key_x && key_y)))
		ce = get_or_fake_pairs_cache_entry (key_x, key_y, flags, ep);

	if (!ce) {
		ce = collect_float_pairs_ce (vx, vy, ep, flags);
		if (use_cache) {
			PairsFloatsCacheEntry *ce2;
			ce->vx = key_x;
			ce->vy = key_y;
			free_keys = FALSE;

			/*
			 * We looked for the entry earlier and it was not there.
			 * However, sub-calculation might have added it so be careful
			 * to adjust sizes and replace the not-so-old entry.
			 * See bug 627079.
			 */
			ce2 = g_hash_table_lookup (pairs_floats_cache, ce);
			if (ce2)
				total_cache_size -= 1 + ce2->n;

			g_hash_table_replace (pairs_floats_cache, ce, ce);
			total_cache_size += 1 + ce->n;
		}
	}

	if (free_keys) {
		value_release (key_x);
		value_release (key_y);
	}

	if (ce == NULL)
		return value_new_error_VALUE (ep);
	else {
		if (ce->error) {
			if (use_cache)
				return value_dup (ce->error);
			else {
				GnmValue *ret = ce->error;
				ce->error = NULL;
				pairs_floats_cache_entry_free (ce);
				return ret;
			}
		}
		*n = ce->n;
		if (ce->n <= 0) {
			if (!use_cache)
				pairs_floats_cache_entry_free (ce);
			*xs0 = NULL;
			*xs1 = NULL;
			if (constp)
				*constp = FALSE;
			return NULL;
		}
		if (use_cache) {
			if (constp) {
				*xs0 = ce->data_x;
				*xs1 = ce->data_y;
				*constp = TRUE;
			} else {
				*xs0 = g_memdup (ce->data_x, *n * sizeof (gnm_float));
				*xs1 = g_memdup (ce->data_y, *n * sizeof (gnm_float));
			}
		} else {
			if (constp)
				*constp = FALSE;
			*xs0 = ce->data_x;
			*xs1 = ce->data_y;
			ce->data_x = NULL;
			ce->data_y = NULL;
			pairs_floats_cache_entry_free (ce);
		}
		return NULL;
	}
}
示例#9
0
static GnmValue *
callback_function_collect (GnmEvalPos const *ep, GnmValue const *value,
			   void *closure)
{
	gnm_float x = 0;
	collect_floats_t *cl = closure;
	gboolean ignore = FALSE;

	switch (value ? value->type : VALUE_EMPTY) {
	case VALUE_EMPTY:
		if (cl->flags & COLLECT_IGNORE_BLANKS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_BLANKS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_BOOLEAN:
		if (cl->flags & COLLECT_IGNORE_BOOLS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZEROONE_BOOLS)
			x = value_get_as_float (value);
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_CELLRANGE :
	case VALUE_ARRAY :
		/* Ranges and arrays are not singleton values treat as errors */

	case VALUE_ERROR:
		if (cl->flags & COLLECT_IGNORE_ERRORS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_ERRORS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	case VALUE_FLOAT:
		x = value_get_as_float (value);
		break;

	case VALUE_STRING:
		if (cl->flags & COLLECT_COERCE_STRINGS) {
			GnmValue *vc = format_match_number (value_peek_string (value),
							    NULL,
							    cl->date_conv);
			gboolean bad = !vc || VALUE_IS_BOOLEAN (vc);
			if (vc) {
				x = value_get_as_float (vc);
				value_release (vc);
			} else
				x = 0;

			if (bad)
				return value_new_error_VALUE (ep);
		} else if (cl->flags & COLLECT_IGNORE_STRINGS)
			ignore = TRUE;
		else if (cl->flags & COLLECT_ZERO_STRINGS)
			x = 0;
		else
			return value_new_error_VALUE (ep);
		break;

	default:
		g_warning ("Trouble in callback_function_collect. (%d)",
			   value->type);
		ignore = TRUE;
	}

	if (ignore) {
		if (cl->flags & COLLECT_INFO)
			cl->info = g_slist_prepend (cl->info, GUINT_TO_POINTER (cl->count));
		else {
			return NULL;
		}
	}

	if (cl->count == cl->alloc_count) {
		cl->alloc_count = cl->alloc_count * 2 + 20;
		cl->data = g_renew (gnm_float, cl->data, cl->alloc_count);
	}

	cl->data[cl->count++] = x;
	return NULL;
}
示例#10
0
文件: sc-fin.c 项目: GNOME/gnumeric
GnmValue *
get_vdb (gnm_float cost, gnm_float salvage, gnm_float life,
	 gnm_float start_period, gnm_float end_period, gnm_float factor,
	 gboolean flag)
{
	gnm_float fVdb;
	gnm_float fIntStart = gnm_floor (start_period);
	gnm_float fIntEnd   = gnm_ceil (end_period);

	fVdb      = 0.0;

	if ( flag ) {
		int i, nLoopStart, nLoopEnd;

		if (fIntEnd > G_MAXINT ||
		    fIntEnd - fIntStart > 10000 /* arbitrary */)
			return value_new_error_VALUE (NULL);

		nLoopStart = (int) fIntStart;
		nLoopEnd   = (int) fIntEnd;
		for (i = nLoopStart + 1; i <= nLoopEnd; i++) {
			gnm_float fTerm;

			fTerm = ScGetGDA (cost, salvage, life, i, factor);
			if ( i == nLoopStart+1 )
				fTerm *= ( MIN( end_period, fIntStart + 1.0 )
					   - start_period );
			else if ( i == nLoopEnd )
				fTerm *= ( end_period + 1.0 - fIntEnd );
			fVdb += fTerm;
		}
	} else {
		gnm_float fPart = 0;
		double fIntEnd = gnm_ceil (end_period);

		if (start_period > fIntStart) {
                        // First period is partial.  Calculate the excess as
			// the pro-rata value of the first period as-if it
			// was not partial.
                        double tempcost = cost -
				ScInterVDB( cost, salvage, life, life, fIntStart, factor);
                        fPart += (start_period - fIntStart) *
				ScInterVDB( tempcost, salvage, life, life - fIntStart,
					    1, factor);
		}

		if (end_period < fIntEnd) {
                        // Last period is partial.  Calculate the excess as
			// the pro-rata value of the last period as-if it
			// was not partial.
                        double em1 = fIntEnd - 1; // Start of last period
                        double tempcost = cost -
                            ScInterVDB (cost, salvage, life, life, em1, factor);
                        fPart += (fIntEnd - end_period) *
                            ScInterVDB (tempcost, salvage, life, life - em1,
					1, factor);
		}

		cost -= ScInterVDB (cost, salvage, life, life, fIntStart, factor);
		fVdb = ScInterVDB (cost, salvage, life, life - fIntStart,
				   fIntEnd - fIntStart, factor);
		fVdb -= fPart;
	}
	return value_new_float (fVdb);
}
示例#11
0
/**
 * FIXME: In the long term this needs optimising.
 **/
static GnmValue *
val_to_base (GnmFuncEvalInfo *ei,
	     GnmValue const *value,
	     GnmValue const *aplaces,
	     int src_base, int dest_base,
	     gnm_float min_value, gnm_float max_value,
	     Val2BaseFlags flags)
{
	int digit, min, max, places;
	gnm_float v;
	GString *buffer;
	GnmValue *vstring = NULL;

	g_return_val_if_fail (src_base > 1 && src_base <= 36,
			      value_new_error_VALUE (ei->pos));
	g_return_val_if_fail (dest_base > 1 && dest_base <= 36,
			      value_new_error_VALUE (ei->pos));

	/* func.c ought to take care of this.  */
	if (VALUE_IS_BOOLEAN (value))
		return value_new_error_VALUE (ei->pos);
	if (aplaces && VALUE_IS_BOOLEAN (aplaces))
		return value_new_error_VALUE (ei->pos);

	switch (value->type) {
	default:
		return value_new_error_NUM (ei->pos);

	case VALUE_STRING:
		if (flags & V2B_STRINGS_GENERAL) {
			vstring = format_match_number
				(value_peek_string (value), NULL,
				 workbook_date_conv (ei->pos->sheet->workbook));
			if (!vstring || !VALUE_IS_FLOAT (vstring)) {
				value_release (vstring);
				return value_new_error_VALUE (ei->pos);
			}
		} else {
			char const *str = value_peek_string (value);
			size_t len;
			gboolean hsuffix = FALSE;
			char *err;

			if ((flags & V2B_STRINGS_BLANK_ZERO) && *str == 0)
				str = "0";

			/* This prevents leading spaces, signs, etc, and "".  */
			if (!g_ascii_isalnum (*str))
				return value_new_error_NUM (ei->pos);

			len = strlen (str);
			/* We check length in bytes.  Since we are going to
			   require nothing but digits, that is fine.  */
			if ((flags & V2B_STRINGS_MAXLEN) && len > 10)
				return value_new_error_NUM (ei->pos);

			if (flags & V2B_STRINGS_0XH) {
				if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
					str += 2;
				else if (str[len - 1] == 'h' || str[len - 1] == 'H')
					hsuffix = TRUE;
			}

			v = g_ascii_strtoll (str, &err, src_base);
			if (err == str || err[hsuffix] != 0)
				return value_new_error_NUM (ei->pos);

			if (v < min_value || v > max_value)
				return value_new_error_NUM (ei->pos);

			break;
		}
		/* Fall through.  */

	case VALUE_FLOAT: {
		gnm_float val = gnm_fake_trunc (value_get_as_float (vstring ? vstring : value));
		char buf[GNM_MANT_DIG + 10];
		char *err;

		value_release (vstring);

		if (val < min_value || val > max_value)
			return value_new_error_NUM (ei->pos);

		g_ascii_formatd (buf, sizeof (buf) - 1,
				 "%.0" GNM_FORMAT_f,
				 val);

		v = g_ascii_strtoll (buf, &err, src_base);
		if (*err != 0)
			return value_new_error_NUM (ei->pos);
		break;
	}
	}

	if (src_base != 10) {
		gnm_float b10 = gnm_pow (src_base, 10);
		if (v >= b10 / 2) /* N's complement */
			v = v - b10;
	}

	if (flags & V2B_NUMBER)
		return value_new_float (v);

	if (v < 0) {
		min = 1;
		max = 10;
		v += gnm_pow (dest_base, max);
	} else {
		if (v == 0)
			min = max = 1;
		else
			min = max = (int)(gnm_log (v + 0.5) /
					  gnm_log (dest_base)) + 1;
	}

	if (aplaces) {
		gnm_float fplaces = value_get_as_float (aplaces);
		if (fplaces < min || fplaces > 10)
			return value_new_error_NUM (ei->pos);
		places = (int)fplaces;
		if (v >= 0 && places > max)
			max = places;
	} else
		places = 1;

	buffer = g_string_sized_new (max);
	g_string_set_size (buffer, max);

	for (digit = max - 1; digit >= 0; digit--) {
		int thisdigit = gnm_fmod (v + 0.5, dest_base);
		v = gnm_floor ((v + 0.5) / dest_base);
		buffer->str[digit] =
			thisdigit["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
	}

	return value_new_string_nocopy (g_string_free (buffer, FALSE));
}
示例#12
0
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;
}