Commit b616f813 authored by Morten Welinder's avatar Morten Welinder Committed by Morten Welinder

Check for ldexpl and frexpl.

2002-02-22  Morten Welinder  <terra@diku.dk>

	* configure.in: Check for ldexpl and frexpl.

	* src/mathfunc.c (gpow2): New function.
	(gnumeric_add_epsilon, gnumeric_sub_epsilon, gnumeric_fake_floor,
	gnumeric_fake_ceil, gnumeric_fake_round, gnumeric_fake_trunc):
	Make these gnum_float typed.

	* src/numbers.h (frexpgnum, ldexpgnum): New stuff.
parent 2c356b79
2002-02-22 Morten Welinder <terra@diku.dk>
* configure.in: Check for ldexpl and frexpl.
* src/mathfunc.c (gpow2): New function.
(gnumeric_add_epsilon, gnumeric_sub_epsilon, gnumeric_fake_floor,
gnumeric_fake_ceil, gnumeric_fake_round, gnumeric_fake_trunc):
Make these gnum_float typed.
* src/numbers.h (frexpgnum, ldexpgnum): New stuff.
2002-02-21 Morten Welinder <terra@diku.dk>
* src/numbers.h: Define prototypes for strtognum, modfgnum, and
......
2002-02-22 Morten Welinder <terra@diku.dk>
* configure.in: Check for ldexpl and frexpl.
* src/mathfunc.c (gpow2): New function.
(gnumeric_add_epsilon, gnumeric_sub_epsilon, gnumeric_fake_floor,
gnumeric_fake_ceil, gnumeric_fake_round, gnumeric_fake_trunc):
Make these gnum_float typed.
* src/numbers.h (frexpgnum, ldexpgnum): New stuff.
2002-02-21 Morten Welinder <terra@diku.dk>
* src/numbers.h: Define prototypes for strtognum, modfgnum, and
......
2002-02-22 Morten Welinder <terra@diku.dk>
* configure.in: Check for ldexpl and frexpl.
* src/mathfunc.c (gpow2): New function.
(gnumeric_add_epsilon, gnumeric_sub_epsilon, gnumeric_fake_floor,
gnumeric_fake_ceil, gnumeric_fake_round, gnumeric_fake_trunc):
Make these gnum_float typed.
* src/numbers.h (frexpgnum, ldexpgnum): New stuff.
2002-02-21 Morten Welinder <terra@diku.dk>
* src/numbers.h: Define prototypes for strtognum, modfgnum, and
......
......@@ -72,7 +72,7 @@ AC_ARG_WITH(long_double,
if test "$ac_cv_c_long_double" != "yes"; then
AC_MSG_ERROR([Long double type is not available.])
fi
AC_CHECK_FUNCS(strtold modfl fabsl string_to_decimal decimal_to_quadruple)
AC_CHECK_FUNCS(strtold modfl fabsl frexpl ldexpl string_to_decimal decimal_to_quadruple)
AC_CHECK_HEADERS(floatingpoint.h)
if test "$ac_cv_func_strtold" = "yes"; then
......
......@@ -12,6 +12,7 @@
#include "sheet.h"
#include "ranges.h"
#include "mathfunc.h"
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-config.h>
......@@ -584,7 +585,6 @@ gnumabs (gnum_float x)
/* ------------------------------------------------------------------------- */
#ifdef NEED_FAKE_STRTOGNUM
gnum_float
strtognum (const char *str, char **end)
{
......@@ -634,3 +634,58 @@ strtognum (const char *str, char **end)
#endif
/* ------------------------------------------------------------------------- */
#ifdef NEED_FAKE_LDEXPGNUM
gnum_float
ldexpgnum (gnum_float x, int exp)
{
if (!FINITE (x) || x == 0)
return x;
else {
gnum_float res = x * gpow2 (exp);
if (FINITE (res))
return res;
else {
errno = ERANGE;
return (x > 0) ? HUGE_VAL : -HUGE_VAL;
}
}
}
#endif
/* ------------------------------------------------------------------------- */
#ifdef NEED_FAKE_FREXPGNUM
gnum_float
frexpgnum (gnum_float x, int *exp)
{
static gboolean warned = FALSE;
double dbl_res;
gnum_float res;
if (!warned) {
warned = TRUE;
g_warning (_("This version of Gnumeric has been compiled with inadequate precision in frexpgnum."));
}
/* This might underflow or overflow in the cast. */
dbl_res = frexp ((double)x, exp);
if (!FINITE (x) || x == 0)
return dbl_res;
/*
* Now correct the result and adjust things that might have gotten
* off-by-one due to rounding. This part has all the precision it
* needs.
*/
res = x / gpow2 (*exp);
if (gnumabs (res) >= 1.0)
res /= 2, (*exp)++;
else if (gnumabs (res) < 0.5)
res *= 2, (*exp)--;
return res;
}
#endif
/* ------------------------------------------------------------------------- */
......@@ -87,54 +87,54 @@ d1mach (int i)
* absolutely). This makes ROUND (etc.) behave a little closer to what
* people want, even if it is a bit bogus.
*/
double
gnumeric_add_epsilon (double x)
gnum_float
gnumeric_add_epsilon (gnum_float x)
{
if (!FINITE (x) || x == 0)
return x;
else {
int exp;
double mant = frexp (fabs (x), &exp);
double absres = ldexp (mant + DBL_EPSILON, exp);
gnum_float mant = frexpgnum (gnumabs (x), &exp);
gnum_float absres = ldexpgnum (mant + GNUM_EPSILON, exp);
return (x < 0) ? -absres : absres;
}
}
double
gnumeric_sub_epsilon (double x)
gnum_float
gnumeric_sub_epsilon (gnum_float x)
{
if (!FINITE (x) || x == 0)
return x;
else {
int exp;
double mant = frexp (fabs (x), &exp);
double absres = ldexp (mant - DBL_EPSILON, exp);
gnum_float mant = frexpgnum (gnumabs (x), &exp);
gnum_float absres = ldexpgnum (mant - GNUM_EPSILON, exp);
return (x < 0) ? -absres : absres;
}
}
double
gnumeric_fake_floor (double x)
gnum_float
gnumeric_fake_floor (gnum_float x)
{
return floor (gnumeric_add_epsilon (x));
}
double
gnumeric_fake_ceil (double x)
gnum_float
gnumeric_fake_ceil (gnum_float x)
{
return ceil (gnumeric_sub_epsilon (x));
}
double
gnumeric_fake_round (double x)
gnum_float
gnumeric_fake_round (gnum_float x)
{
return (x >= 0)
? gnumeric_fake_floor (x + 0.5)
: -gnumeric_fake_floor (-x + 0.5);
}
double
gnumeric_fake_trunc (double x)
gnum_float
gnumeric_fake_trunc (gnum_float x)
{
return (x >= 0)
? gnumeric_fake_floor (x)
......@@ -3713,6 +3713,28 @@ random_bernoulli (double p)
return (r <= p) ? 1.0 : 0.0;
}
/*
* Generate 2^n being careful not to overflow
*/
gnum_float
gpow2 (int n)
{
g_assert (FLT_RADIX == 2);
if (n >= DBL_MIN_EXP && n <= DBL_MAX_EXP)
return (gnum_float) ldexp (1.0, n);
else {
gnum_float tmp;
tmp = gpow2 (n / 2);
tmp *= tmp;
if (n & 1)
tmp *= 2;
return tmp;
}
}
/*
* Generate 10^n being careful not to overflow
*/
......
......@@ -27,20 +27,20 @@
/* Make up for a few deficient headers. */
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#define M_LN2 0.6931471805599453094172321214581766
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#define M_LN10 2.3025850929940456840179914546843642
#endif
/* ------------------------------------------------------------------------- */
double gnumeric_add_epsilon (double x);
double gnumeric_sub_epsilon (double x);
double gnumeric_fake_floor (double x);
double gnumeric_fake_ceil (double x);
double gnumeric_fake_round (double x);
double gnumeric_fake_trunc (double x);
gnum_float gnumeric_add_epsilon (gnum_float x);
gnum_float gnumeric_sub_epsilon (gnum_float x);
gnum_float gnumeric_fake_floor (gnum_float x);
gnum_float gnumeric_fake_ceil (gnum_float x);
gnum_float gnumeric_fake_round (gnum_float x);
gnum_float gnumeric_fake_trunc (gnum_float x);
/* ------------------------------------------------------------------------- */
......@@ -119,6 +119,7 @@ void mmult (gnum_float *A, gnum_float *B, int cols_a, int rows_a, int cols_b,
/* Misc. */
gnum_float gpow10 (int n);
gnum_float gpow2 (int n);
int gcd (int a, int b);
gnum_float combin (int n, int k);
gnum_float fact (int n);
......
......@@ -31,6 +31,22 @@ gnum_float modfgnum (gnum_float x, gnum_float *iptr);
gnum_float gnumabs (gnum_float x);
#endif
#ifdef HAVE_LDEXPL
#define ldexpgnum ldexpl
#else
#define NEED_FAKE_LDEXPGNUM
/* Defined in gutils.c */
gnum_float ldexpgnum (gnum_float x, int exp);
#endif
#ifdef HAVE_FREXPL
#define frexpgnum frexpl
#else
#define NEED_FAKE_FREXPGNUM
/* Defined in gutils.c */
gnum_float frexpgnum (gnum_float x, int *exp);
#endif
#define GNUM_FORMAT_e "Le"
#define GNUM_FORMAT_E "LE"
#define GNUM_FORMAT_f "Lf"
......@@ -39,6 +55,8 @@ gnum_float gnumabs (gnum_float x);
#define GNUM_MANT_DIG LDBL_MANT_DIG
#define GNUM_MAX_EXP LDBL_MAX_EXP
#define GNUM_MAX LDBL_MAX
#define GNUM_EPSILON LDBL_EPSILON
#define GNUM_const(_c) _c ## L
#else /* !WITH_LONG_DOUBLE */
......@@ -46,6 +64,8 @@ typedef double gnum_float;
#define strtognum strtod
#define modfgnum modf
#define gnumabs fabs
#define ldexpgnum ldexp
#define frexpgnum frexp
#define GNUM_FORMAT_e "e"
#define GNUM_FORMAT_E "E"
......@@ -55,6 +75,8 @@ typedef double gnum_float;
#define GNUM_MANT_DIG DBL_MANT_DIG
#define GNUM_MAX_EXP DBL_MAX_EXP
#define GNUM_MAX DBL_MAX
#define GNUM_EPSILON DBL_EPSILON
#define GNUM_const(_c) _c
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment