Ну, я не совсем уверен, что это именно то, что вы хотите, но, надеюсь, это даст вам некоторые идеи о том, как действовать:
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
Это выглядит разумно для меня, хотя я не знаю, что именно вы хотите увидеть для некоторых из этих крайних случаев.Во всяком случае, надеюсь, что это помогает.Удачи!