mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-30 17:00:23 +02:00
(FLOBUFLEN): Increase so that radix 2 strings will fit.
(fx): Removed. (scm_dblprec, fx_per_radix, init_dblprec, init_fx_radix, number_chars): New, to support variable radices. (idbl2str): Use above instead of the old base-10 only tables. (iflo2str): Pass on new RADIX argument to idbl2str. (scm_number_to_string): Pass radix to iflo2str. (scm_print_real, scm_print_complex): Explicitly pass radix 10 to iflo2str. (scm_init_numbers): Call init_dblprec and init_fx_radix for all possible radices.
This commit is contained in:
parent
d12a658091
commit
0b799eeab6
1 changed files with 114 additions and 63 deletions
|
@ -91,7 +91,7 @@
|
||||||
/* FLOBUFLEN is the maximum number of characters neccessary for the
|
/* FLOBUFLEN is the maximum number of characters neccessary for the
|
||||||
* printed or scm_string representation of an inexact number.
|
* printed or scm_string representation of an inexact number.
|
||||||
*/
|
*/
|
||||||
#define FLOBUFLEN (10+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
|
#define FLOBUFLEN (40+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
|
||||||
|
|
||||||
#if defined (SCO)
|
#if defined (SCO)
|
||||||
#if ! defined (HAVE_ISNAN)
|
#if ! defined (HAVE_ISNAN)
|
||||||
|
@ -1973,19 +1973,71 @@ SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
|
|
||||||
/*** NUMBERS -> STRINGS ***/
|
/*** NUMBERS -> STRINGS ***/
|
||||||
int scm_dblprec;
|
#define SCM_MAX_DBL_PREC 60
|
||||||
static const double fx[] =
|
#define SCM_MAX_DBL_RADIX 36
|
||||||
{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
|
|
||||||
5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
|
/* this is an array starting with radix 2, and ending with radix SCM_MAX_DBL_RADIX */
|
||||||
5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
|
static int scm_dblprec[SCM_MAX_DBL_RADIX - 1];
|
||||||
5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
|
static double fx_per_radix[SCM_MAX_DBL_RADIX - 1][SCM_MAX_DBL_PREC];
|
||||||
|
|
||||||
|
static
|
||||||
|
void init_dblprec(int *prec, int radix) {
|
||||||
|
/* determine floating point precision by adding successively
|
||||||
|
smaller increments to 1.0 until it is considered == 1.0 */
|
||||||
|
double f = ((double)1.0)/radix;
|
||||||
|
double fsum = 1.0 + f;
|
||||||
|
|
||||||
|
*prec = 0;
|
||||||
|
while (fsum != 1.0)
|
||||||
|
{
|
||||||
|
if (++(*prec) > SCM_MAX_DBL_PREC)
|
||||||
|
fsum = 1.0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f /= radix;
|
||||||
|
fsum = f + 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*prec) -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void init_fx_radix(double *fx_list, int radix)
|
||||||
|
{
|
||||||
|
/* initialize a per-radix list of tolerances. When added
|
||||||
|
to a number < 1.0, we can determine if we should raund
|
||||||
|
up and quit converting a number to a string. */
|
||||||
|
int i;
|
||||||
|
fx_list[0] = 0.0;
|
||||||
|
fx_list[1] = 0.5;
|
||||||
|
for( i = 2 ; i < SCM_MAX_DBL_PREC; ++i )
|
||||||
|
fx_list[i] = (fx_list[i-1] / radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use this array as a way to generate a single digit */
|
||||||
|
static const char*number_chars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
idbl2str (double f, char *a)
|
idbl2str (double f, char *a, int radix)
|
||||||
{
|
{
|
||||||
int efmt, dpt, d, i, wp = scm_dblprec;
|
int efmt, dpt, d, i, wp;
|
||||||
size_t ch = 0;
|
double *fx;
|
||||||
int exp = 0;
|
#ifdef DBL_MIN_10_EXP
|
||||||
|
double f_cpy;
|
||||||
|
int exp_cpy;
|
||||||
|
#endif /* DBL_MIN_10_EXP */
|
||||||
|
size_t ch = 0;
|
||||||
|
int exp = 0;
|
||||||
|
|
||||||
|
if(radix < 2 ||
|
||||||
|
radix > SCM_MAX_DBL_RADIX)
|
||||||
|
{
|
||||||
|
/* revert to existing behavior */
|
||||||
|
radix = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp = scm_dblprec[radix-2];
|
||||||
|
fx = fx_per_radix[radix-2];
|
||||||
|
|
||||||
if (f == 0.0)
|
if (f == 0.0)
|
||||||
{
|
{
|
||||||
|
@ -1995,7 +2047,6 @@ idbl2str (double f, char *a)
|
||||||
if (sgn < 0.0)
|
if (sgn < 0.0)
|
||||||
a[ch++] = '-';
|
a[ch++] = '-';
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
|
goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2021,10 +2072,15 @@ idbl2str (double f, char *a)
|
||||||
|
|
||||||
#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
|
#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
|
||||||
make-uniform-vector, from causing infinite loops. */
|
make-uniform-vector, from causing infinite loops. */
|
||||||
while (f < 1.0)
|
/* just do the checking...if it passes, we do the conversion for our
|
||||||
|
radix again below */
|
||||||
|
f_cpy = f;
|
||||||
|
exp_cpy = exp;
|
||||||
|
|
||||||
|
while (f_cpy < 1.0)
|
||||||
{
|
{
|
||||||
f *= 10.0;
|
f_cpy *= 10.0;
|
||||||
if (exp-- < DBL_MIN_10_EXP)
|
if (exp_cpy-- < DBL_MIN_10_EXP)
|
||||||
{
|
{
|
||||||
a[ch++] = '#';
|
a[ch++] = '#';
|
||||||
a[ch++] = '.';
|
a[ch++] = '.';
|
||||||
|
@ -2032,10 +2088,10 @@ idbl2str (double f, char *a)
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (f > 10.0)
|
while (f_cpy > 10.0)
|
||||||
{
|
{
|
||||||
f *= 0.10;
|
f_cpy *= 0.10;
|
||||||
if (exp++ > DBL_MAX_10_EXP)
|
if (exp_cpy++ > DBL_MAX_10_EXP)
|
||||||
{
|
{
|
||||||
a[ch++] = '#';
|
a[ch++] = '#';
|
||||||
a[ch++] = '.';
|
a[ch++] = '.';
|
||||||
|
@ -2043,25 +2099,27 @@ idbl2str (double f, char *a)
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
while (f < 1.0)
|
|
||||||
{
|
|
||||||
f *= 10.0;
|
|
||||||
exp--;
|
|
||||||
}
|
|
||||||
while (f > 10.0)
|
|
||||||
{
|
|
||||||
f /= 10.0;
|
|
||||||
exp++;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (f + fx[wp] >= 10.0)
|
|
||||||
|
while (f < 1.0)
|
||||||
|
{
|
||||||
|
f *= radix;
|
||||||
|
exp--;
|
||||||
|
}
|
||||||
|
while (f > radix)
|
||||||
|
{
|
||||||
|
f /= radix;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f + fx[wp] >= radix)
|
||||||
{
|
{
|
||||||
f = 1.0;
|
f = 1.0;
|
||||||
exp++;
|
exp++;
|
||||||
}
|
}
|
||||||
zero:
|
zero:
|
||||||
#ifdef ENGNOT
|
#ifdef ENGNOT
|
||||||
|
/* adding 9999 makes this equivalent to abs(x) % 3 */
|
||||||
dpt = (exp + 9999) % 3;
|
dpt = (exp + 9999) % 3;
|
||||||
exp -= dpt++;
|
exp -= dpt++;
|
||||||
efmt = 1;
|
efmt = 1;
|
||||||
|
@ -2088,15 +2146,15 @@ idbl2str (double f, char *a)
|
||||||
{
|
{
|
||||||
d = f;
|
d = f;
|
||||||
f -= d;
|
f -= d;
|
||||||
a[ch++] = d + '0';
|
a[ch++] = number_chars[d];
|
||||||
if (f < fx[wp])
|
if (f < fx[wp])
|
||||||
break;
|
break;
|
||||||
if (f + fx[wp] >= 1.0)
|
if (f + fx[wp] >= 1.0)
|
||||||
{
|
{
|
||||||
a[ch - 1]++;
|
a[ch - 1] = number_chars[d+1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f *= 10.0;
|
f *= radix;
|
||||||
if (!(--dpt))
|
if (!(--dpt))
|
||||||
a[ch++] = '.';
|
a[ch++] = '.';
|
||||||
}
|
}
|
||||||
|
@ -2131,26 +2189,25 @@ idbl2str (double f, char *a)
|
||||||
exp = -exp;
|
exp = -exp;
|
||||||
a[ch++] = '-';
|
a[ch++] = '-';
|
||||||
}
|
}
|
||||||
for (i = 10; i <= exp; i *= 10);
|
for (i = radix; i <= exp; i *= radix);
|
||||||
for (i /= 10; i; i /= 10)
|
for (i /= radix; i; i /= radix)
|
||||||
{
|
{
|
||||||
a[ch++] = exp / i + '0';
|
a[ch++] = number_chars[exp / i];
|
||||||
exp %= i;
|
exp %= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
iflo2str (SCM flt, char *str)
|
iflo2str (SCM flt, char *str, int radix)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
if (SCM_REALP (flt))
|
if (SCM_REALP (flt))
|
||||||
i = idbl2str (SCM_REAL_VALUE (flt), str);
|
i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i = idbl2str (SCM_COMPLEX_REAL (flt), str);
|
i = idbl2str (SCM_COMPLEX_REAL (flt), str, radix);
|
||||||
if (SCM_COMPLEX_IMAG (flt) != 0.0)
|
if (SCM_COMPLEX_IMAG (flt) != 0.0)
|
||||||
{
|
{
|
||||||
double imag = SCM_COMPLEX_IMAG (flt);
|
double imag = SCM_COMPLEX_IMAG (flt);
|
||||||
|
@ -2158,7 +2215,7 @@ iflo2str (SCM flt, char *str)
|
||||||
NaN. They will provide their own sign. */
|
NaN. They will provide their own sign. */
|
||||||
if (0 <= imag && !xisinf (imag) && !xisnan (imag))
|
if (0 <= imag && !xisinf (imag) && !xisnan (imag))
|
||||||
str[i++] = '+';
|
str[i++] = '+';
|
||||||
i += idbl2str (imag, &str[i]);
|
i += idbl2str (imag, &str[i], radix);
|
||||||
str[i++] = 'i';
|
str[i++] = 'i';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2239,7 +2296,7 @@ SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
|
||||||
else if (SCM_INEXACTP (n))
|
else if (SCM_INEXACTP (n))
|
||||||
{
|
{
|
||||||
char num_buf [FLOBUFLEN];
|
char num_buf [FLOBUFLEN];
|
||||||
return scm_mem2string (num_buf, iflo2str (n, num_buf));
|
return scm_mem2string (num_buf, iflo2str (n, num_buf, base));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SCM_WRONG_TYPE_ARG (1, n);
|
SCM_WRONG_TYPE_ARG (1, n);
|
||||||
|
@ -2254,7 +2311,7 @@ int
|
||||||
scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
|
scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
|
||||||
{
|
{
|
||||||
char num_buf[FLOBUFLEN];
|
char num_buf[FLOBUFLEN];
|
||||||
scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
|
scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
|
||||||
return !0;
|
return !0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2263,7 +2320,7 @@ scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
|
||||||
|
|
||||||
{
|
{
|
||||||
char num_buf[FLOBUFLEN];
|
char num_buf[FLOBUFLEN];
|
||||||
scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
|
scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
|
||||||
return !0;
|
return !0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5710,6 +5767,8 @@ SCM_DEFINE (scm_sys_check_number_conversions, "%check-number-conversions", 0, 0,
|
||||||
void
|
void
|
||||||
scm_init_numbers ()
|
scm_init_numbers ()
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
mpz_init_set_si (z_negative_one, -1);
|
mpz_init_set_si (z_negative_one, -1);
|
||||||
|
|
||||||
/* It may be possible to tune the performance of some algorithms by using
|
/* It may be possible to tune the performance of some algorithms by using
|
||||||
|
@ -5724,25 +5783,17 @@ scm_init_numbers ()
|
||||||
scm_add_feature ("complex");
|
scm_add_feature ("complex");
|
||||||
scm_add_feature ("inexact");
|
scm_add_feature ("inexact");
|
||||||
scm_flo0 = scm_make_real (0.0);
|
scm_flo0 = scm_make_real (0.0);
|
||||||
|
|
||||||
|
/* determine floating point precision */
|
||||||
|
for(i=2; i <= SCM_MAX_DBL_RADIX; ++i)
|
||||||
|
{
|
||||||
|
init_dblprec(&scm_dblprec[i-2],i);
|
||||||
|
init_fx_radix(fx_per_radix[i-2],i);
|
||||||
|
}
|
||||||
#ifdef DBL_DIG
|
#ifdef DBL_DIG
|
||||||
scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
|
/* hard code precision for base 10 if the preprocessor tells us to... */
|
||||||
#else
|
scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
|
||||||
{ /* determine floating point precision */
|
#endif
|
||||||
double f = 0.1;
|
|
||||||
double fsum = 1.0 + f;
|
|
||||||
while (fsum != 1.0)
|
|
||||||
{
|
|
||||||
if (++scm_dblprec > 20)
|
|
||||||
fsum = 1.0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f /= 10.0;
|
|
||||||
fsum = f + 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm_dblprec = scm_dblprec - 1;
|
|
||||||
}
|
|
||||||
#endif /* DBL_DIG */
|
|
||||||
|
|
||||||
#ifdef GUILE_DEBUG
|
#ifdef GUILE_DEBUG
|
||||||
check_sanity ();
|
check_sanity ();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue