7
\$\begingroup\$

This code below converts number from decimal to fraction. I don't know if there's a better way or better methods to do this job so any advice would be appreciated.

const toFraction = (inputNumber) => {
  // Only two digits after decimal point
  inputNumber = inputNumber.toFixed(2);

  // destructure number
  let [int, dec] = inputNumber
    .toString()
    .split(".")
    .map((el) => parseInt(el));

  // Round it up to nearst multiple of 5
  dec = Math.ceil(dec / 5) * 5;

  // Keep Dividing until it's impossible
  const divide = [9, 8, 7, 6, 5, 4, 3, 2];
  let hundred = 100;
  let notOver = true;
  while (notOver) {
    notOver = false;
    for (let num of divide) {
      if (dec % num === 0 && hundred % num === 0) {
        dec /= num;
        hundred /= num;
        notOver = true;
      }
    }
  }
  return int === 0 ? `${dec}${hundred}` : `${int} ${dec}/${hundred}`;
};
\$\endgroup\$
  • \$\begingroup\$ Why limit it to 2 decimal places? \$\endgroup\$ – Mohsen Alyafei Aug 9 at 14:58
  • \$\begingroup\$ I have used it in a project that only needs two decimal points but you're right. I'll edit it to cover more digits \$\endgroup\$ – user3756068 Aug 9 at 15:03
  • 1
    \$\begingroup\$ I suggest that you also add few test cases; with "console.log" outputs. \$\endgroup\$ – Mohsen Alyafei Aug 9 at 15:08
  • 1
    \$\begingroup\$ Great. You had my upvote. \$\endgroup\$ – Mohsen Alyafei Aug 9 at 15:41
  • 1
    \$\begingroup\$ Please don't change or add to the code in your question after you have received answers. This makes it hard to understand the answers with respect to the version of code that they are referring to. You can put the improvements in a new follow-up question instead. See What should I do when someone answers my question? \$\endgroup\$ – L. F. Aug 10 at 4:42
7
\$\begingroup\$

You can remove the toString() bit from here:

  let [int, dec] = inputNumber
    .toString()
    .split(".")
    .map((el) => parseInt(el));

toFixed returns a string. So, there is no need to call toString again.


The calculation part:

If the decimal part is 12, your output is 3/25. How do you get this? You get the greatest common divisor between 12 and 100 and divide both of them with it. GCD of 12 and 100 is 4. So, (12/4) / (100/4)

There's already a simple recursive implementation of euclidean algorithm for that:

function gcd(a, b)
    if b = 0
        return a
    else
        return gcd(b, a mod b)

You can get the precision required as an option parameter which defaults to a predefined MAX_PRECISION. Get the GCD between the dec and 10 precision (eg: 100 for precision = 2)

const MAX_PRECISION = 5

function toFraction(inputNumber, precision = MAX_PRECISION) {
  let [int, dec] = inputNumber
                      .toFixed(precision)
                      .split(".")
                      .map(n => +n)
                      
  const powerOf10 = 10 ** precision,
        gcd = getGCD(dec, powerOf10),
        fraction = `${dec/gcd}/${powerOf10/gcd}`;
  
  return int ? `${int} ${fraction}` : fraction
};

function getGCD(a, b) {
  if (!b) return a;

  return getGCD(b, a % b);
};

console.log( toFraction(1.14)   );
console.log( toFraction(5.71)   );
console.log( toFraction(3.34)   );
console.log( toFraction(5.1044) );
console.log( toFraction(0.67)   );
console.log( toFraction(0.84)   );

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for your great solution. Actually i round the number to nearest multiple of 5 so 0.12 becomes 0.15 and it's get divided by 5 and result become 3/20 \$\endgroup\$ – user3756068 Aug 9 at 15:28
  • \$\begingroup\$ @user3756068 Is it required to round it to nearest multiple of 5? You can still add that part to the code. \$\endgroup\$ – adiga Aug 9 at 15:35
  • 1
    \$\begingroup\$ I'm using this code for a food recipe ingredients to calculate amount of the unit. It can be more precise but in this case it's not required. \$\endgroup\$ – user3756068 Aug 9 at 15:43
  • \$\begingroup\$ The above information that the code is used in a food recipe should have gone into the question instead. It's important to have these details in the description since then we can decide whether the precision is good enough. \$\endgroup\$ – Roland Illig Aug 10 at 6:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.