将十进制数转换为javascript中的分数或最接近的分数

convert decimal number to fraction in javascript or closest fraction

本文关键字:最接近 十进制数 转换 javascript      更新时间:2023-09-26

所以我希望能够将任何十进制数转换为分数。在这两种形式中,如不带余数的:3/5或带余数的:3 1/4

我所做的是…

假设数字是。3435

  • 计算小数后的位数。
  • 乘以10,以数字前的金额为幂。
  • 然后以某种方式找到最大公因数。

现在我不知道如何找到GCF。如果精确分数不存在,我也不知道如何实现逻辑来找到接近表示数字的分数或以余数形式存在的分数。

(测试)
x = 34/35;
a = x - x.toFixed();
tens = (10).pow(a.toString().length - 2);
numerator = tens * x;
denominator = tens;

你的前两步是合理的。

但是你应该做的是计算分子和分母的最大公约数(GCD),然后用这个公约数除以分子和分母,得到你想要的分数。

GCD相当容易计算。以下是欧几里得算法:

var gcd = function(a, b) {
  if (!b) return a;
  return gcd(b, a % b);
};

编辑

我已经添加了一个完全工作的JSFiddle

除非你愿意自己开发一些东西,否则我建议使用别人已经投入精力的库,比如fraction.js

Javascript

var frac = new Fraction(0.3435);
console.log(frac.toString());

输出
687/2000
在jsFiddle

可以对不同的分母进行蛮力测试,并保留误差最小的结果。

下面的算法是如何实现这一点的一个例子,但是,它的缺点是效率低下,并且仅限于搜索最多10000个分母。

function find_rational( value, maxdenom ) {
  console.clear();
  console.log( "Looking up: " + value );
  let best = { numerator: 1, denominator: 1, error: Math.abs(value - 1) }
  if ( !maxdenom ) maxdenom = 10000;
  for ( let denominator = 1; best.error > 0 && denominator <= maxdenom; denominator++ ) {
    let numerator = Math.round( value * denominator );
    let error = Math.abs( value - numerator / denominator );
    if ( error >= best.error ) continue;
    best.numerator = numerator;
    best.denominator = denominator;
    best.error = error;
    console.log( "Intermediate result: "
                   + best.numerator + "/" + best.denominator
                   + " (" + ( best.numerator/best.denominator)
                   + " error " + best.error + " )" );
  }
  console.log( "Final result: " + JSON.stringify( best ) );
  return best;
}
  
function calc() {
    const value = parseFloat( $("#myInput").val() );
    if ( isNaN(value) ) {
        $( "#myResult" ).val( "NaN" );
        return;
    }
    const rational = find_rational( value, 10000 );
    $("#myResult").val( rational.numerator
                        + " / " + rational.denominator
                        + " ( Error: " + rational.error + " )" );
}
calc();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<P>
Enter a decimal number:<BR/>
<INPUT type="text" name="myInput" id="myInput" value=".3435" onkeyup="calc()"/><BR/>
</P>
<P>
Resulting Rational:<BR/>
<INPUT name="myResult" id="myResult" value=""/><BR/>
</P>

以上决定了。3435作为分数是687/2000。

同样,如果你给它PI(例如3.1415926),它会产生好看的分数,如22/7和355/113。

一个简单快捷的方法是

getFraction = (decimal) => {
  for(var denominator = 1; (decimal * denominator) % 1 !== 0; denominator++);
  return {numerator: decimal * denominator, denominator: denominator};
}

我使用GCD方法得到非常差的结果。我使用迭代方法得到了更好的结果。

例如,下面是一种非常粗糙的方法,它将十进制中的一个分数归零:

function toFraction(x, tolerance) {
    if (x == 0) return [0, 1];
    if (x < 0) x = -x;
    if (!tolerance) tolerance = 0.0001;
    var num = 1, den = 1;
    function iterate() {
        var R = num/den;
        if (Math.abs((R-x)/x) < tolerance) return;
        if (R < x) num++;
        else den++;
        iterate();
    }
    iterate();
    return [num, den];
}

用欧几里德算法求最大公约数。

function reduce(numerator,denominator){
  var gcd = function gcd(a,b){
    return b ? gcd(b, a%b) : a;
  };
  gcd = gcd(numerator,denominator);
  return [numerator/gcd, denominator/gcd];
}

这将在控制台上为您提供以下结果

reduce(2,4);
// [1,2]
reduce(13427,3413358);
// [463,117702]

