Как преобразовать десятичные дроби в ближайшую дробь - PullRequest
1 голос
/ 03 апреля 2019

Я хотел бы преобразовать десятичные числа в ближайшую дробь с одним числом! Например, «8,75» должно быть «8 3/4», «1,875» должно быть «1 7/8», но «8,565217 ...» должно отображать не «8 13/23», а ошибку. В Excel есть аналогичная функция, объясненная здесь

Я также хотел бы не использовать третью библиотеку, такую ​​как fra.js, и предпочитаю использовать нативный JS / TS или Lodash! У кого-нибудь есть идея? =)

Спасибо за помощь!

EDIT: Есть часть кода, которую я пробовал, но она не работает должным образом. CS 8.75 отправляет мне 35/4, а не 8 3/4 ...

  private checkNumberToCompute(numberToCompute: any) {
    let numberToReturn = numberToCompute;
    if (
      (!isNaN(Number(numberToCompute)) && numberToCompute.includes('.')) ||
      (numberToCompute.includes(',') && !numberToCompute.includes('/'))
    ) {
      console.log('Nombre à décimal sans fraction');
      numberToReturn = this.computeFractions(numberToCompute);
    }
    return numberToReturn;
  }
  private computeFractions(numberToCompute: any): string {
    console.log('numberToCompute', numberToCompute);

    const lenghtOfDecimals = numberToCompute.substring(numberToCompute.indexOf('.') + 1).length;
    let denominator = Math.pow(10, lenghtOfDecimals),
      numerator = numberToCompute * denominator;
    const divisor = this.gcd(numerator, denominator);

    numerator /= divisor;
    denominator /= divisor;
    return Math.floor(numerator) + '/' + Math.floor(denominator);
  }

  private gcd(numerator: number, denominator: number): any {
    if (denominator < 0.0000001) {
      return numerator;
    }
    return this.gcd(denominator, Math.floor(numerator % denominator));
  }

1 Ответ

3 голосов
/ 03 апреля 2019

Ну, я не совсем уверен, что это именно то, что вы хотите, но, надеюсь, это даст вам некоторые идеи о том, как действовать:

const acceptableDenominators = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const maxDistanceToNumerator = 0.0001;

function numberToFractionString(n: number): string | undefined {
    const negative = (n < 0);
    if (negative) n = -n;

    const wholePart = Math.floor(n);
    n -= wholePart;

    const denom = acceptableDenominators.find(d =>
        Math.abs(d * n - Math.round(d * n)) <= maxDistanceToNumerator
    );
    if (typeof denom === 'undefined') {
        return;
    }
    const numer = Math.round(denom * n);

    if (denom === 1) {
        return "" + (wholePart + numer) * (negative ? -1 : 1);
    }

    return (negative ? "-" : "") +
        (wholePart ? wholePart + " " : "") +
        numer + "/" + denom;

}

Идея состоит в том, что вам нужно выяснить,каковы приемлемые знаменатели для дробей;в вашем случае вам, похоже, нужны только однозначные числа, поэтому я указал только 1 - 9.Также вам нужно выяснить, насколько близко число с плавающей запятой должно быть к дроби, чтобы принять его.В данном случае я указал, что для того, чтобы что-то было распознано, скажем, 3/5, оно должно быть между 2.9999/5 и 3.0001/5.

Тогда есть много крайних случаев, с которыми нужно иметь дело(отрицательные числа и числа, очень близкие к целому числу, интересны), но основная процедура состоит в том, чтобы просто проверить каждый возможный знаменатель от наименьшего к наибольшему (автоматически давая вам уменьшенную дробь, поскольку она найдет 1/2 до 4/8) и выбратьпервый, где числитель будет достаточно близок к целому числу ... или вернет undefined (вместо того, чтобы выдать ошибку, но вы можете сделать это, если хотите), если нет.

Давайте посмотрим, еслиэто работает:

const tests = [8.75, 1.875, 8.565217, 9.99999999, -1, -0.888889,
    0, 1e140, -1e-140, -0.111111, 0.5,
    -7.66667, -7.6667, -7.667, -7.67, -7.7,
    NaN, Infinity, -Infinity];

tests.forEach(n =>
    console.log("" + n + ": " + String(numberToFractionString(n)))
);

// 8.75: 8 3/4
// 1.875: 1 7/8
// 8.565217: undefined
// 9.99999999: 10
// -1: -1
// -0.888889: -8/9
// 0: 0
// 1e+140: 1e+140
// -1e-140: 0
// -0.111111: -1/9
// 0.5: 1/2
// -7.66667: -7 2/3
// -7.6667: -7 2/3
// -7.667: undefined
// -7.67: undefined
// -7.7: undefined
// NaN: undefined
// Infinity: undefined
// -Infinity: undefined

Это выглядит разумно для меня, хотя я не знаю, что именно вы хотите увидеть для некоторых из этих крайних случаев.Во всяком случае, надеюсь, что это помогает.Удачи!

...