Skip to content

Commit b7a17d3

Browse files
author
maechler
committed
signif(1***e308, dig) no longer truncates wrongly
git-svn-id: https://svn.r-project.org/R/trunk@88192 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 0bf5b2f commit b7a17d3

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

doc/NEWS.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@
118118
\code{dbinom()}, \code{dnbinom()}, and via \code{dbinom_raw()}
119119
potentially \code{dgeom()}, \code{dhyper()}, \code{dbeta()}, and
120120
\code{df()}.
121+
122+
\item \code{signif(1.**e308, digits)} no longer truncates unnecessarily
123+
(but still to prevent overflow to \code{Inf}), fixing \PR{18889}.
121124
}
122125
}
123126
}

src/nmath/fprec.c

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Mathlib : A C Library of Special Functions
3-
* Copyright (C) 2000-2019 The R Core Team
3+
* Copyright (C) 2000-2025 The R Core Team
44
* Copyright (C) 1998 Ross Ihaka
55
*
66
* This program is free software; you can redistribute it and/or modify
@@ -57,38 +57,37 @@
5757
// R's signif(x, digits) via Math2(args, fprec) in ../main/arithmetic.c :
5858
double fprec(double x, double digits)
5959
{
60-
double l10, pow10, sgn, p10, P10;
61-
int e10, e2, do_round, dig;
62-
// Max.expon. of 10 (w/o denormalizing or overflow; = R's trunc( log10(.Machine$double.xmax) )
63-
const static int max10e = (int) DBL_MAX_10_EXP; // == 308 ("IEEE")
64-
6560
if (ISNAN(x) || ISNAN(digits))
6661
return x + digits;
6762
if (!R_FINITE(x)) return x;
6863
if (!R_FINITE(digits)) {
69-
if(digits > 0.0) return x;
70-
else digits = 1.0;
64+
if(digits > 0.) return x;
65+
else digits = 1.;
7166
}
7267
if(x == 0) return x;
73-
dig = (int)round(digits);
68+
69+
int dig = (int)round(digits);
7470
if (dig > MAX_DIGITS) {
7571
return x;
7672
} else if (dig < 1)
7773
dig = 1;
7874

79-
sgn = 1.0;
75+
double sgn = 1.;
8076
if(x < 0.0) {
8177
sgn = -sgn;
8278
x = -x;
8379
}
84-
l10 = log10(x);
85-
e10 = (int)(dig-1-floor(l10));
80+
double l10 = log10(x);
81+
int e10 = dig-1 - (int)floor(l10);
82+
// Max.expon. of 10 (w/o denormalizing or overflow; = R's trunc( log10(.Machine$double.xmax) ):
83+
const static int max10e = (int) DBL_MAX_10_EXP; // == 308 ("IEEE")
8684
if(fabs(l10) < max10e - 2) {
87-
p10 = 1.0;
85+
double p10 = 1.;
8886
if(e10 > max10e) { /* numbers less than 10^(dig-1) * 1e-308 */
8987
p10 = R_pow_di(10., e10-max10e);
9088
e10 = max10e;
9189
}
90+
double pow10;
9291
if(e10 > 0) { /* Try always to have pow >= 1
9392
and so exactly representable */
9493
pow10 = R_pow_di(10., e10);
@@ -98,10 +97,13 @@ double fprec(double x, double digits)
9897
return(sgn*(nearbyint((x/pow10))*pow10));
9998
}
10099
} else { /* -- LARGE or small -- */
101-
do_round = max10e - l10 >= R_pow_di(10., -dig);
102-
e2 = dig + ((e10>0)? 1 : -1) * MAX_DIGITS;
103-
p10 = R_pow_di(10., e2); x *= p10;
104-
P10 = R_pow_di(10., e10-e2); x *= P10;
100+
bool do_round = log10(DBL_MAX) - l10 >= R_pow_di(10., -dig); /* e.g. signif(1.09e308, 2) */
101+
int e2 = dig + ((e10 > 0)? 1 : -1) * MAX_DIGITS;
102+
double
103+
p10 = R_pow_di(10., e2),
104+
P10 = R_pow_di(10., e10-e2);
105+
x *= p10;
106+
x *= P10;
105107
/*-- p10 * P10 = 10 ^ e10 */
106108
if(do_round) x += 0.5;
107109
x = floor(x) / p10;

tests/reg-tests-1e.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,11 @@ r <- return; assertWarnV(environment(r) <- baseenv())
19491949
## then an error for about one day; now is deprecated (and no longer mutating).
19501950

19511951

1952+
## signif(<LRG>, dig) -- PR#18889
1953+
stopifnot(all.equal(1.1e308, signif(1.06e308, 2)),
1954+
all.equal(1.01e308, signif(1.0055e308, 3)))
1955+
1956+
19521957

19531958
## keep at end
19541959
rbind(last = proc.time() - .pt,

0 commit comments

Comments
 (0)