Commit d23b0086 authored by Martin Maechler's avatar Martin Maechler
Browse files

base round.bigq() on new roundQ() wch can change default r0=round0

parent 8ccb020c
2020-07-23 Martin Maechler <maechler@stat.math.ethz.ch>
* R/bigq.R (round, round0, roundQ): round0(): "round to even"; make
'round0()' the default argument to 'round(x, digits)'.
2020-06-12 Martin Maechler <maechler@stat.math.ethz.ch>
* R/biginteger.R (c_bigz): export, to be used, e.g.,
......
Package: gmp
Version: 0.6-1
Date: 2020-07-04
Date: 2020-07-24
Title: Multiple Precision Arithmetic
Author: Antoine Lucas, Immanuel Scholz, Rainer Boehme <rb-gmp@reflex-studio.de>,
Sylvain Jasson <Sylvain.Jasson@inrae.fr>,
......@@ -11,7 +11,7 @@ Description: Multiple Precision Arithmetic (big integers and rationals,
using the C library GMP (GNU Multiple Precision Arithmetic).
Depends: R (>= 3.5.0)
Imports: methods
Suggests: Rmpfr, MASS
Suggests: Rmpfr, MASS, round
SystemRequirements: gmp (>= 4.2.3)
License: GPL (>= 2)
BuildResaveData: no
......
......@@ -56,6 +56,7 @@ export(
## "prod", "prod.default",
"prod.bigq", "prod.bigz",
"rep.bigq", "rep.bigz",
round0, roundQ, # (x, digits, round0)
## "sign.bigq", "sign.bigz",
"sizeinbase",
"solve.bigq", "solve.bigz",
......
......@@ -60,13 +60,14 @@ div.bigz <- function(e1, e2) {
"%%.bigz" <- mod.bigz <- function(e1, e2) {
if(inherits(e2, "bigq")) {
if(!all(is.whole(e2[is.finite(e2)])))
if(!all(is.whole.bigq(e2[is.finite(e2)])))
e2 <- as.bigz(e2)
else
stop("In 'n %% d', d must be integer")
}
.Call(biginteger_mod, e1, e2)
}
.mod.bigz <- function(e1, e2) .Call(biginteger_mod, e1, e2)
pow.bigz <- function(e1, e2,...) {
if(inherits(e2, "bigq"))
......
......@@ -102,9 +102,9 @@ formatN.bigq <- function(x, ...) {
r
}
as.double.bigq<- function(x,...) .Call(bigrational_as_numeric, x)
as.double.bigq <- function(x,...) .Call(bigrational_as_numeric, x)
## maybe sub-optimal, but at least "R-consistent" in warnings/errors...:
as.integer.bigq<- function(x,...) as.integer(.Call(bigrational_as_numeric, x))
as.integer.bigq <- function(x,...) as.integer(.Call(bigrational_as_numeric, x))
.bigq2num <- function(x) {
## cat(".bigq2num():\n")
......@@ -205,19 +205,34 @@ trunc.bigq <- function(x, ...) ## := sign(x) * floor(abs(x)) =
sign.bigq(x) * as.bigz.bigq(abs.bigq(x))
floor.bigq <- function(x) as.bigz.bigq(x)
ceiling.bigq <- function(x) -as.bigz.bigq(-x)
round.bigq <- function(x, digits = 0) {
if(FALSE) ## this was used in round.bigq() for several months in 2020:
round0 <- function(x) as.bigz.bigq(x + as.bigq(1, 2))
##' rounding to integer a la "nearbyint()" -- i.e. "round to even"
round0 <- function(x) {
nU <- as.bigz.bigq(xU <- x + as.bigq(1, 2)) # traditional round: .5 rounded up
if(any(I <- is.whole.bigq(xU))) { # I <==> x == <n>.5 : "hard case"
I[I] <- .mod.bigz(nU[I], 2L) == 1L # rounded up is odd ==> round *down*
nU[I] <- nU[I] - 1L
}
nU
}
roundQ <- function(x, digits = 0, r0 = round0) {
## round(x * 10^d) / 10^d
bigq_half <- as.bigq(1, 2)
round0 <- function(x) as.bigz.bigq(x + bigq_half)
stopifnot(length(digits) == 1L)
if(digits == 0)
round0(x)
r0(x)
else {
p10 <- as.bigz(10) ^ digits # bigz iff digits >= 0, bigq otherwise
round0(x * p10) / p10
r0(x * p10) / p10
}
}
##' round() method ==> signature = (x, digits) {round0 *not* allowed as argument}
round.bigq <- function(x, digits = 0) roundQ(x, digits)
cumsum.bigq <- function(x) .Call(bigrational_cumsum, x)
## TODO: add cummax(), cummin(), cumprod()
......
* Remove full path in `configure.ac` script, with example of Rmpfr configure. -*-org-*-
* Bug Fixes
** TODO Logical ops should work: 0=FALSE NA=NA, <any_else>=TRUE
*** !as.bigz(0:3) crashes R badly (!!), but should return !(0:3) (logical vector).
terminate called after throwing an instance of 'std::length_error'
what(): vector::_M_default_append \\ ...R: line 141: 25400 Aborted (core dumped)
*** as.bigz(0:3) | as.bigz(0) etc should return logical as with regular numbers in R
** TODO `format()` currently works via as.character(.), particularly unsatisfying for bigz.
** TODO Not working column assignment : A[,j] <- vec does nothing, not warn, nothing -- but A[i,] <- val works ??
** TODO m <- matrix(1:6, 2); Z <- as.bigz(m); str(Z) fails because e.g. Z[5] fails, contrary m[5]
** TODO asNumeric(x) : the generic must get a "..." argument, so can use "rounding mode" in Rmpfr
......
\name{roundQ}
\title{Rounding Big Rationals ("bigq") to Decimals}
\alias{roundQ}
\alias{round0}
\alias{round.bigq}
\description{
Rounding big rationals (of class \code{"bigq"}, see \code{\link{as.bigq}()})
to decimal \code{digits} is strictly based on a (optionally choosable)
definition of rounding to integer, i.e., \code{digits = 0}, the default
method of which we provide as \code{round0()}.
The users typically just call \code{round(x, digits)} as elsewhere, and
the \code{round()} method will call \code{round(x, digits, round0=round0)}.
}
\usage{
round0(x)
roundQ(x, digits = 0, r0 = round0)
\S3method{round}{bigq}(x, digits = 0)
}
\arguments{
\item{x}{vector of big rationals, i.e., of \code{\link{class}} \code{"bigq"}.}
\item{digits}{integer number of decimal digits to round to.}
\item{r0}{a \code{\link{function}} of one argument which implements a
version of \code{\link{round}(x, digits=0)}. The default for
\code{roundQ()} is to use our \code{round0()} which implements
\dQuote{round to even}, as base \R's \code{\link{round}}.}
}
\value{
\code{round0()} returns a vector of big integers, i.e., \code{"bigz"} classed.
\code{roundQ(x, digits, round0)} returns a vector of big rationals,
\code{"bigq"}, as \code{x}.
\code{round.bigq} is very simply defined as
\code{function(x, digits) roundQ(x, digits)} .
}
\references{
The vignette \dQuote{\emph{Exact Decimal Rounding via Rationals}} from
CRAN package \CRANpkg{round},
% not yet
% \url{https://CRAN.R-project.org/package=round/vignettes/rationalRound.html}
Wikipedia, Rounding, notably "Round half to even":
\url{https://en.wikipedia.org/wiki/Rounding#Round_half_to_even}
}
\author{Martin Maechler, ETH Zurich}
\seealso{
\code{\link{round}} for (double precision) numbers in base \R;
\code{\link[round]{roundX}} from CRAN package \CRANpkg{round}.
}
\examples{
qq <- as.bigq((-21:31), 10)
noquote(cbind(as.character(qq), asNumeric(qq)))
round0(qq)
## corresponds to R's own "round to even" :
stopifnot(round0(qq) == round(asNumeric(qq)))
halfs <- as.bigq(1,2) + -5:12
\dontshow{q <- c(halfs, qq)
stopifnot(identical(round0(q),
round (q, 0))) ; rm(q)
}
\dontshow{if(FALSE)}
## round0() is simply
round0 <- function (x) {
nU <- as.bigz.bigq(xU <- x + as.bigq(1, 2)) # traditional round: .5 rounded up
if(any(I <- is.whole.bigq(xU))) { # I <==> x == <n>.5 : "hard case"
I[I] <- .mod.bigz(nU[I], 2L) == 1L # rounded up is odd ==> round *down*
nU[I] <- nU[I] - 1L
}
nU
}
## 's' for simple: rounding as you learned in school:
round0s <- function(x) as.bigz.bigq(x + as.bigq(1, 2))
cbind(halfs, round0s(halfs), round0(halfs))
\dontshow{if(FALSE)}
## roundQ() is also just
roundQ <- function(x, digits = 0, r0 = round0) {
## round(x * 10^d) / 10^d
if(digits == 0)
r0(x)
else {
p10 <- as.bigz(10) ^ digits # bigz iff digits >= 0, bigq otherwise
r0(x * p10) / p10
}
}
}
\keyword{arith}
\concept{Rounding}
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