The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
{friendlynumber} translates vectors of numbers into character vectors of English numerals (AKA number words). Supported numerals include:
{friendlynumber} functions are intended to be used internally by other packages (e.g. for generating friendly error messages). To this end, {friendlynumber} is written in base R and has no Imports.
Install the released version from CRAN with:
install.packages("friendlynumber")
You can install the development version of {friendlynumber} from GitHub with:
# install.packages("pak")
::pak("EthanSansom/friendlynumber") pak
library(friendlynumber)
number_friendly()
is an S3 generic which converts
numbers into cardinal numerals.
number_friendly(c(0:3, 2/3, 1/100, NA, NaN, Inf))
#> [1] "zero" "one" "two" "three"
#> [5] "two thirds" "one hundredth" "missing" "not a number"
#> [9] "infinity"
number_friendly()
defines methods for four number
classes included in base R
and the {bignum} package:
<integer>
and <numeric>
vectors<bignum_biginteger>
vectors, which can
store arbitrarily large integers<bignum_bigfloat>
vectors, which store
numbers with 50 decimal digits of precisionEach method has a corresponding standalone *_friendly()
function which expects a number of a specific class.
number_friendly(1L) # integerish_friendly()
#> [1] "one"
number_friendly(1.0) # numeric_friendly()
#> [1] "one"
number_friendly(bignum::biginteger(1L)) # biginteger_friendly()
#> [1] "one"
number_friendly(bignum::bigfloat(1.0)) # bigfloat_friendly()
#> [1] "one"
{friendlynumber} provides an additional set of functions for
translating whole numbers (e.g. 1L
or 1.00
)
into common numeral types.
# Ordinals
ordinal_friendly(0:4)
#> [1] "zeroth" "first" "second" "third" "fourth"
# Numeric Ordinals
nth_friendly(0:4)
#> [1] "0th" "1st" "2nd" "3rd" "4th"
# Counts
ntimes_friendly(0:4)
#> [1] "no times" "once" "twice" "three times" "four times"
# Quantifiers
quantifier_friendly(0:4)
#> [1] "no" "the" "both" "all three" "all four"
{friendlynumber} provides two options()
for setting the
number of decimals that {friendlynumber} functions report.
options(
friendlynumber.numeric.digits = 3, # Effects `<numeric>` numbers
friendlynumber.bigfloat.digits = 5 # Effects `<bignum_bigfloat>` numbers
)
numeric_friendly(0.12345)
#> [1] "one hundred twenty-three thousandths"
bigfloat_friendly(bignum::bigfloat(0.12345))
#> [1] "twelve thousand three hundred forty-five hundred-thousandths"
format_number()
is a utility function which formats
numbers via format()
and abides by these options.
format_number(0.12345)
#> [1] "0.123"
format_number(bignum::bigfloat(0.12345))
#> [1] "0.12345"
This is useful for verifying whether unexpected results are a consequence of precision issues. For instance, look what happens when we attempt to translate the number “ten billion and one hundred-thousandth”.
options(
friendlynumber.numeric.digits = 7,
friendlynumber.bigfloat.digits = 7
)
numeric_friendly(10000000000.00001)
#> [1] "ten billion and ninety-five ten-millionths"
bigfloat_friendly(bignum::bigfloat("10000000000.00001"))
#> [1] "ten billion and one hundred-thousandth"
We can use format_number()
to confirm that, on my
machine, a <numeric>
vector lacks the precision to
store this number accurately.
format_number(10000000000.00001)
#> [1] "10,000,000,000.0000095"
format_number(bignum::bigfloat("10000000000.00001"))
#> [1] "10,000,000,000.00001"
Similar problems can arise when working with whole numbers. Consider the number “ten quadrillion” minus one.
numeric_friendly(10000000000000000 - 1)
#> [1] "ten quadrillion"
biginteger_friendly(bignum::biginteger("10000000000000000") - 1L)
#> [1] "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"
{friendlynumber} is faster than other alternatives written in base R - such as the {english} and {nombre} packages.
# Scalar (small)
::mark(
benchenglish = as.character(english::english(1L)),
nombre = as.character(nombre::nom_card(1L)),
friendlynumber = as.character(number_friendly(1L))
1:6]
)[#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 english 89.54µs 92.95µs 10520. 140KB 33.9
#> 2 nombre 120.83µs 125.95µs 7666. 685KB 29.4
#> 3 friendlynumber 6.64µs 7.26µs 134666. 0B 40.4
# Scalar (large)
::mark(
benchenglish = as.character(english::english(100000)),
nombre = as.character(nombre::nom_card(100000)),
friendlynumber = as.character(number_friendly(100000))
1:6]
)[#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 english 174.3µs 179µs 5498. 8.26KB 27.2
#> 2 nombre 126.2µs 130.6µs 7468. 0B 31.7
#> 3 friendlynumber 34.7µs 36.2µs 27136. 0B 29.9
# Vector
::mark(
benchenglish = as.character(english::english(1:10000)),
nombre = as.character(nombre::nom_card(1:10000)),
friendlynumber = as.character(number_friendly(1:10000)),
filter_gc = FALSE
1:6]
)[#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 english 1.24s 1.24s 0.804 2.34MB 12.1
#> 2 nombre 45.4ms 47.82ms 20.8 11.43MB 11.4
#> 3 friendlynumber 8.91ms 9.2ms 105. 3.87MB 7.89
To increase the speed of processing scalar inputs, the set of
*_friendly()
functions do not check that their arguments
are of valid types. All *_friendly()
functions have a
slightly slower *_friendly_safe()
alternative which
confirms that it’s arguments are of the correct type and emits an
informative error otherwise.
try(integerish_friendly_safe(numbers = 1/2))
#> Error : `numbers` must be coercible to an integer without loss of precision.
When used with the {bignum} package, {friendlynumber} is capable of translating extremely large numbers into cardinal numerals. Here, we translate a number equal to 1 followed by three thousand and three 0’s.
number_friendly(bignum::biginteger(10L)^3003L)
#> [1] "one millinillion"
This package was originally inspired by the {english} package by John Fox, Bill Venables, Anthony Damico and Anne Pier Salverda, which inspired my fixation with the problem of converting numbers to numerals.
Several functions in {friendlynumber} were inspired by Alexander Rossell Hayes’ {nombre} package:
ntimes_friendly()
is based on nombre::adverbial()quantifier_friendly()
is based on nombre::collective()The following sources were very helpful for naming extremely large numbers:
number_friendly()
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.