We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
浮点数转换为分数是一个不算常见的需求。其中涉及的数学原理也不算十分复杂。这里简单讲述两种方法。
首先,浮点数均为有理数。所以其实可以将问题简单转化为有理数转分数。
假设我们有浮点数 2.33,即可知道其能转化为 233/100。也就是我们需要求出 233 与 100 的最大公约数简化分数即可。
而求公约数比较通用有效的方法就是辗转相除法,计算公式gcd(a,b) = gcd(b,a mod b)。
gcd(a,b) = gcd(b,a mod b)
JavaScript 算法如下:
function gcd(a, b) { let temp; if (a < b) { temp = a; a = b; b = temp; } while(b !== 0) { temp = b; b = a % b; a = temp; } return a; }
那么我们这个转化方法就很简单了。
示例如下:https://codepen.io/anon/pen/ajYyXd
求公约数的方法的好处就是能够保证精确度。但是有的时候太过精确并不是一件好事。
例如 0.33333333333,1/3 会是比 33333333333/100000000000 更符合人类的习惯。
这个时候我们就要使用连分数这个概念。详情可见 wiki。https://zh.wikipedia.org/zh-hans/%E8%BF%9E%E5%88%86%E6%95%B0
关键的原理如下:
鉴于此,我们可以利用其进行浮点数转分数。
关键算法如下:
要计算实数r的连分数表示,写下r的整数部分(技术上floor)。从r减去这个整数部分。如果差为0则停止;否则找到这个差的倒数并重复。这个过程将终止,当且仅当r是有理数。
我们可以得出如下 JavaScript 代码:
/** * 通过连分数原理计算可选的分数选项 * @param {number} number 浮点数 * @param {object} option 选项 * @param {number} option.maxDenominatorLength 分母最大位数 * @returns {Object} 将返回最贴近的分数 */ function getApproximateFractionsByContinuedFraction(num, { maxDenominatorLength = 7 }) { const numerators = [0, 1]; const denominators = [1, 0]; const decimalPart = num - parseInt(num); const maxNumerator = parseInt(decimalPart.toString().replace('0.', '')); let currentDigits = num; let currentResult; let previousResult = NaN; const ret = {numerators, denominators}; // 为避免较长时间的运算,我们设定最多一千次的限制 for (let i = 2; i < 1000; i++) { const integerPart = Math.floor(currentDigits); const currentNumerator = integerPart * numerators[i-1] + numerators[i-2]; // 用于排除整数 if (Math.abs(numerators[i]) > maxNumerator) break; const currentDenominator = integerPart * denominators[i - 1] + denominators[i - 2]; if (maxDenominatorLength && currentDenominator.toString().length > maxDenominatorLength) break; numerators[i] = currentNumerator; denominators[i] = currentDenominator; currentResult = numerators[i] / denominators[i]; if (currentResult === previousResult || currentResult === num) break; previousResult = currentResult; // 找到这个差的倒数并重复。 currentDigits = 1 / (currentDigits - integerPart); } const lastIndex = numerators.length - 1; // 证明是整数 if (lastIndex < 2) { return { numerator: num, denominator: 1, } } return { numerator: numerators[lastIndex], denominator: denominators[lastIndex], } }
可见 demo 如下 http://www.mindspring.com/~alanh/fracs.html
The text was updated successfully, but these errors were encountered:
No branches or pull requests
浮点数转换为分数
浮点数转换为分数是一个不算常见的需求。其中涉及的数学原理也不算十分复杂。这里简单讲述两种方法。
辗转相除法求公约数
首先,浮点数均为有理数。所以其实可以将问题简单转化为有理数转分数。
假设我们有浮点数 2.33,即可知道其能转化为 233/100。也就是我们需要求出 233 与 100 的最大公约数简化分数即可。
而求公约数比较通用有效的方法就是辗转相除法,计算公式
gcd(a,b) = gcd(b,a mod b)
。JavaScript 算法如下:
那么我们这个转化方法就很简单了。
示例如下:https://codepen.io/anon/pen/ajYyXd
使用连分数转换分数
求公约数的方法的好处就是能够保证精确度。但是有的时候太过精确并不是一件好事。
例如 0.33333333333,1/3 会是比 33333333333/100000000000 更符合人类的习惯。
这个时候我们就要使用连分数这个概念。详情可见 wiki。https://zh.wikipedia.org/zh-hans/%E8%BF%9E%E5%88%86%E6%95%B0
关键的原理如下:
鉴于此,我们可以利用其进行浮点数转分数。
关键算法如下:
我们可以得出如下 JavaScript 代码:
可见 demo 如下 http://www.mindspring.com/~alanh/fracs.html
The text was updated successfully, but these errors were encountered: