Convert a decimal number to a fraction / rational number

前端 未结 11 1785
情歌与酒
情歌与酒 2020-12-01 16:36

In JavaScript, is there any way to convert a decimal number (such as 0.0002) to a fraction represented as a string (such as \"2/10000\")?

I

相关标签:
11条回答
  • 2020-12-01 16:54

    I did what popnoodles suggested and here it is

    function FractionFormatter(value) {
      if (value == undefined || value == null || isNaN(value))
        return "";
    
      function _FractionFormatterHighestCommonFactor(u, v) {
          var U = u, V = v
          while (true) {
            if (!(U %= V)) return V
            if (!(V %= U)) return U
          }
      }
    
      var parts = value.toString().split('.');
      if (parts.length == 1)
        return parts;
      else if (parts.length == 2) {
        var wholeNum = parts[0];
        var decimal = parts[1];
        var denom = Math.pow(10, decimal.length);
        var factor = _FractionFormatterHighestCommonFactor(decimal, denom)
        return (wholeNum == '0' ? '' : (wholeNum + " ")) + (decimal / factor) + '/' + (denom / factor);
      } else {
        return "";
      }
    }
    
    0 讨论(0)
  • 2020-12-01 16:58

    I know this is an old question, but I have created a function that has been greatly simplified.

    Math.fraction=function(x){
    return x?+x?x.toString().includes(".")?x.toString().replace(".","")/(function(a,b){return b?arguments.callee(b,a%b):a;})(x.toString().replace(".",""),"1"+"0".repeat(x.toString().split(".")[1].length))+"/"+("1"+"0".repeat(x.toString().split(".")[1].length))/(function(a,b){return b?arguments.callee(b,a%b):a;})(x.toString().replace(".",""),"1"+"0".repeat(x.toString().split(".")[1].length)):x+"/1":NaN:void 0;
    }
    

    Call it with Math.fraction(2.56)

    It will:

    • return NaN if the input is not a number
    • return undefined if the input is undefined
    • reduce the fraction
    • return a string (use Math.fraction(2.56).split("/") for an array containing the numerator and denominator)

    Please note that this uses the deprecated arguments.callee, and thus may be incompatible in some browsers.

    Test it here

    0 讨论(0)
  • 2020-12-01 17:00

    Have tried something like this?

    <script type="texrt/javascript>
    var cnum = 3.5,deno = 10000,neww;
    neww = cnum * deno;
    while(!(neww % 2 > 0) && !(deno % 2 > 0)){
        neww = neww / 2;
        deno = deno / 2;
    }
    while(!(neww % 3 > 0) && !(deno % 3 > 0)){
        neww = neww / 3;
        deno = deno / 3;
    }
    while(!(neww % 5 > 0) && !(deno % 5 > 0)){
        neww = neww / 5;
        deno = deno / 5;
    }
    while(!(neww % 7 > 0) && !(deno % 7 > 0)){
        neww = neww / 7;
        deno = deno / 7;
    }
    while(!(neww % 11 > 0) && !(deno % 11 > 0)){
        neww = neww / 11;
        deno = deno / 11;
    }
    while(!(neww % 13 > 0) && !(deno % 13 > 0)){
        neww = neww / 13;
        deno = deno / 13;
    }
    while(!(neww % 17 > 0) && !(deno % 17 > 0)){
        neww = neww / 17;
        deno = deno / 17;
    }
    while(!(neww % 19 > 0) && !(deno % 19 > 0)){
        neww = neww / 19;
        deno = deno / 19;
    }
    console.log(neww+"/"+deno);
    </script>
    
    0 讨论(0)
  • 2020-12-01 17:01

    A little googling with the term "decimal to fraction js" the first yielded this:

    http://wildreason.com/wildreason-blog/2010/javascript-convert-a-decimal-into-a-simplified-fraction/

    It seems to work:

    http://jsfiddle.net/VKfHH/

    function HCF(u, v) { 
        var U = u, V = v
        while (true) {
            if (!(U%=V)) return V
            if (!(V%=U)) return U 
        } 
    }
    //convert a decimal into a fraction
    function fraction(decimal){
    
        if(!decimal){
            decimal=this;
        }
        whole = String(decimal).split('.')[0];
        decimal = parseFloat("."+String(decimal).split('.')[1]);
        num = "1";
        for(z=0; z<String(decimal).length-2; z++){
            num += "0";
        }
        decimal = decimal*num;
        num = parseInt(num);
        for(z=2; z<decimal+1; z++){
            if(decimal%z==0 && num%z==0){
                decimal = decimal/z;
                num = num/z;
                z=2;
            }
        }
        //if format of fraction is xx/xxx
        if (decimal.toString().length == 2 && 
                num.toString().length == 3) {
                    //reduce by removing trailing 0's
            decimal = Math.round(Math.round(decimal)/10);
            num = Math.round(Math.round(num)/10);
        }
        //if format of fraction is xx/xx
        else if (decimal.toString().length == 2 && 
                num.toString().length == 2) {
            decimal = Math.round(decimal/10);
            num = Math.round(num/10);
        }
        //get highest common factor to simplify
        var t = HCF(decimal, num);
    
        //return the fraction after simplifying it
        return ((whole==0)?"" : whole+" ")+decimal/t+"/"+num/t;
    }
    
    // Test it
    alert(fraction(0.0002)); // "1/5000"
    
    0 讨论(0)
  • 2020-12-01 17:01

    There is a very simple solution using string representation of numbers

        string = function(f){ // returns string representation of an object or number
            return f+"";
        }
        fPart = function(f){ // returns the fraction part (the part after the '.') of a number
            str = string(f);
            return str.indexOf(".")<0?"0":str.substring(str.indexOf(".") + 1);
        }
        wPart = function(f){ // returns the integer part (the part before the '.') of a number
            str = string(f);
            return str.indexOf(".")<0?str:str.substring(0, str.indexOf(".")); // possibility 1
            //return string(f - parseInt(fPart(f))); // just substract the fPart
        }
    
        power = function(base, exp){
            var tmp = base;
            while(exp>1){
                base*=tmp;
                --exp;
            }
            return base;
        }
    
        getFraction = function(f){ // the function
            var denominator = power(10, fPart(f).length), numerator = parseInt(fPart(f)) + parseInt(wPart(f))*denominator;
            return "[ " + numerator + ", " + denominator + "]";
        }
    
        console.log(getFraction(987.23));
    

    which will just check how many numbers are in the fraction and then expands the fraction of f/1 until f is an integer. This can lead to huge fractions, so you can reduce it by dividing both numerator and denominator by the greatest common divisor of both, e.g.

        // greatest common divisor brute force
        gcd = function(x,y){
            for(var i = Math.min(x, y);i>0;i--) if(!(x%i||y%i)) return i;
            return 1;
        }
    
    0 讨论(0)
  • 2020-12-01 17:07

    Very old question but maybe someone can find this useful. It's iterative, not recursive and doesn't require factorization

    function getClosestFraction(value, tol) {
        var original_value = value;
        var iteration = 0;
        var denominator=1, last_d = 0, numerator;
        while (iteration < 20) {
            value = 1 / (value - Math.floor(value))
            var _d = denominator;
            denominator = Math.floor(denominator * value + last_d);
            last_d = _d;
            numerator = Math.ceil(original_value * denominator)
    
            if (Math.abs(numerator/denominator - original_value) < tol)
                break;
            iteration++;
        }
        return {numerator: numerator, denominator: denominator};
    };
    
    0 讨论(0)
提交回复
热议问题