将十进制数转换为分数/有理数
Convert a decimal number to a fraction / rational number
在JavaScript中,有没有任何方法可以将十进制数(如0.0002
)转换为用字符串表示的分数(如"2/10000"
")?
如果为此目的编写了一个名为decimalToFraction
的函数,那么decimalToFraction(0.0002)
将返回字符串"2/10000"
。
您可以使用Erik Garrison的fraction.js库来执行此操作以及更多的分数运算。
var f = new Fraction(2, 10000);
console.log(f.numerator + '/' + f.denominator);
要做.003你可以只做
var f = new Fraction(.003);
console.log(f.numerator + '/' + f.denominator);
用"decimal-to-fraction js"一词在谷歌上搜索一下,第一个结果是:
http://wildreason.com/wildreason-blog/2010/javascript-convert-a-decimal-into-a-simplified-fraction/
它似乎起作用:
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"
这个问题很老,但也许有人会觉得有用。它是迭代的,不是递归的,不需要因子分解
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};
};
我使用这个网站链接来构建一个函数,但正如文章所提到的,你会得到一个不合理的大量部首或pi。
希望它能有所帮助。
function Fraction(){}
Fraction.prototype.convert = function(x, improper)
{
improper = improper || false;
var abs = Math.abs(x);
this.sign = x/abs;
x = abs;
var stack = 0;
this.whole = !improper ? Math.floor(x) : 0;
var fractional = !improper ? x-this.whole : abs;
/*recursive function that transforms the fraction*/
function recurs(x){
stack++;
var intgr = Math.floor(x); //get the integer part of the number
var dec = (x - intgr); //get the decimal part of the number
if(dec < 0.0019 || stack > 20) return [intgr,1]; //return the last integer you divided by
var num = recurs(1/dec); //call the function again with the inverted decimal part
return[intgr*num[0]+num[1],num[0]]
}
var t = recurs(fractional);
this.numerator = t[0];
this.denominator = t[1];
}
Fraction.prototype.toString = function()
{
var l = this.sign.toString().length;
var sign = l === 2 ? '-' : '';
var whole = this.whole !== 0 ? this.sign*this.whole+' ': sign;
return whole+this.numerator+'/'+this.denominator;
}
//var frac = new Fraction()
//frac.convert(2.56, false)
//console.log(frac.toString())
//use frac.convert(2.56,true) to get it as an improper fraction
如果你只想要一个只返回分子和分母的自包含函数,那么使用下面的函数。
var toFraction = function (dec) {
var is_neg = dec < 0;
dec = Math.abs(dec);
var done = false;
//you can adjust the epsilon to a larger number if you don't need very high precision
var n1 = 0, d1 = 1, n2 = 1, d2 = 0, n = 0, q = dec, epsilon = 1e-13;
while (!done) {
n++;
if (n > 10000) {
done = true;
}
var a = parseInt(q);
var num = n1 + a * n2;
var den = d1 + a * d2;
var e = (q - a);
if (e < epsilon) {
done = true;
}
q = 1 / e;
n1 = n2;
d1 = d2;
n2 = num;
d2 = den;
if (Math.abs(num / den - dec) < epsilon || n > 30) {
done = true;
}
}
return [is_neg ? -num : num, den];
};
//Usage:
//var frac = toFraction(0.5);
//console.log(frac)
//Output: [ 1, 2 ]
使用数字的字符串表示有一个非常简单的解决方案
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));
它将只检查分数中有多少个数字,然后扩展f/1的分数,直到f是整数。这可能导致巨大的分数,所以你可以通过将分子和分母除以两者的最大公约数来减少它,例如
// 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;
}
好消息是这是可能的,但您必须将其转换为代码。
让我们毫无理由地选择2.56。
使用数字的小数部分。56
.56中有两位数字,将.56写成56/100。
所以我们有2+56/100,需要通过将分子和分母除以最大公约数,将这个分数降到最低项,在这种情况下是4。
因此,这个分数降到最低项是2+14/25。
为了把这整个2加起来,我们乘以除数,再加上14
(2*25+14)/25=64/25
我按照popfaced的建议做了,这里是
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值上失败。我已经修复了这个错误,并将在下面发布更新的代码
//function to get highest common factor of two numbers (a fraction)
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
if(isNaN(whole) === true)
{
whole = "0";
}
if(isNaN(decimal) === true)
{
return ((whole==0)?"0" : whole);
}
else
{
return ((whole==0)?"0 " : whole+" ")+decimal/t+"/"+num/t;
}
}
我只想要一个左一的替代方案,它是一个JS库,我发现了将十进制数转换为分数和减少分数 库调用fractionn.js,这对我很有帮助,为我节省了很多时间和工作。希望对别人有用!
我知道这是一个老问题,但我创建了一个大大简化的函数。
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;
}
称之为Math.fraction(2.56)
它将:
- 如果输入不是数字,则返回NaN
- 如果输入未定义,则返回undefined
- 减少分数
- 返回一个
string
(对于包含分子和分母的数组使用Math.fraction(2.56).split("/")
)
请注意,这使用了不推荐使用的arguments.callee
,因此在某些浏览器中可能不兼容。
在这里测试
试过这样的东西吗?
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);
简介&解释
尽管这个问题很老,但我看到这个问题最近有了一些修改,当我研究这个问题时,它仍然是搜索引擎上出现的第一件事。
出于这个原因,我想与大家分享:如果有人来这里寻找一个不需要拉入库的简单(天真)解决方案,这就是我最终使用的解决方案。
它是一个简单的蛮力,首先查看1/⌊1/x⌉
是否是一个好的近似值,如果不是,则检查2/⌊2/x⌉
、3/⌊3/x⌉
等,直到在给定的误差范围内得到第一个结果。
代码
function getFrac(x, maxErr){
let s = x<0?-1:1
x = Math.abs(x),
i = Math.floor(x),
d = x-i,
maxErr = maxErr ? maxErr : Math.pow(10,-6);
if(d<maxErr) return [i,1];
let n = 1,
nmax = Math.ceil(d*Math.min(
Math.pow(10,Math.ceil(Math.abs(Math.log10(maxErr)))),
Number.MAX_SAFE_INTEGER
)),
min = Infinity,
best = [0,0];
while(n <= nmax){
let err = Math.abs(d - n/Math.round(n/d));
if(err < maxErr) return [s*(n+i*Math.round(n/d)), Math.round(n/d)];
else if(err < min){
min = err;
best = [s*(n+i*Math.round(n/d)), Math.round(n/d)];
}
n++;
}
return best[1] == 0 ? false : best;
}
示例输出:
getFrac(0) // [0, 1]
getFrac(0.28) // [7, 25]
getFrac(0.28282828) // [28, 99]
getFrac(2.56) // [64, 25]
getFrac(-1.33333333) // [-4, 3]
getFrac(Math.E) // [2721, 1001]
getFrac(Math.PI) // [355, 113]
getFrac(Math.PI, 0.01) // [22, 7]
getFrac(Math.PI, 0.001) // [201, 64]
getFrac(Math.PI, 10**-4) // [333, 106]
getFrac(Math.PI, 10**-12) // [4272943, 1360120]
性能
尽管这是幼稚的方法,但它运行得出奇地好,足够快,满足大多数需求。JSbench和我控制台中使用performance.now()
的测试都表明,当使用小数点后6位的默认错误级别提供随机输入时,getFrac
平均需要约4微秒才能返回。当每次调用getFrac
1000次操作时,链接的JSBench在我的机器上给了我大约200次操作/秒的结果。我在控制台中使用的计时器脚本下面包含了这个结果。
let N = 10000,
nums = new Array(N).fill(0).map(v=>Math.random()*(Math.random()<2/3?1:100)),
t = 0;
for(let n of nums){
const t0 = performance.now();
getFrac(n);
const t1 = performance.now();
t += t1-t0;
}
console.log((t/N)*1000,'micros'); // 4.039999999850989 micros
- 如何生成十进制数
- 将一个十进制数转换成八分之一的分数
- JavaScript basis 是 math.pow 函数中的十进制数
- 用于验证十进制数的正则表达式
- 如何使用 javascript 将浮点数格式化为十进制数(7)
- 如何在javascript中输入十进制数
- 使用jquery验证器插件为十进制数设置正则表达式
- 用于在字符串中查找十进制数的正则表达式
- 如何验证十进制数
- 在 sort() 之后,十进制数的 JavaScript 数组顺序不正确
- 为什么项目符号图显示十进制数,而我们的范围为1
- 输入字段不保存十进制数并将其设置为 ,00
- 使用带有 .NET MVC 的 Javascript 将十进制数格式化为两位
- j查询添加十进制数
- 如何将十进制数添加到时间并将其作为时间格式恢复
- AngularJS双向绑定输入到十进制数
- 请求动画帧不适用于小于 1 的十进制数
- 如何使用 id 输入类型=“文本”JavaScript 中的值设置自动 2 个十进制数
- 将十进制数转换为浮点数并将其截断
- 将十进制数转换为分数/有理数