2013-05-02 36 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是英文,但沒有太多的可視化。