Преобразовать строку дроби в десятичную?

Я пытаюсь создать функцию javascript, которая может принимать входную строку дроби, такую ​​​​как '3/2', и преобразовывать ее в десятичную — либо в виде строки '1.5', либо числа 1.5

function ratio(fraction) {
    var fraction = (fraction !== undefined) ? fraction : '1/1',
    decimal = ??????????;
    return decimal;
});

Есть ли способ сделать это?


person ryanve    schedule 22.08.2011    source источник
comment
eval(fraction), конечно, сработает, но только если вы доверяете своим данным.   -  person cdhowie    schedule 22.08.2011
comment
@cdhowie И в этом случае да — спасибо!   -  person ryanve    schedule 22.08.2011
comment
Обратите внимание, что многие дроби не могут быть точно представлены в виде десятичных чисел (например, 1/3), а многие десятичные дроби не могут быть точно представлены в javascript: 0.0065 + 0.0005 = 0.006999999999999999;   -  person RobG    schedule 22.08.2011


Ответы (16)


Поскольку никто еще не упомянул об этом, есть быстрое и грязное решение:

var decimal = eval(fraction); 

У которого есть преимущества правильной оценки всех видов математических строк.

eval("3/2")    // 1.5
eval("6")      // 6
eval("6.5/.5") // 13, works with decimals (floats)
eval("12 + 3") // 15, you can add subtract and multiply too

Люди здесь будут быстро упоминать об опасностях использования необработанного eval, но я представляю это как ответ ленивого человека.

person Community    schedule 22.08.2011
comment
+1, так как это это простое решение, и вы предупредили об опасностях. - person paxdiablo; 22.08.2011
comment
@Nat Это именно то, что мне нужно в данном случае. Спасибо! - person ryanve; 22.08.2011
comment
Не лень, это то, для чего предназначен eval — вычисление выражений, которые неизвестны до времени выполнения. - person RobG; 22.08.2011
comment
Это старый вопрос, но я хотел бы понять, каковы опасности использования eval в этом случае? Я новичок в JS, но это очень хорошо решило мою проблему, однако это данные, введенные пользователем, так что может ли это вызвать проблемы? - person GiH; 05.03.2013
comment
@GiH eval работает медленно и потенциально опасно. Если пользователь может найти способ заставить вас вызывать eval() в его строке, то он потенциально может использовать XSS с ней. - person Matt Greer; 19.02.2014
comment
так как это простое решение и вы предупредили об опасностях – но в том то и дело, он НЕ предупреждает об опасностях. В полном ответе будет указано, почему они не должны этого делать! - person Indolering; 20.10.2014
comment
@Индолер Право. Он не предупреждал об опасностях. Но он упомянул, что есть связанные с этим опасности. Список опасностей мы все можем попросить у дяди Google, или Bing, или кого-то еще;) - person Ricardo Appleton; 21.02.2017

Вот минимальный код, необходимый для этого:

var a = "3/2";
var split = a.split('/');
var result = parseInt(split[0], 10) / parseInt(split[1], 10);
alert(result); // alerts 1.5

JsFiddle: http://jsfiddle.net/XS4VE/

Что следует учитывать:

  • деление на ноль
  • если пользователь дает вам целое число вместо дроби или любой другой недопустимый ввод
  • проблемы с округлением (например, 1/3)
person Matt Greer    schedule 22.08.2011
comment
Спасибо. Это довольно гладко. Я буду иметь это в виду, если мне когда-нибудь понадобится полная сделка, но сейчас все, что мне нужно, это метод eval(). - person ryanve; 22.08.2011
comment
Нет необходимости в parseInt, просто используйте split[0]/split[1]. - person RobG; 22.08.2011

Что-то вроде этого:

bits = fraction.split("/");
return parseInt(bits[0],10)/parseInt(bits[1],10);
person Coomie    schedule 22.08.2011

Я создал хорошую функцию, чтобы сделать именно это, все было основано на этом вопросе и ответах, но он будет принимать строку и выводить десятичное значение, но также будет выводить целые числа без ошибок.

https://gist.github.com/drifterz28/6971440

