Just to consolidate all comments and answers into one ready-to-use solution that also considers different countries (locales) and NA
I post this as an answer (please give credits to @Imo, @Gregor et al.).
Edit (Feb 09, 2017): Added the SQL.precision
as return value since it may be different from the mathematical precision.
#' Calculates the biggest precision and scale that occurs in a numeric vector
#'
#' The scale of a numeric is the count of decimal digits in the fractional part (to the right of the decimal point).
#' The precision of a numeric is the total count of significant digits in the whole number,
#' that is, the number of digits to both sides of the decimal point.
#'
#' To create a suitable numeric data type in a SQL data base use the returned \code{SQL.precision} which
#' is defined by \code{max(precision, non.fractional.precision + scale)}.
#'
#' @param x numeric vector
#'
#' @return A list with four elements:
#' precision (total number of significant digits in the whole number),
#' scale (number of digits in the fractional part),
#' non.fractional.precision (number of digits at the left side and SQL precision.
#'
#' @details NA will be counted as precision 1 and scale 0!
#'
#' @examples
#'
#' \preformatted{
#' x <- c(0, 7654321, 54321.1234, 321.123, 321.123456789, 54321.1234, 100000000000, 1E4, NA)
#' numeric.precision.and.scale(x)
#' numeric.precision.and.scale(c(10.0, 1.2)) # shows why the SQL.precision is different
#' }
numeric.precision.and.scale <- function(x) {
# Remember current options
old.scipen <- getOption("scipen")
# Overwrite options
options(scipen = 999) # avoid scientific notation when converting numerics to strings
# Extract the decimal point character of the computer's current locale
decimal.sign <- substr( 1 / 2, 2, 2)
x.string <- as.character(x[!is.na(x)])
if (length(x.string) > 0) {
# calculate
precision <- max(nchar(sub(decimal.sign, "", x.string, fixed = TRUE)))
scale <- max(nchar(sub(paste0("\\d+\\", decimal.sign, "?(.*)$"), "\\1", x.string)))
non.fractional.precision <- max(trunc(log10(abs(x))) + 1, na.rm = TRUE)
SQL.precision <- max(precision, non.fractional.precision + scale)
# Reset changed options
options(scipen = old.scipen)
} else {
precision <- 1
scale <- 0
non.fractional.precision <- 1
SQL.precision <- 1
}
return(list(precision = precision,
scale = scale,
non.fractional.precision = non.fractional.precision,
SQL.precision = SQL.precision))
}