Example #1
0
double
lgamma_r (double x, int *signp)
{
	*signp = +1;

	if (gnm_isnan (x))
		return gnm_nan;

	if (x > 0) {
		gnm_float f = 1;

		while (x < 10) {
			f *= x;
			x++;
		}

		return (M_LN_SQRT_2PI + (x - 0.5) * gnm_log(x) -
			x + lgammacor(x)) - gnm_log (f);
	} else {
		gnm_float axm2 = gnm_fmod (-x, 2.0);
		gnm_float y = gnm_sinpi (axm2) / M_PIgnum;

		*signp = axm2 > 1.0 ? +1 : -1;

		return y == 0
			? gnm_nan
			: - gnm_log (gnm_abs (y)) - lgamma1p (-x);
	}
}
Example #2
0
static gnm_float lgammacor(gnm_float x)
{
    static const gnm_float algmcs[15] = {
	GNM_const(+.1666389480451863247205729650822e+0),
	GNM_const(-.1384948176067563840732986059135e-4),
	GNM_const(+.9810825646924729426157171547487e-8),
	GNM_const(-.1809129475572494194263306266719e-10),
	GNM_const(+.6221098041892605227126015543416e-13),
	GNM_const(-.3399615005417721944303330599666e-15),
	GNM_const(+.2683181998482698748957538846666e-17),
	GNM_const(-.2868042435334643284144622399999e-19),
	GNM_const(+.3962837061046434803679306666666e-21),
	GNM_const(-.6831888753985766870111999999999e-23),
	GNM_const(+.1429227355942498147573333333333e-24),
	GNM_const(-.3547598158101070547199999999999e-26),
	GNM_const(+.1025680058010470912000000000000e-27),
	GNM_const(-.3401102254316748799999999999999e-29),
	GNM_const(+.1276642195630062933333333333333e-30)
    };

    gnm_float tmp;

#ifdef NOMORE_FOR_THREADS
    static int nalgm = 0;
    static gnm_float xbig = 0, xmax = 0;

    /* Initialize machine dependent constants, the first time gamma() is called.
	FIXME for threads ! */
    if (nalgm == 0) {
	/* For IEEE gnm_float precision : nalgm = 5 */
	nalgm = chebyshev_init(algmcs, 15, GNM_EPSILON/2);/*was d1mach(3)*/
	xbig = 1 / gnm_sqrt(GNM_EPSILON/2); /* ~ 94906265.6 for IEEE gnm_float */
	xmax = gnm_exp(fmin2(gnm_log(GNM_MAX / 12), -gnm_log(12 * GNM_MIN)));
	/*   = GNM_MAX / 48 ~= 3.745e306 for IEEE gnm_float */
    }
#else
/* For IEEE gnm_float precision GNM_EPSILON = 2^-52 = GNM_const(2.220446049250313e-16) :
 *   xbig = 2 ^ 26.5
 *   xmax = GNM_MAX / 48 =  2^1020 / 3 */
# define nalgm 5
# define xbig  GNM_const(94906265.62425156)
# define xmax  GNM_const(3.745194030963158e306)
#endif

    if (x < 10)
	ML_ERR_return_NAN
    else if (x >= xmax) {
	ML_ERROR(ME_UNDERFLOW);
	return ML_UNDERFLOW;
    }
    else if (x < xbig) {
	tmp = 10 / x;
	return chebyshev_eval(tmp * tmp * 2 - 1, algmcs, nalgm) / x;
    }
    else return 1 / (x * 12);
}
Example #3
0
gnm_float stirlerr(gnm_float n)
{

#define S0 GNM_const(0.083333333333333333333)       /* 1/12 */
#define S1 GNM_const(0.00277777777777777777778)     /* 1/360 */
#define S2 GNM_const(0.00079365079365079365079365)  /* 1/1260 */
#define S3 GNM_const(0.000595238095238095238095238) /* 1/1680 */
#define S4 GNM_const(0.0008417508417508417508417508)/* 1/1188 */

/*
  error for 0, 0.5, 1.0, 1.5, ..., 14.5, 15.0.
*/
    static const gnm_float sferr_halves[31] = {
	0.0, /* n=0 - wrong, place holder only */
	GNM_const(0.1534264097200273452913848),  /* 0.5 */
	GNM_const(0.0810614667953272582196702),  /* 1.0 */
	GNM_const(0.0548141210519176538961390),  /* 1.5 */
	GNM_const(0.0413406959554092940938221),  /* 2.0 */
	GNM_const(0.03316287351993628748511048), /* 2.5 */
	GNM_const(0.02767792568499833914878929), /* 3.0 */
	GNM_const(0.02374616365629749597132920), /* 3.5 */
	GNM_const(0.02079067210376509311152277), /* 4.0 */
	GNM_const(0.01848845053267318523077934), /* 4.5 */
	GNM_const(0.01664469118982119216319487), /* 5.0 */
	GNM_const(0.01513497322191737887351255), /* 5.5 */
	GNM_const(0.01387612882307074799874573), /* 6.0 */
	GNM_const(0.01281046524292022692424986), /* 6.5 */
	GNM_const(0.01189670994589177009505572), /* 7.0 */
	GNM_const(0.01110455975820691732662991), /* 7.5 */
	GNM_const(0.010411265261972096497478567), /* 8.0 */
	GNM_const(0.009799416126158803298389475), /* 8.5 */
	GNM_const(0.009255462182712732917728637), /* 9.0 */
	GNM_const(0.008768700134139385462952823), /* 9.5 */
	GNM_const(0.008330563433362871256469318), /* 10.0 */
	GNM_const(0.007934114564314020547248100), /* 10.5 */
	GNM_const(0.007573675487951840794972024), /* 11.0 */
	GNM_const(0.007244554301320383179543912), /* 11.5 */
	GNM_const(0.006942840107209529865664152), /* 12.0 */
	GNM_const(0.006665247032707682442354394), /* 12.5 */
	GNM_const(0.006408994188004207068439631), /* 13.0 */
	GNM_const(0.006171712263039457647532867), /* 13.5 */
	GNM_const(0.005951370112758847735624416), /* 14.0 */
	GNM_const(0.005746216513010115682023589), /* 14.5 */
	GNM_const(0.005554733551962801371038690)  /* 15.0 */
    };
    gnm_float nn;

    if (n <= 15.0) {
	nn = n + n;
	if (nn == (int)nn) return(sferr_halves[(int)nn]);
	return(lgamma1p (n ) - (n + 0.5)*gnm_log(n) + n - M_LN_SQRT_2PI);
    }

    nn = n*n;
    if (n>500) return((S0-S1/nn)/n);
    if (n> 80) return((S0-(S1-S2/nn)/nn)/n);
    if (n> 35) return((S0-(S1-(S2-S3/nn)/nn)/nn)/n);
    /* 15 < n <= 35 : */
    return((S0-(S1-(S2-(S3-S4/nn)/nn)/nn)/nn)/n);
}
Example #4
0
gnm_float
dsnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean give_log)
{
    if (shape == 0.)
        return dnorm (x, location, scale, give_log);
    else if (give_log)
        return gnm_log (2.) + dnorm (x, location, scale, TRUE) + pnorm (shape * x, shape * location, scale, TRUE, TRUE);
    else
        return 2 * dnorm (x, location, scale, FALSE) * pnorm (shape * x, location/shape, scale, TRUE, FALSE);
}
Example #5
0
void
gsl_complex_arccos (complex_t const *a, complex_t *res)
{                               /* z = arccos(a) */
        gnm_float R = GSL_REAL (a), I = GSL_IMAG (a);

	if (I == 0) {
	        gsl_complex_arccos_real (R, res);
	} else {
	        gnm_float x = gnm_abs (R);
		gnm_float y = gnm_abs (I);
		gnm_float r = gnm_hypot (x + 1, y);
		gnm_float s = gnm_hypot (x - 1, y);
		gnm_float A = 0.5 * (r + s);
		gnm_float B = x / A;
		gnm_float y2 = y * y;

		gnm_float real, imag;

		const gnm_float A_crossover = 1.5;
		const gnm_float B_crossover = 0.6417;

		if (B <= B_crossover) {
		        real = gnm_acos (B);
		} else {
		        if (x <= 1) {
			        gnm_float D = 0.5 * (A + x) *
				        (y2 / (r + x + 1) + (s + (1 - x)));
				real = gnm_atan (gnm_sqrt (D) / x);
			} else {
			        gnm_float Apx = A + x;
				gnm_float D = 0.5 * (Apx / (r + x + 1) + Apx /
						      (s + (x - 1)));
				real = gnm_atan ((y * gnm_sqrt (D)) / x);
			}
		}
		if (A <= A_crossover) {
		        gnm_float Am1;

			if (x < 1) {
			        Am1 = 0.5 * (y2 / (r + (x + 1)) + y2 /
					     (s + (1 - x)));
			} else {
			        Am1 = 0.5 * (y2 / (r + (x + 1)) +
					     (s + (x - 1)));
			}

			imag = gnm_log1p (Am1 + gnm_sqrt (Am1 * (A + 1)));
		} else {
		        imag = gnm_log (A + gnm_sqrt (A * A - 1));
		}

		complex_init (res, (R >= 0) ? real : M_PIgnum - real, (I >= 0) ?
			      -imag : imag);
	}
}
Example #6
0
gnm_float
dst (gnm_float x, gnm_float n, gnm_float shape, gboolean give_log)
{
    if (shape == 0.)
        return dt (x, n, give_log);
    else {
        gnm_float pdf = dt (x, n, give_log);
        gnm_float cdf = pt (shape * x * gnm_sqrt ((n + 1)/(x * x + n)),
                            n + 1, TRUE, give_log);
        return ((give_log) ? (gnm_log (2.) + pdf + cdf) : (2. * pdf * cdf));
    }
}
Example #7
0
gnm_float
qgumbel (gnm_float p, gnm_float mu, gnm_float beta, gboolean lower_tail, gboolean log_p)
{
	if (!(beta > 0) ||
	    gnm_isnan (mu) || gnm_isnan (beta) || gnm_isnan (p) ||
	    (log_p ? p > 0 : (p < 0 || p > 1)))
		return gnm_nan;

	if (log_p) {
		if (!lower_tail)
			p = swap_log_tail (p);
	} else {
		if (lower_tail)
			p = gnm_log (p);
		else
			p = gnm_log1p (-p);
	}

	/* We're now in the log_p, lower_tail case.  */
	return mu - beta * gnm_log (-p);
}
Example #8
0
gnm_float
dgumbel (gnm_float x, gnm_float mu, gnm_float beta, gboolean give_log)
{
	gnm_float z, lp;

	if (!(beta > 0) || gnm_isnan (mu) || gnm_isnan (beta) || gnm_isnan (x))
		return gnm_nan;

	z = (x - mu) / beta;
	lp = -(z + gnm_exp (-z));
	return give_log ? lp - gnm_log (beta) : gnm_exp (lp) / beta;
}
Example #9
0
gnm_float gnm_lbeta(gnm_float a, gnm_float b)
{
    gnm_float corr, p, q;

    p = q = a;
    if(b < p) p = b;/* := min(a,b) */
    if(b > q) q = b;/* := max(a,b) */

#ifdef IEEE_754
    if(gnm_isnan(a) || gnm_isnan(b))
	return a + b;
#endif

    /* both arguments must be >= 0 */

    if (p < 0)
	ML_ERR_return_NAN
    else if (p == 0) {
	return gnm_pinf;
    }
    else if (!gnm_finite(q)) {
	return gnm_ninf;
    }

    if (p >= 10) {
	/* p and q are big. */
	corr = lgammacor(p) + lgammacor(q) - lgammacor(p + q);
	return gnm_log(q) * -0.5 + M_LN_SQRT_2PI + corr
		+ (p - 0.5) * gnm_log(p / (p + q)) + q * gnm_log1p(-p / (p + q));
    }
    else if (q >= 10) {
	/* p is small, but q is big. */
	corr = lgammacor(q) - lgammacor(p + q);
	return gnm_lgamma(p) + corr + p - p * gnm_log(p + q)
		+ (q - 0.5) * gnm_log1p(-p / (p + q));
    }
    else
	/* p and q are small: p <= q < 10. */
	return gnm_lgamma (p) + gnm_lgamma (q) - gnm_lgamma (p + q);
}
Example #10
0
gnm_float
psnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean lower_tail, gboolean log_p)
{
	gnm_float result, h;

	if (gnm_isnan (x) || gnm_isnan (shape) ||
	    gnm_isnan (location) || gnm_isnan (scale))
		return gnm_nan;

	if (shape == 0.)
		return pnorm (x, location, scale, lower_tail, log_p);

	/* Normalize */
	h = (x - location) / scale;

	/* Flip to a lower-tail problem.  */
	if (!lower_tail) {
		h = -h;
		shape = -shape;
		lower_tail = !lower_tail;
	}

	if (gnm_abs (shape) < 10) {
		gnm_float s = pnorm (h, 0, 1, lower_tail, FALSE);
		gnm_float t = 2 * gnm_owent (h, shape);
		result = s - t;
	} else {
		/*
		 * Make use of this result for Owen's T:
		 *
		 * T(h,a) = .5N(h) + .5N(ha) - N(h)N(ha) - T(ha,1/a)
		 */
		gnm_float s = pnorm (h * shape, 0, 1, TRUE, FALSE);
		gnm_float u = gnm_erf (h / M_SQRT2gnum);
		gnm_float t = 2 * gnm_owent (h * shape, 1 / shape);
		result = s * u + t;
	}

	/*
	 * Negatives can occur due to rounding errors and hopefully for no
	 * other reason.
	 */
	result= CLAMP (result, 0.0, 1.0);

	if (log_p)
		return gnm_log (result);
	else
		return result;
}
Example #11
0
gnm_float
psnorm (gnm_float x, gnm_float shape, gnm_float location, gnm_float scale, gboolean lower_tail, gboolean log_p)
{
    gnm_float result;

    if (shape == 0.)
        return pnorm (x, location, scale, lower_tail, log_p);

    result = pnorm (x, location, scale, TRUE, FALSE) - 2 * gnm_owent ((x - location)/scale, shape);

    if (!lower_tail)
        result = 1. - result;

    if (log_p)
        return gnm_log (result);
    else
        return result;
}
Example #12
0
void
gsl_complex_arctan (complex_t const *a, complex_t *res)
{                               /* z = arctan(a) */
        gnm_float R = GSL_REAL (a), I = GSL_IMAG (a);

	if (I == 0) {
	        complex_init (res, gnm_atan (R), 0);
	} else {
	        /* FIXME: This is a naive implementation which does not fully
		 * take into account cancellation errors, overflow, underflow
		 * etc.  It would benefit from the Hull et al treatment. */

	        gnm_float r = gnm_hypot (R, I);

		gnm_float imag;

		gnm_float u = 2 * I / (1 + r * r);

		/* FIXME: the following cross-over should be optimized but 0.1
		 * seems to work ok */

		if (gnm_abs (u) < 0.1) {
		        imag = 0.25 * (gnm_log1p (u) - gnm_log1p (-u));
		} else {
		        gnm_float A = gnm_hypot (R, I + 1);
			gnm_float B = gnm_hypot (R, I - 1);
			imag = 0.5 * gnm_log (A / B);
		}
		if (R == 0) {
		        if (I > 1) {
			        complex_init (res, M_PI_2gnum, imag);
			} else if (I < -1) {
			        complex_init (res, -M_PI_2gnum, imag);
			} else {
			        complex_init (res, 0, imag);
			}
		} else {
		        complex_init (res, 0.5 * gnm_atan2 (2 * R,
							    ((1 + r) * (1 - r))),
				      imag);
		}
	}
}
Example #13
0
/**
 * gnm_lbeta3:
 * @a: a number
 * @b: a number
 * @sign: (out): the sign
 *
 * Returns: the logarithm of the absolute value of the Beta function
 * evaluated at @a and @b.  The sign will be stored in @sign as -1 or
 * +1.  This function is useful because the result of the beta
 * function can be too large for doubles.
 */
gnm_float
gnm_lbeta3 (gnm_float a, gnm_float b, int *sign)
{
	int sign_a, sign_b, sign_ab;
	gnm_float ab = a + b;
	gnm_float res_a, res_b, res_ab;
	GnmQuad r;
	int e;

	switch (qbetaf (a, b, &r, &e)) {
	case 0: {
		gnm_float m = gnm_quad_value (&r);
		*sign = (m >= 0 ? +1 : -1);
		return gnm_log (gnm_abs (m)) + e * M_LN2gnum;
	}
	case 1:
		/* Overflow */
		break;
	default:
		*sign = 1;
		return gnm_nan;
	}

	if (a > 0 && b > 0) {
		*sign = 1;
		return gnm_lbeta (a, b);
	}

	/* This is awful */
	res_a = gnm_lgamma_r (a, &sign_a);
	res_b = gnm_lgamma_r (b, &sign_b);
	res_ab = gnm_lgamma_r (ab, &sign_ab);

	*sign = sign_a * sign_b * sign_ab;
	return res_a + res_b - res_ab;
}
Example #14
0
gnm_float
pochhammer (gnm_float x, gnm_float n)
{
	gnm_float rn, rx, lr;
	GnmQuad m1, m2;
	int e1, e2;

	if (gnm_isnan (x) || gnm_isnan (n))
		return gnm_nan;

	if (n == 0)
		return 1;

	rx = gnm_floor (x);
	rn = gnm_floor (n);

	/*
	 * Use naive multiplication when n is a small integer.
	 * We don't want to use this if x is also an integer
	 * (but we might do so below if x is insanely large).
	 */
	if (n == rn && x != rx && n >= 0 && n < 40)
		return pochhammer_naive (x, (int)n);

	if (!qfactf (x + n - 1, &m1, &e1) &&
	    !qfactf (x - 1, &m2, &e2)) {
		void *state = gnm_quad_start ();
		int de = e1 - e2;
		GnmQuad qr;
		gnm_float r;

		gnm_quad_div (&qr, &m1, &m2);
		r = gnm_quad_value (&qr);
		gnm_quad_end (state);

		return gnm_ldexp (r, de);
	}

	if (x == rx && x <= 0) {
		if (n != rn)
			return 0;
		if (x == 0)
			return (n > 0)
				? 0
				: ((gnm_fmod (-n, 2) == 0 ? +1 : -1) /
				   gnm_fact (-n));
		if (n > -x)
			return gnm_nan;
	}

	/*
	 * We have left the common cases.  One of x+n and x is
	 * insanely big, possibly both.
	 */

	if (gnm_abs (x) < 1)
		return gnm_pinf;

	if (n < 0)
		return 1 / pochhammer (x + n, -n);

	if (n == rn && n >= 0 && n < 100)
		return pochhammer_naive (x, (int)n);

	if (gnm_abs (n) < 1) {
		/* x is big.  */
		void *state = gnm_quad_start ();
		GnmQuad qr;
		gnm_float r;
		pochhammer_small_n (x, n, &qr);
		r = gnm_quad_value (&qr);
		gnm_quad_end (state);
		return r;
	}

	/* Panic mode.  */
	g_printerr ("x=%.20g  n=%.20g\n", x, n);
	lr = ((x - 0.5) * gnm_log1p (n / x) +
	      n * gnm_log (x + n) -
	      n +
	      (lgammacor (x + n) - lgammacor (x)));
	return gnm_exp (lr);
}
Example #15
0
gnm_float
pst (gnm_float x, gnm_float n, gnm_float shape, gboolean lower_tail, gboolean log_p)
{
	gnm_float p;

	if (n <= 0 || gnm_isnan (x) || gnm_isnan (n) || gnm_isnan (shape))
		return gnm_nan;

	if (shape == 0.)
		return pt (x, n, lower_tail, log_p);

	if (n > 100) {
		/* Approximation */
		return psnorm (x, shape, 0.0, 1.0, lower_tail, log_p);
	}

	/* Flip to a lower-tail problem.  */
	if (!lower_tail) {
		x = -x;
		shape = -shape;
		lower_tail = !lower_tail;
	}

	/* Generic fallback.  */
	if (log_p)
		gnm_log (pst (x, n, shape, TRUE, FALSE));

	if (n != gnm_floor (n)) {
		/* We would need numerical integration for this.  */
		return gnm_nan;
	}

	/*
	 * Use recurrence formula from "Recurrent relations for
	 * distributions of a skew-t and a linear combination of order
	 * statistics form a bivariate-t", Computational Statistics
	 * and Data Analysis volume 52, 2009 by Jamallizadeh,
	 * Khosravi, Balakrishnan.
	 *
	 * This brings us down to n==1 or n==2 for which explicit formulas
	 * are available.
	 */

	p = 0;
	while (n > 2) {
		double a, lb, c, d, pv, v = n - 1;

		d = v == 2
			? M_LN2gnum - gnm_log (M_PIgnum) + gnm_log (3) / 2
			: (0.5 + M_LN2gnum / 2 - gnm_log (M_PIgnum) / 2 +
			   v / 2 * (gnm_log1p (-1 / (v - 1)) + gnm_log (v + 1)) -
			   0.5 * (gnm_log (v - 2) + gnm_log (v + 1)) +
			   stirlerr (v / 2 - 1) -
			   stirlerr ((v - 1) / 2));

		a = v + 1 + x * x;
		lb = (d - gnm_log (a) * v / 2);
		c = pt (gnm_sqrt (v) * shape * x / gnm_sqrt (a), v, TRUE, FALSE);
		pv = x * gnm_exp (lb) * c;
		p += pv;

		n -= 2;
		x *= gnm_sqrt ((v - 1) / (v + 1));
	}

	g_return_val_if_fail (n == 1 || n == 2, gnm_nan);
	if (n == 1) {
		gnm_float p1;

		p1 = (gnm_atan (x) + gnm_acos (shape / gnm_sqrt ((1 + shape * shape) * (1 + x * x)))) / M_PIgnum;
		p += p1;
	} else if (n == 2) {
		gnm_float p2, f;

		f = x / gnm_sqrt (2 + x * x);

		p2 = (gnm_atan_mpihalf (shape) + f * gnm_atan_mpihalf (-shape * f)) / -M_PIgnum;

		p += p2;
	} else {
		return gnm_nan;
	}

	/*
	 * Negatives can occur due to rounding errors and hopefully for no
	 * other reason.
	 */
	p = CLAMP (p, 0.0, 1.0);

	return p;
}
Example #16
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));
}