inline-r-0.7.0.0: tests/shootout/pidigits.R
# Constructors and string conversion functions
zero_mag = integer(0)
zero = c(0L, zero_mag) # ( = 0L )
one_mag = c(1L)
one = c(1L, one_mag)
ten_mag = c(10L)
ten = c(1L, ten_mag)
elem_max = 10000
elem_digits = as.integer(log10(elem_max))
signum <- function(v) v[[1]]
mag <- function(v) v[2:length(v)]
str_to_mag <- function(s) {
strip_leading_zeros <- function(s) {
for (i in 1:nchar(s))
if (substr(s, i, i) != '0')
return(substr(s, i, nchar(s)))
return("")
}
len = nchar(s <- strip_leading_zeros(s))
if (len == 0)
return(zero_mag)
mod <- len %% elem_digits
if (mod > 0) chunks <- substr(s, 1, mod)
else chunks <- character(0)
if (1 + mod < len) {
chunk_inds_begin <- seq(1 + mod, len, elem_digits)
chunk_inds_end <- chunk_inds_begin + elem_digits - 1
chunks <- c(chunks, substring(s, chunk_inds_begin, chunk_inds_end))
}
return(sapply(chunks, as.integer))
}
hi =
bigint <- function(s, i=NA) {
if (!is.na(i)) {
s <- as.character(i)
#x <- abs(i)
#sgn <- if (i < 0L) -1L else 1L
#while (i >= max_elem) {
#}
}
# } else {
if (substr(s, 1, 1) == '-') {
mag <- str_to_mag(substr(s, 2L, nchar(s)))
sgn <- -1L
} else {
mag <- str_to_mag(s)
sgn <- 1L
}
# }
return(c(if (length(mag)) sgn else 0L, mag))
}
to_int <- function(x) {
ret <- 0L
if ((x_len = length(x)) > 1L)
for (i in length(x):2)
ret <- ret * elem_max + x[[i]]
return(x[[1]] * ret)
}
mag_to_str <- function(x) {
len = length(x)
if (len == 1) return(as.character(x[[1]]))
xs <- sapply(x[2:length(x)], function(e) zeropad(e, 4))
x1 <- x[[1]]
return(paste(collapse="", sep="", c(
x[[1]],
sapply(x[2:length(x)], function(e) zeropad(e, elem_digits)))))
}
to_str <- function(x) {
if (x[[1]] == 0L)
return("0")
return(paste(sep="", if (x[[1]] < 0L) '-' else '', mag_to_str(mag(x))))
}
# Comparison functions
cmp_elem <- function(x, y) (x > y) - (x < y)
cmp_mag <- function(x, y) {
x_len = length(x)
y_len = length(y)
if (x_len < y_len) return(-1L)
if (x_len > y_len) return(1L)
for (i in 1:x_len)
if (c <- cmp_elem(x[[i]], y[[i]]))
return(c)
return(0L)
}
cmp <- function(x, y) {
x_sign = x[[1]]
y_sign = y[[1]]
if (x_sign == y_sign) {
if (x[[1]] == 1L) return(cmp_mag(mag(x), mag(y)))
if (x[[1]] == -1L) return(cmp_mag(mag(y), mag(x)))
return(0L)
}
return((x_sign > y_sign) - (x_sign < y_sign))
}
eq <- function(x, y) cmp(x, y) == 0L
ne <- function(x, y) cmp(x, y) != 0L
le <- function(x, y) cmp(x, y) <= 0L
lt <- function(x, y) cmp(x, y) < 0L
ge <- function(x, y) cmp(x, y) >= 0L
gt <- function(x, y) cmp(x, y) > 0L
# Arithmetic operations
add_mag <- function(x, y) {
# if x is shorter, swap the two vectors
if (length(x) < length(y)) {
tmp <- x; x <- y; y <- tmp
}
x_len = length(x)
y_len = length(y)
x_index <- x_len
y_index <- y_len
result <- integer(x_len)
sum <- 0L
# add common parts of both numbers
while (y_index > 0L) {
sum <- (x[[x_index]] %% elem_max + y[[y_index]] %% elem_max +
sum %/% elem_max) # TODO shift
result[[x_index]] <- sum %% elem_max
x_index <- x_index - 1L
y_index <- y_index - 1L
}
# copy remainder of the longer number while carry propagation is required
carry <- (sum >= elem_max)
while (x_index > 0L & carry) {
carry <- (result[[x_index]] <- x[[x_index]] + 1L) == 0L
x_index <- x_index - 1L
}
# copy remainder of the longer number
while (x_index > 0L) {
result[[x_index]] <- x[[x_index]]
x_index <- x_index - 1L
}
# grow result if necessary
if (carry)
return(c(0x01L, result))
return(result)
}
add <- function(x, y) {
if (y[[1]] == 0L)
return(x)
if (x[[1]] == 0L)
return(y)
if (x[[1]] == y[[1]])
return(c(x[[1]], add_mag(mag(x), mag(y))))
c <- cmp_mag(mag(x), mag(y))
if (c == 0L)
return(zero)
if (c > 0L)
result_mag <- sub_mag(mag(x), mag(y))
else
result_mag <- sub_mag(mag(y), mag(x))
return(c(sign_prod(c, x[[1]]),
strip_leading_zero_elems(result_mag)))
}
sub_mag <- function(big, little) {
big_len = length(big)
little_len = length(little)
result <- integer(big_len)
big_index <- big_len
little_index <- little_len
difference <- 0L
# subtract common parts of both numbers
while (little_index > 0L) {
difference <- (big[[big_index]] - little[[little_index]] +
if (difference < 0L) -1L else 0L)
result[[big_index]] <- difference %% elem_max
big_index <- big_index - 1L
little_index <- little_index - 1L
}
# subtract remainder of longer number while borrow propagates
borrow <- if (difference < 0L) -1 else 0L
while (big_index > 0L && borrow) {
borrow <- (result[[big_index]] <- big[[big_index]] - 1L) == -1L
big_index <- big_index - 1L
}
# copy remainder of the longer number
while (big_index > 0L) {
result[[big_index]] <- big[[big_index]]
big_index <- big_index - 1L
}
return(result)
}
sub <- function(x, y) {
if (y[[1]] == 0L)
return(x)
if (x[[1]] == 0L)
return(negate(y))
if (x[[1]] != y[[1]])
return(c(x[[1]], add_mag(mag(x), mag(y))))
c <- cmp_mag(mag(x), mag(y))
if (c == 0L)
return(zero)
if (c > 0L)
result_mag <- sub_mag(mag(x), mag(y))
else
result_mag <- sub_mag(mag(y), mag(x))
return(c(sign_prod(c, x[[1]]),
strip_leading_zero_elems(result_mag)))
}
negate <- function(x) c(-x[[1]], x[2:length(x)])
multiply_mag <- function(x, y) {
x_len = length(x)
y_len = length(y)
x_start = x_len # remove
y_start = y_len # remove
c <- integer(x_len + y_len)
carry <- 0L
k <- y_start + x_start
for (j in seq(y_start, 1L, -1L)) {
product = y[[j]] * x[[x_start]] + carry
c[k] <- product %% elem_max
carry <- product %/% elem_max
k <- k - 1L
}
c[x_start] <- carry
if (x_len <= 1)
return(c)
for (i in seq(x_start - 1L, 1L, -1L)) {
carry <- 0
k <- y_start + i
for (j in seq(y_start, 1L, -1L)) {
product = y[[j]] * x[[i]] + c[[k]] + carry
c[[k]] <- product %% elem_max
carry <- product %/% elem_max
k <- k - 1L
}
c[[i]] <- carry %% elem_max
}
return(c)
}
mul <- function(x, y) {
if (y[[1]] == 0L || x[[1]] == 0)
return(zero)
return(c(sign_prod(x[[1]], y[[1]]),
strip_leading_zero_elems(multiply_mag(mag(x), mag(y)))))
}
div_mag <- function(x_mag, y_mag) {
if (length(y_mag) == 1L && y_mag == one_mag)
return(x_mag)
x <- c(1L, x_mag)
y <- c(1L, y_mag)
x_mag_log10 = log10_mag(x_mag); y_mag_log10 = log10_mag(y_mag)
lo_log10 = x_mag_log10 - y_mag_log10 - (x_mag_log10 != y_mag_log10)
hi_log10 <- x_mag_log10 - y_mag_log10 + 1L
lo <- bigint_pow10(lo_log10)
# try pruning hi > 10 or lo <= 10
if (lo_log10 == 0L && hi_log10 > 1L) {
lo10 = mul(lo, ten)
if (gt(mul(lo10, y), x))
hi <- lo10
else {
lo <- lo10
hi <- bigint_pow10(hi_log10)
}
} else
hi <- bigint_pow10(hi_log10)
while (lt(lo, hi)) {
mid <- div2(add(add(lo, hi), one))
if (le(mul(mid, y), x))
lo <- mid
else
hi <- sub(mid, one)
}
return(mag(lo))
}
div <- function(x, y) {
# check if division by zero
if (x[[1]] == 0L)
return(zero)
c <- cmp_mag(mag(x), mag(y))
if (c == 0L)
return(one)
if (c < 0L)
return(zero)
return(c(sign_prod(x[[1]], y[[1]]), div_mag(mag(x), mag(y))))
}
# Helper arithmetic functions
div2_mag <- function(x) {
x_len <- length(x)
if (x_len == 1L)
return(x %/% 2L)
borrow <- (x[[1]] == 1)
x_start <- borrow + 1L
x_end <- x_len
result_index <- 1L
result <- integer(x_end - x_start + 1L)
for (x_index in x_start:x_end) {
d = x[[x_index]] + elem_max * borrow
result[[result_index]] <- d %/% 2
borrow <- d %% 2
result_index <- result_index + 1L
}
return(result)
}
div2 <- function(x) {
if (x[[1]] == 0L || (length(x) == 2L && x[[2]] == 1L))
return(zero)
return(c(x[[1]], div2_mag(mag(x))))
}
log10_mag <- function(m) elem_digits * (length(m) - 1L) + as.integer(log(m[[1]], 10))
bigint_pow10 <- function(n) c(1L, as.integer(10^(n %% elem_digits)), rep.int(0L, n %/% elem_digits))
# Misc functions
sign_prod <- function(x, y) (x == y) - (x != y)
strip_leading_zero_elems <- function(x) {
for (i in 1:length(x))
if (x[[i]] != 0L)
return(x[i:length(x)])
return(zero_mag)
}
zeropad <- function(s, n)
paste(sep="", paste(collapse="", rep('0', max(0L, n - nchar(s)))), s)
# PIDIGITS program
pidigits <- function(args) {
N = if (length(args)) as.integer(args[[1]]) else 100L
ONE = one
TWO = bigint("2")
TEN = bigint("10")
THREE = add(ONE, TWO)
i <- k <- ns <- 0L
k1 <- 1L
a <- t <- u <- bigint("0")
n <- d <- bigint("1")
while (TRUE) {
k <- k + 1L
t <- mul(n, TWO)
n <- mul(n, bigint(k))
a <- add(a, t)
k1 <- k1 + 2L
k1_big <- bigint(i=k1)
a <- mul(a, k1_big)
d <- mul(d, k1_big)
if (ge(a, n)) {
n3a <- add(mul(n, THREE), a)
t <- div(n3a, d)
td = mul(t, d)
u <- add(sub(n3a, td), n)
if (gt(d, u)) {
ns <- ns * 10L + to_int(t)
i <- i + 1L
if (i %% 5L == 0L) {
cat(zeropad(as.character(ns), 5))
if (i %% 2L == 0L)
cat(sep="", "\t:", i, "\n")
ns = 0L
}
if (i >= N)
break
a <- sub(a, td) # TODO use td
a <- mul(a, TEN)
n <- mul(n, TEN)
}
}
}
}
if (!exists("i_am_wrapper"))
pidigits(commandArgs(trailingOnly=TRUE))