function toDeci(fraction) {
    fraction = fraction.toString();
    var result,wholeNum=0, frac, deci=0;
    if(fraction.search('/') >=0){
        if(fraction.search('-') >=0){
            wholeNum = fraction.split('-');
            frac = wholeNum[1];
            wholeNum = parseInt(wholeNum,10);
        }else{
            frac = fraction;
        }
        if(fraction.search('/') >=0){
            frac =  frac.split('/');
            deci = parseInt(frac[0], 10) / parseInt(frac[1], 10);
        }
        result = wholeNum+deci;
    }else{
        result = fraction
    }
    return result;
}

/* Testing values / examples */
console.log('1 ',toDeci("1-7/16"));
console.log('2 ',toDeci("5/8"));
console.log('3 ',toDeci("3-3/16"));
console.log('4 ',toDeci("12"));
console.log('5 ',toDeci("12.2"));
person E-comm    schedule 14.10.2013

У меня есть функция, которую я использую для обработки целых чисел, смешанных дробей (включая символы вульгарной дроби Unicode) и десятичных дробей. Вероятно, нуждается в некоторой полировке, но это работает для моей цели (разбор списка ингредиентов рецепта).

Вводы "2 1/2", "2½", "2 ½" и "2.5" вернут 2.5. Примеры:

var numQty = require("numeric-quantity");

numQty("1 1/4") === 1.25;  // true
numQty("3 / 4") === 0.75;  // true
numQty("¼" ) === 0.25;     // true
numQty("2½") === 2.5;      // true
numQty("¾") === 0.75;      // true
numQty("⅓") === 0.333;     // true
numQty("⅔") === 0.667;     // true

Одна вещь, которую он не обрабатывает, - это десятичные дроби внутри дроби, например. "2.5 / 5".

person Jake Boone    schedule 20.03.2015

Слишком поздно, но может быть полезно:

Вы можете использовать Array.prototype.reduce вместо eval https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

ES6

const fractionStrToDecimal = str => str.split('/').reduce((p, c) => p / c);
console.log(fractionStrToDecimal('1/4/2')); // Logs 0.125
console.log(fractionStrToDecimal('3/2')); // Logs 1.5

ЗАО

function fractionStrToDecimal(str) {
  return str.split('/').reduce((p, c) => p / c);
}
console.log(fractionStrToDecimal('1/4')); // Logs 0.25

[EDIT] Удалено начальное значение редуктора, и теперь функция работает для числителей больше 1. Спасибо, Джеймс Фьюри.

person Fabricio Mendonça    schedule 20.11.2017
comment
Не работает для числителей больше 1 (например, «3/2»). - person James Furey; 13.03.2018
comment
Ты прав. Просто удалил начальное значение редуктора, и теперь он работает. Спасибо! - person Fabricio Mendonça; 14.03.2018

Функция (ES6):

function fractionToDecimal(fraction) {
  return fraction
    .split('/')
    .reduce((numerator, denominator, i) =>
      numerator / (i ? denominator : 1)
    );
}

Функция (ES6, сокращенно):

function fractionToDecimal(f) {
  return f.split('/').reduce((n, d, i) => n / (i ? d : 1));
}

Примеры:

fractionToDecimal('1/2');     // 0.5
fractionToDecimal('5/2');     // 2.5
fractionToDecimal('1/2/2');   // 0.25
fractionToDecimal('10/5/10'); // 0.2
fractionToDecimal('0/1');     // 0
fractionToDecimal('1/0');     // Infinity
fractionToDecimal('cat/dog'); // NaN
person James Furey    schedule 13.03.2018

Если вы не возражаете против использования внешней библиотеки, math.js предлагает несколько полезных функций. для преобразования дробей в десятичные, а также для выполнения арифметических операций с дробными числами.

console.log(math.number(math.fraction("1/3"))); //returns 0.3333333333333333
console.log(math.fraction("1/3") * 9) //returns 3
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.20.1/math.js"></script>

person Alfred Waligo    schedule 30.01.2018

Чтобы преобразовать дробь в десятичную, просто разделите верхнее число на нижнее число. 5 разделить на 3 будет 5/3 или 1,67. Так же, как:

function decimal(top,bottom) {
    return (top/bottom)
}

Надеюсь, это поможет, ха-ха

person DDPWNAGE    schedule 20.02.2013

