Print Number as Reduced Fraction in R

Print number as reduced fraction in R

fractions() in the MASS package does just that:

> library(MASS)
> fractions(.14)
[1] 7/50

Function in R to convert a decimal to a fraction with a specified denominator

Just in case you need to use a more simplified version of the above function

f = function(x, den) {paste0(round(x * den), "/", den)}
x <- c(0.55, 0.246, 0.767)
f(x, 10)

[1] "6/10" "2/10" "8/10"

How to format a number as percentage in R?

Even later:

As pointed out by @DzimitryM, percent() has been "retired" in favor of label_percent(), which is a synonym for the old percent_format() function.

label_percent() returns a function, so to use it, you need an extra pair of parentheses.

library(scales)
x <- c(-1, 0, 0.1, 0.555555, 1, 100)
label_percent()(x)
## [1] "-100%" "0%" "10%" "56%" "100%" "10 000%"

Customize this by adding arguments inside the first set of parentheses.

label_percent(big.mark = ",", suffix = " percent")(x)
## [1] "-100 percent" "0 percent" "10 percent"
## [4] "56 percent" "100 percent" "10,000 percent"

An update, several years later:

These days there is a percent function in the scales package, as documented in krlmlr's answer. Use that instead of my hand-rolled solution.


Try something like

percent <- function(x, digits = 2, format = "f", ...) {
paste0(formatC(100 * x, format = format, digits = digits, ...), "%")
}

With usage, e.g.,

x <- c(-1, 0, 0.1, 0.555555, 1, 100)
percent(x)

(If you prefer, change the format from "f" to "g".)

How to output fraction instead of decimal number?

You can't. You would need to write a class dedicated to holding rational numbers (i.e. fractions). Or maybe just use the Boost Rational Number library.

How to convert floats to human-readable fractions?

I have found David Eppstein's find rational approximation to given real number C code to be exactly what you are asking for. Its based on the theory of continued fractions and very fast and fairly compact.

I have used versions of this customized for specific numerator and denominator limits.

/*
** find rational approximation to given real number
** David Eppstein / UC Irvine / 8 Aug 1993
**
** With corrections from Arno Formella, May 2008
**
** usage: a.out r d
** r is real number to approx
** d is the maximum denominator allowed
**
** based on the theory of continued fractions
** if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...)))
** then best approximation is found by truncating this series
** (with some adjustments in the last term).
**
** Note the fraction can be recovered as the first column of the matrix
** ( a1 1 ) ( a2 1 ) ( a3 1 ) ...
** ( 1 0 ) ( 1 0 ) ( 1 0 )
** Instead of keeping the sequence of continued fraction terms,
** we just keep the last partial product of these matrices.
*/

#include <stdio.h>

main(ac, av)
int ac;
char ** av;
{
double atof();
int atoi();
void exit();

long m[2][2];
double x, startx;
long maxden;
long ai;

/* read command line arguments */
if (ac != 3) {
fprintf(stderr, "usage: %s r d\n",av[0]); // AF: argument missing
exit(1);
}
startx = x = atof(av[1]);
maxden = atoi(av[2]);

/* initialize matrix */
m[0][0] = m[1][1] = 1;
m[0][1] = m[1][0] = 0;

/* loop finding terms until denom gets too big */
while (m[1][0] * ( ai = (long)x ) + m[1][1] <= maxden) {
long t;
t = m[0][0] * ai + m[0][1];
m[0][1] = m[0][0];
m[0][0] = t;
t = m[1][0] * ai + m[1][1];
m[1][1] = m[1][0];
m[1][0] = t;
if(x==(double)ai) break; // AF: division by zero
x = 1/(x - (double) ai);
if(x>(double)0x7FFFFFFF) break; // AF: representation failure
}

/* now remaining x is between 0 and 1/ai */
/* approx as either 0 or 1/m where m is max that will fit in maxden */
/* first try zero */
printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
startx - ((double) m[0][0] / (double) m[1][0]));