从已有的内容继续,

var x = 34/35;
var a = x - x.toFixed();
var tens = Math.pow(10,a.toString().length - 2);
var numerator = tens * x;
var denominator = tens;
reduce(numerator,denominator);

来源:https://stackoverflow.com/a/4652513/1998725

我研究了整个网站,并将所有代码合并为一个,给你!

function fra_to_dec(num){
    var test=(String(num).split('.')[1] || []).length;
    var num=(num*(10**Number(test)))
    var den=(10**Number(test))
    function reduce(numerator,denominator){
        var gcd = function gcd(a,b) {
            return b ? gcd(b, a%b) : a;
        };
        gcd = gcd(numerator,denominator);
        return [numerator/gcd, denominator/gcd];
    }
    return (reduce(num,den)[0]+"/"+reduce(num,den)[1])
}

这个代码很容易使用!你甚至可以把number放在这个函数中!

关键是不要让浮点数丢失。

将数字转换为字符串限制了末尾数字,

特别是当你有一个小数和一个整数,比如1.0625。

可以通过传递精度形参来舍入笨拙的分数。

通常你想强制一个四舍五入的值向上,所以第三个参数可以指定。

(例如;如果使用1/64的精度,则非零数字的最小返回值将是1/64,而不是0。

Math.gcd= function(a, b){
    if(b) return Math.gcd(b, a%b);
    return Math.abs(a);
}
Math.fraction= function(n, prec, up){
    var s= String(n), 
    p= s.indexOf('.');
    if(p== -1) return s;
    var i= Math.floor(n) || '', 
    dec= s.substring(p), 
    m= prec || Math.pow(10, dec.length-1), 
    num= up=== 1? Math.ceil(dec*m): Math.round(dec*m), 
    den= m, 
    g= Math.gcd(num, den);
    if(den/g==1) return String(i+(num/g));
    if(i) i= i+' and  ';
    return i+ String(num/g)+'/'+String(den/g);
}

Math.roundFraction (.3435, 64);value:(String) 11/32

受@chowey答案的启发,其中包含在给定公差范围内寻找十进制值的接近分数的递归实现,这里是更好的(参见基准),迭代版本。

function toFractionIterative(x, epsilon = 0.0001) {
    if (x == 0) return [0, 1];
    const a = Math.abs(x);
    let n = 0;
    let d = 1;
    let r;
    while (true) {
        r = n / d;
        if (Math.abs((r - a) / a) < epsilon) {
            break;
        }
        if (r < a) {
            n++;
        }
        else {
            d++;
        }
    }
    return [x < 0 ? -n : n, d];
}

基准测试(tl;dr:递归1,589 ops/s,迭代5,955 ops/s;使用迭代方法)

let v = 3.141592;
document.write(d2f(v)); // 392699/125000
function d2f(v) // decimal to fraction
{
    if (Math.floor(v) == v) return v + '/' + 1;
    v = Math.abs(v);
    let ret = .01,            // rounding error tolerance
        td = v-Math.floor(v), // trailing digits
        r = 1/td,             // reciprocal
        d = r,                // start building denominator
        lim = 20;             // max loop limit
    for (let i = 0; i < lim; i++)
    {
        td = r-Math.floor(r);
        if (Math.abs(r-Math.round(r)) < ret) break;
        r = 1/td;
        d *= r;
    }
    return Math.round(d*v) + '/' + Math.round(d);
}

我想出了这个

function getfract(theNum){
    var input=theNum.toString();
    var whole = input.split(".")[0];
    var rem = input.split(".")[1] * .1;
    return(whole + " " + Math.round(rem * 16) + "/16");
}
function decimalToFraction(num) {
    let numsAfterDecPoint = num.toString().split('.')[1] ? num.toString().split('.')[1].length : 0;
    let numerator = num * Math.pow(10, numsAfterDecPoint);
    let denominator = Math.pow(10, numsAfterDecPoint);
    console.log(numerator + " / " + denominator)
    let d = GCD(numerator,denominator)
    return numerator / d + " / " + denominator / d
}
console.log(decimalToFraction(0.5)); // 5 / 10 => 1 / 2
console.log(decimalToFraction(178.45)); // 17845 / 100 => 3569 / 20
function GCD(a,b) {
    let r = 0;
    while(b != 0) {
        r = a % b 
        a = b;
        b = r;
    }
    return a;
}