2013-05-02 35 views
1
function gcd(a, b) { 
    return (b) ? gcd(b, a % b) : a; 
} 
var dec2Frac = function (d) { 
    var top = d.toString().replace(/\d+[.]/, ''); 
    var bot = Math.pow(10, top.length); 
    if (d > 1) { 
     top = +top + Math.floor(d) * bot; 
    } 
    var x = gcd(top, bot); 
    var r1 = top/x; 
    var r2 = bot/x; 
    var frac = r1 + "/" + r2; 
    var parts = frac.split('/'); 
    var simpler = parts[0][0]+'/'+parts[1][0]; 
    return simpler; 
}; 

如果我输入640x960 = 0.66666666666667意外的结果转换时小数部分

我期待的结果是2/3这里显而易见的:http://www.mindspring.com/~alanh/fracs.html

不是此函数返回6/1。测试在这里:http://jsbin.com/asoxud/1/

+0

为什么你期待'2/3'的结果呢?您的算法与正确的舍入技术无关,如连续分数。 – 2013-05-02 09:08:24

+1

一些调试技巧可以帮助:http://jsbin.com/asoxud/3/edit – Passerby 2013-05-02 09:24:41

回答

1

作为除了MVG的答案,

我发现这很有趣,想了解怎么点浮动存储以及如何回到一个浮动的分数,也许做计算他们。

它给了一点brainache试图弄清楚这一点对我自己的,但因为它使点击,我想出了这个Fraction功能,

我不知道如果这能帮助你或没有,但

现在它反正写的,为什么不离开这里

function Fraction(n, d) { 
    if ("number" !== typeof n) 
     throw new TypeError("Excptected Parameter to be of type number"); 

    var strings = n.toString(2).split("."); //Split the number by its decimal point 

    if (strings.length > 1 && !d) { //No denominator given and n is a float 

     var floats = [strings[1].substr(0, 27), strings[1].substr(27, 54)]; //Split into to parts 

     var int64 = [ 
      parseInt(floats[0], 2) << 1, 
      parseInt(floats[1], 2) << 1 
     ]; 

     var denominator = Math.pow(2, strings[1].length + 1); // 
     var numerator = int64[0] * Math.pow(2, floats[1].length); 

     numerator += int64[1]; 
     numerator += parseInt(strings[0], 2) * denominator; 

     this.numerator = numerator; 
     this.denominator = denominator; 
     this.reduce(); 

     this.approx = approx(n); 

    } else if (strings.length < 2 && !d) { // If no denominator and n is an int 
     this.numerator = n; 
     this.denominator = 1; 
    } else { //if n and d 
     this.numerator = n; 
     this.denominator = d; 
    } 

    function approx(f, n) { 
     n = n || 0; 
     var fraction = new Fraction(1, 1); 

     var float = Math.pow(f, -1); 
     var rec = ~~float; 
     var decimal = float - rec; 

     if (float.toPrecision(Fraction.precision) == rec) 
      return new Fraction(1, rec); 
     var _fraction = approx(decimal, n + 1); 

     fraction.denominator = rec * _fraction.denominator + _fraction.numerator; 
     fraction.numerator = _fraction.denominator; 

     return fraction; 

    } 

} 

//The approx precision 
Fraction.precision = 10; 
Fraction.prototype.toString = function() { 
    return this.numerator + "/" + this.denominator; 
}; 
Fraction.prototype.gcd = function() { 
    return (function gcd(u, v) { 
     return ((u > 0) ? gcd(v % u, u) : v); 
    })(this.numerator, this.denominator); 
}; 
Fraction.prototype.reduce = function() { 
    var _gcd = this.gcd(); 
    this.numerator /= _gcd; 
    this.denominator /= _gcd; 
}; 

Fraction.prototype.valueOf = function() { 
    return this.numerator/this.denominator; 
}; 




var f = new Fraction(0.3333); 
+ f; //0.3333333333 
f.toString(); // 6004799502560181/18014398509481984 
+ f.approx //0.33333 
+ f.approx.toString() //3333/10000 

var g = new Fraction(2/3); 
+ g; //0.6666666666666666 
g.toString(); //6004799503160661/9007199254740992 
+ g.approx //0.6666666666666666 
+ g.approx.toString() //2/3 

继承人JSbin以及

+0

太棒了!感谢堆! :D – 3zzy 2013-05-06 10:58:36

+0

:D不客气! =) – C5H8NNaO4 2013-05-08 08:53:23

0

你的浮点数是你希望的有理数的近似值。见例如Is floating point math broken?了解详细信息。突出的是:你不可能希望真正找到代表你的原始分数的分子和分母。

如果你想要这个分数,你应该看看continued fractions。每个截断的连续分数将表示best possible rational approximation为任意值。您可以继续操作,直到错误足够小。

Here是一个可视化这个近似值的页面。文本是德文的,但是数学应该足够清楚。 This page是英文,但没有太多的可视化。