Он работает с методом eval(), но вы можете использовать метод parseFloat. Я думаю, что это лучше! К сожалению, это будет работать только с такими значениями - "12,2" не с "5/8", но поскольку вы можете справиться с расчетами, я думаю, что это хороший подход!

person Kaloyan Stamatov    schedule 21.01.2014

Если вы хотите использовать результат как дробь, а не просто получить ответ из строки, библиотека типа https://github.com/infusion/Fraction.js отлично справится с этой задачей.

var f = new Fraction("3/2");
console.log(f.toString()); // Returns string "1.5"
console.log(f.valueOf()); // Returns number 1.5

var g = new Fraction(6.5).div(.5);
console.log(f.toString()); // Returns string "13"
person Robert Eisele    schedule 04.06.2015

Также немного поздно для вечеринки, но альтернативой eval() с меньшими проблемами безопасности (по крайней мере, согласно MDN) является фабрика Function().

var fraction = "3/2";
console.log( Function("return (" + fraction + ");")() );

Это выведет результат «1.5» в консоль.

Также в качестве примечания: смешанные дроби, такие как 1 1/2, не будут работать ни с eval(), ни с решением с Function(), как написано, поскольку они оба натыкаются на пробел.

person Canis    schedule 25.07.2018

более безопасный eval() согласно MDN

const safeEval = (str) => {
   return Function('"use strict";return (' + str + ")")();
}

safeEval("1 1/2") // 1.5

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Do_not_ever_use_eval!

person AverageChau    schedule 03.03.2019

Это тоже будет работать:

let y = "2.9/59"
let a = y.split('')
let b = a.splice(a.indexOf("/"))
console.log(parseFloat(a.join('')))
a = parseFloat(a.join(''))
console.log(b)
let c = parseFloat(b.slice(1).join(''))
let d = a/c
console.log(d) // Answer for y fraction
person Muks123    schedule 02.07.2019

С точки зрения удобочитаемости, шаг через точку отладки, это может быть проще:

// i.e. '1/2' -> .5
// Invalid input returns 0 so impact on upstream callers are less likely to be impacted
function fractionToNumber(fraction = '') {
    const fractionParts = fraction.split('/');
    const numerator = fractionParts[0] || '0';
    const denominator = fractionParts[1] || '1';
    const radix = 10;
    const number = parseInt(numerator, radix) / parseInt(denominator, radix);
    const result = number || 0;

    return result;
}
person Christopher Fahey    schedule 18.03.2020
comment
Этот код является хорошей отправной точкой в ​​зависимости от того, насколько устойчивым/защитным/предсказуемым вы хотите его сделать. Эта функция кричит о модульном тестировании, чтобы подтвердить, что она работает правильно в сценариях, которые вы ожидаете обработать. - person Christopher Fahey; 18.03.2020

Я разработал функцию для преобразования значения с использованием коэффициента, который может быть передан как часть целых чисел или десятичных дробей. Пользовательский ввод и коэффициент преобразования могут быть в неправильном формате, поэтому он проверяет, является ли исходное значение числом, а также проверяется, может ли преобразование быть преобразовано в дробь, предполагая, что /число означает 1/число, или есть числитель и знаменатель в формате число/число.

/**
 * Convert value using conversion factor
 * @param {float} value - number to convert
 * @param {string} conversion - factor
 * @return {float} converted value
 */
function convertNumber(value, conversion) {
  try {
    let numberValue = eval(value);
    if (isNaN(numberValue)) {
      throw value + " is not a number.";
    }
    let fraction = conversion.toString();
    let divider = fraction.indexOf("/");
    let upper = 1;
    let denominator = 1;
    if (divider == -1) {
      upper = eval(fraction);
    } else {
      let split = fraction.split("/");
      if (split.length > 2) {
        throw fraction + " cannot be evaluated to a fraction.";
      } else {
        denominator = eval(split[1]);
        if (divider > 0) {
          upper = eval(split[0]);
        }
      }
    }
    let factor = upper/denominator;
    if (isNaN(factor)) {
      throw fraction + " cannot be converted to a factor.";
    }
    let result = numberValue * factor;
    if (isNaN(result)) {
      throw numberValue + " * " + factor + " is not a number.";
    }
    return result
  } catch (err) {
    let message = "Unable to convert '" + value + "' using '" + conversion + "'. " + err;
    throw message;
  }
}
person Janine White    schedule 18.03.2021