blob: cf55c24c3f29a4472967772297d2a4f22cc6e121 [file] [log] [blame]
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka
* Copyright (C) 1997-2018 R Core Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.R-project.org/Licenses/
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Rinternals.h>
#include <math.h>
#include <limits.h> /* INT_MAX */
#include <stdlib.h> /* abs */
#include <Rmath.h> /* for imin2 and imax2 */
#include <R_ext/Print.h> /* for Rprintf */
#include <R_ext/Utils.h> /* for R_rsort */
#include <R_ext/Error.h>
#include <R_ext/Arith.h> /* for R_FINITE */
#ifdef ENABLE_NLS
#include <libintl.h>
#define _(String) dgettext ("graphics", String)
#else
#define _(String) (String)
#endif
static void stem_print(int close, int dist, int ndigits)
{
if((close/10 == 0) && (dist < 0))
Rprintf(" %*s | ", ndigits, "-0");
else
Rprintf(" %*d | ", ndigits, close/10);
}
static Rboolean
stem_leaf(double *x, int n, double scale, int width, double atom)
{
double r, c, x1, x2;
double mu, lo, hi;
int mm, k, i, j, xi;
int ldigits, hdigits, ndigits, pdigits;
R_rsort(x,n);
if(n <= 1)
return FALSE;
Rprintf("\n");
mu = 10;
if(x[n-1] > x[0]) {
r = atom + (x[n-1] - x[0])/scale;
// this needs to be exact: exp10 in glibc is not accurate
c = R_pow_di(10.0, (int)(1.0 - floor(log10(r))));
mm = imin2(2, imax2(0, (int)(r*c/25)));
k = 3*mm + 2 - 150/(n + 50);
if ((k-1)*(k-2)*(k-5) == 0)
c *= 10.;
/* need to ensure that x[i]*c does not integer overflow */
x1 = fabs(x[0]); x2 = fabs(x[n-1]);
if(x2 > x1) x1 = x2;
while(x1*c > INT_MAX) c /= 10;
if (k*(k-4)*(k-8) == 0) mu = 5;
if ((k-1)*(k-5)*(k-6) == 0) mu = 20;
} else {
r = atom + fabs(x[0])/scale;
c = R_pow_di(10.0, (int)(1.0 - floor(log10(r))));
}
/* Find the print width of the stem. */
lo = floor(x[0]*c/mu)*mu;
hi = floor(x[n-1]*c/mu)*mu;
ldigits = (lo < 0) ? (int) floor(log10(-(double)lo)) + 1 : 0;
hdigits = (hi > 0) ? (int) floor(log10((double)hi)): 0;
ndigits = (ldigits < hdigits) ? hdigits : ldigits;
/* Starting cell */
if(lo < 0 && floor(x[0]*c) == lo) lo = lo - mu;
hi = lo + mu;
if(floor(x[0]*c+0.5) > hi) {
lo = hi;
hi = lo + mu;
}
/* Print out the info about the decimal place */
pdigits = 1 - (int) floor(log10(c) + 0.5);
Rprintf(" The decimal point is ");
if(pdigits == 0)
Rprintf("at the |\n\n");
else
Rprintf("%d digit(s) to the %s of the |\n\n",abs(pdigits),
(pdigits > 0) ? "right" : "left");
i = 0;
do {
if(lo < 0)
stem_print((int)hi, (int)lo, ndigits);
else
stem_print((int)lo, (int)hi, ndigits);
j = 0;
do {
if(x[i] < 0)xi = (int) (x[i]*c - .5);
else xi = (int) (x[i]*c + .5);
if( (hi == 0 && x[i] >= 0)||
(lo < 0 && xi > hi) ||
(lo >= 0 && xi >= hi) )
break;
j++;
if(j <= width-12)
Rprintf("%1d", abs(xi) % 10);
i++;
} while(i < n);
if(j > width)
Rprintf("+%d", j - width);
Rprintf("\n");
if(i >= n)
break;
hi += mu;
lo += mu;
} while(1);
Rprintf("\n");
return TRUE;
}
/* The R wrapper has removed NAs from x */
SEXP C_StemLeaf(SEXP x, SEXP scale, SEXP swidth, SEXP atom)
{
if(TYPEOF(x) != REALSXP || TYPEOF(scale) != REALSXP) error("invalid input");
#ifdef LONG_VECTOR_SUPPORT
if (IS_LONG_VEC(x))
error(_("long vector '%s' is not supported"), "x");
#endif
int width = asInteger(swidth), n = LENGTH(x);
if (n == NA_INTEGER) error(_("invalid '%s' argument"), "x");
if (width == NA_INTEGER) error(_("invalid '%s' argument"), "width");
double sc = asReal(scale), sa = asReal(atom);
if (!R_FINITE(sc)) error(_("invalid '%s' argument"), "scale");
if (!R_FINITE(sa)) error(_("invalid '%s' argument"), "atom");
stem_leaf(REAL(x), n, sc, width, sa);
return R_NilValue;
}
/* Formerly a version in src/appl/binning.c */
#include <string.h> // for memset
static void
C_bincount(double *x, R_xlen_t n, double *breaks, R_xlen_t nb, int *count,
int right, int include_border)
{
R_xlen_t i, lo, hi, nb1 = nb - 1, new;
// for(i = 0; i < nb1; i++) count[i] = 0;
memset(count, 0, nb1 * sizeof(int));
for(i = 0 ; i < n ; i++)
if(R_FINITE(x[i])) { // left in as a precaution
lo = 0;
hi = nb1;
if(breaks[lo] <= x[i] &&
(x[i] < breaks[hi] || (x[i] == breaks[hi] && include_border))) {
while(hi-lo >= 2) {
new = (hi+lo)/2;
if(x[i] > breaks[new] || (!right && x[i] == breaks[new]))
lo = new;
else
hi = new;
}
#ifdef LONG_VECTOR_SUPPORT
if(count[lo] >= INT_MAX)
error("count for a bin exceeds INT_MAX");
#endif
count[lo]++;
}
}
}
/* The R wrapper removed non-finite values */
SEXP C_BinCount(SEXP x, SEXP breaks, SEXP right, SEXP lowest)
{
x = PROTECT(coerceVector(x, REALSXP));
breaks = PROTECT(coerceVector(breaks, REALSXP));
R_xlen_t n = XLENGTH(x), nB = XLENGTH(breaks);
int sr = asLogical(right), sl = asLogical(lowest);
if (sr == NA_INTEGER) error(_("invalid '%s' argument"), "right");
if (sl == NA_INTEGER) error(_("invalid '%s' argument"), "include.lowest");
SEXP counts = PROTECT(allocVector(INTSXP, nB - 1));
C_bincount(REAL(x), n, REAL(breaks), nB, INTEGER(counts), sr, sl);
UNPROTECT(3);
return counts;
}