Convert decimals to fractions in R
You can install the released version of fracture from CRAN with:
install.packages("fracture")
or the development version from GitHub with:
# install.packages("remotes")
::install_github("rossellhayes/fracture") remotes
fracture converts decimals into fractions.
fracture(0.5)
#> [1] 1/2
fracture((1:11) / 12)
#> [1] 1/12 1/6 1/4 1/3 5/12 1/2 7/12 2/3 3/4 5/6 11/12
fracture
sfracture
s are implemented using an S3 class. This means
we can perform mathematical operations on them like real fractions.
fracture(0.25) * 2
#> [1] 1/2
fracture(0.25) + fracture(1/6)
#> [1] 5/12
fracture
sfrac_style()
uses Unicode to provide stylish formatting
for inline fractions.
`r frac_style(pi, mixed = TRUE, max_denom = 500)`
3 ¹⁶/₁₁₃
Additional arguments help you get exactly the result you expect:
fracture((1:12) / 12, denom = 100)
#> [1] 8/100 17/100 25/100 33/100 42/100 50/100 58/100 67/100 75/100
#> [10] 83/100 92/100 100/100
fracture((1:12) / 12, common_denom = TRUE)
#> [1] 1/12 2/12 3/12 4/12 5/12 6/12 7/12 8/12 9/12 10/12 11/12 12/12
fracture(1 / (2:12), base_10 = TRUE)
#> [1] 5/10 3333333/10000000 25/100 2/10
#> [5] 1666667/10000000 1428571/10000000 125/1000 1111111/10000000
#> [9] 1/10 909091/10000000 833333/10000000
fracture(sqrt(1 / (1:12)), max_denom = 100)
#> [1] 1/1 70/99 56/97 1/2 17/38 20/49 31/82 35/99 1/3 6/19 19/63 28/97
fracture((1:9) / 3, mixed = TRUE)
#> [1] "1/3" "2/3" "1" "1 1/3" "1 2/3" "2" "2 1/3" "2 2/3" "3"
For more advanced work, you may prefer to work with a fraction matrix:
frac_mat((1:11) / 12)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
#> numerator 1 1 1 1 5 1 7 2 3 5 11
#> denominator 12 6 4 3 12 2 12 3 4 6 12
frac_mat()
accepts all the same arguments as
fracture()
.
When mixed fractions are used, frac_mat()
has three
rows:
frac_mat((1:9) / 3, mixed = TRUE, common_denom = TRUE)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> integer 0 0 1 1 1 2 2 2 3
#> numerator 1 2 0 1 2 0 1 2 0
#> denominator 3 3 3 3 3 3 3 3 3
Use fracture to find the best approximations of π for each maximum denominator.
unique(purrr::map_chr(1:50000, ~ fracture(pi, max_denom = .x)))
#> [1] "3/1" "6/2" "9/3" "12/4" "15/5"
#> [6] "18/6" "22/7" "333/106" "355/113" "103993/33102"
#> [11] "104348/33215"
Isn’t is interesting that there’s such a wide gap between ³⁵⁵/₁₁₃ and ¹⁰³⁹⁹³/₃₃₁₀₂?
fracture is implemented using optimized C++ with Rcpp and S3 methods.
This allows it to run faster than alternatives like MASS::fractions()
or fractional::fractional()
.*
# Performance with a single value
single_benchmark#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 print(fracture(x[1])) 1 1 1.47 1 1.50
#> 2 print(MASS::fractions(x[1])) 1.38 1.37 1.06 26.4 2.50
#> 3 print(fractional::fractional(x[1])) 1.29 1.40 1 18.3 1
# Performance with a vector of length 1000
vector_benchmark#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 print(fracture(x)) 1 1 2.37 1 1
#> 2 print(MASS::fractions(x)) 3.29 1.82 1.29 6.47 1.64
#> 3 print(fractional::fractional(x)) 4.25 2.26 1 1.66 1.57
* fractional()
does not compute a decimal’s fractional
equivalent until it is printed. Therefore, benchmarking the time to
print provides a fairer test of the three packages’ capabilities.
Hex sticker fonts are Source Sans and Hasklig.
Please note that fracture is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.