7

When calculating a proportion (0 < x < 1) I am looking to convert that result x into it's nearest 1/r form, so that for example for

x = 0.30 is converted into 1/3

whereas for

x = 0.29 is converted into 1/4

I have been trying different ideas using round() and fractions() from MASS with little success.

What would be your most simple solution in R that could make this work?

neilfws
  • 32,751
  • 5
  • 50
  • 63
Sergio Henriques
  • 135
  • 1
  • 1
  • 6
  • 5
    Perhaps I'm missing something but why is 0.29 converted to 1/4 and not 1/3? – Maurits Evers Sep 09 '19 at 22:20
  • 2
    why not just `round(1/x)` or perhaps `ceiling(1/x)`? It would help if you showed what you did and explained how it didn't work. – John Coleman Sep 09 '19 at 22:21
  • Hi @MauritsEvers, the conversion would be because 0.29 is closer to 0.25 (1/4) than it is to 0.333 (1/3). – Sergio Henriques Sep 09 '19 at 22:49
  • Hi @JohnColeman, besides failing to use rounding x and fractions(). I also tried something along the lines of listing many of the known values frac = c(1,0.5,0.3333333,0.25,0.2,0.1666667, 0.1428571, 0.125, 0.1111111, 0.1) and min(x - frac) which sort of works, but only for these values and it's pretty clunky – Sergio Henriques Sep 09 '19 at 22:58
  • Not the same, but related - https://stackoverflow.com/questions/5046026/print-number-as-reduced-fraction-in-r – thelatemail Sep 09 '19 at 23:08

2 Answers2

2
findR <- function(x){
    possibles <- 1/seq(1:100)
    diffs <- abs(x - possibles)
    1/possibles[which.min(diffs)]}


df <- data.frame(x = seq(.1, .3, .01))
df$r <- sapply(df$x, findR)

      x  r
1  0.10 10
2  0.11  9
3  0.12  8
4  0.13  8
5  0.14  7
6  0.15  7
7  0.16  6
8  0.17  6
9  0.18  6
10 0.19  5
11 0.20  5
12 0.21  5
13 0.22  5
14 0.23  4
15 0.24  4
16 0.25  4
17 0.26  4
18 0.27  4
19 0.28  4
20 0.29  4
21 0.30  3
Bill O'Brien
  • 862
  • 5
  • 14
2

The following might do what you want, returning either the ceiling or the floor of the reciprocal (whichever gives a better result):

f <- function(x) ifelse(abs(1/floor(1/x) - x) < abs(1/ceiling(1/x) - x),floor(1/x),ceiling(1/x))
John Coleman
  • 51,337
  • 7
  • 54
  • 119