/* now try other possibility */
ai = (maxden - m[1][1]) / m[1][0];
m[0][0] = m[0][0] * ai + m[0][1];
m[1][0] = m[1][0] * ai + m[1][1];
printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
startx - ((double) m[0][0] / (double) m[1][0]));
}

How would I make a new fraction if a fraction cannot be simplified?

  • Method decimal() in class Fraction is not used, so I removed it.
  • Rather than recursively call method getAGoodFraction() when the GCD value is 1, use a loop.
  • Rather than create a new Fraction object each time the randomly generated numerator is greater than the randomly generated denominator, use methods setNumerator() and setDenominator(). That's what they're for.
  • There is no need to call method simplify() in method getAGoodFraction(). Just return the fraction. Because the GCD is not equal to 1, you know it can be simplified.

Compare the following code with yours.

Note that I added a main() method to class Fraction so as to be able to run the code. And I also changed method gcd() due to the comment to your question from @KevinAnderson.

import java.util.Random;

public class Fraction {
private int numerator;
private int denominator;

public Fraction() {
this(0, 1);
}

public Fraction(int number) {
this(number, 1);
}

public Fraction(Fraction frac) {
this(frac.getNumerator(), frac.getDenominator());
}

public Fraction(int num, int denom) {
setNumerator(num);
setDenominator(denom);
}

public static int gcd(int m, int n) {
int factor = m;
int r = n % factor;
while (r != 0 && factor > 1) {
r = n % --factor;
if (r == 0) {
r = m % factor;
}
}
return factor;
}

public int getDenominator() {
return denominator;
}

public int getNumerator() {
return numerator;
}

public void setDenominator(int denom) {
if (denom == 0) {
System.err.println("Fatal Error");
System.exit(1);
}
denominator = denom;
}

public void setNumerator(int num) {
numerator = num;
}

public Fraction simplify() {
int num = getNumerator();
int denom = getDenominator();
int gcd = gcd(num, denom);

Fraction simp = new Fraction(num / gcd, denom / gcd);
return simp;
}

public String toString() {
return getNumerator() + "/" + getDenominator();
}

public static void main(String[] args) {
SimpleFracBoxes sfb = new SimpleFracBoxes(10);
sfb.makeTheFractions();
System.out.println(sfb.getFractions());
}
}

class SimpleFracBoxes {
private int numberOfFractions = 0;
private String result = "";
Random myRandom = new Random();
int min = 1;
int max = 100000;

public SimpleFracBoxes() {
}

public SimpleFracBoxes(int nOFracs) {
numberOfFractions = nOFracs;
}

//makes the fractions
public void makeTheFractions() {
for (int i = 0; i < numberOfFractions; i++) {
Fraction frac = getAGoodFraction();
Fraction frac2 = frac.simplify();
result += String.format("%" + String.valueOf(numberOfFractions).length() + "d. %5d/%5d simplifies to %5d/%5d%n",
(i + 1),
frac.getNumerator(),
frac.getDenominator(),
frac2.getNumerator(),
frac2.getDenominator());
}
}

// creates a fraction that can be divided
private Fraction getAGoodFraction() {
int gcd = 1;
Fraction frac = new Fraction();
while (gcd == 1) {
do {
frac.setNumerator(myRandom.nextInt(max - min));
frac.setDenominator(myRandom.nextInt(max - min));
} while (frac.getNumerator() >= frac.getDenominator());
int num = frac.getNumerator();
int denom = frac.getDenominator();
gcd = Fraction.gcd(num, denom);
}
return frac;
}

public String getFractions() {
return result;
}
}

Here is a sample output produced when running the above code.

 1. 64480/84728 simplifies to  8060/10591
2. 33376/79317 simplifies to 4768/11331
3. 50944/97026 simplifies to 25472/48513
4. 21339/45510 simplifies to 7113/15170
5. 35884/38628 simplifies to 8971/ 9657
6. 15148/17199 simplifies to 2164/ 2457
7. 72670/95005 simplifies to 14534/19001
8. 19810/44730 simplifies to 283/ 639
9. 61790/63956 simplifies to 30895/31978
10. 4824/ 5352 simplifies to 201/ 223


Related Topics



Leave a reply



Submit