amexlar
@amexlar

Какой библиотекой на Node.js можно воспользоваться для равномерного деления?

Всем привет!

Не знаю, как это правильно выразить "по-математически")

Суть задачи в следующем.
- есть некое (в общем случае) вещественное число
- есть целое число - кол-во разбиений
- есть некое ограничение - точность
Надо найти "равномерное" разбиение

Проще показать на примере
Исходное число - 20, кол-во разбиений - 3, точность разбиений - до целого
Подходящий результат - 6-7-7 (три целых числа, в сумме дают исходное). Варианты типа 5-7-8 не подойдут - у них разброс получается не совсем "равномерный"
Понятное дело, что, к примеру, число 18 на три "равномерных" разбиения делится без проблем - 6-6-6

Более сложный пример
Исходное число 27.8, кол-во разбиений - 4, точность - 0.1. Подходящий результат - 6.9-6.9-7.0-7.0

Точность - это не максимально допустимое отклонение между полученными числами, а максимальная (минимальная?) точность самих чисел. То есть при точности 0.1 не может быть число, к примеру, 2.75 - только 2.7 или 2.8

Подозреваю, что у этой задачи наверняка есть свое название и, соответственно, алгоритм расчета. Буду рад, если кто-то им поделится, но в идеале хотелось бы готовое решение на Node.js

Заранее спасибо за ответы
  • Вопрос задан
  • 123 просмотра
Решения вопроса 1
index0h
@index0h
PHP, Golang. https://github.com/index0h
Довольно интересная задачка, тут конечно нужно еще кучу проверок сделать, но алгоримт может выглядеть примерно так: https://3v4l.org/DQRKq
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
sergiks
@sergiks Куратор тега JavaScript
♬♬
Можно решить рекурсией.

На каждом шаге получаем очередное слагаемое, округляя результат к ближайшему в «сетке» с учётом точности. Для целых это выглядит так:
Math.round(20 / 3) === 7 // 7 занесли в массив результата
20 - 7 = 13 
// далее повторяем с 13 и делим уже на 3 - 1 === 2
Math.round(13 / 2) === 7 // 7 идёт в результат
13 - 7 === 6
// далее повторяем с 6 и делить надо бы на 2 - 1 === 1
// т.е. осталось одно число в результат. Просто вписываем туда остаток 6


С точностью надо умножать/делить на эту точность перед тем, как округлять к ближайшему целому. Но тут вылезают проблемы с точностью плавающей точки. Поэтому надо уточнить, какие могут быть значения точности: до опр. знака после запятой, или вообще любое значение типа 0.137456?
function split(n, divisor, q, result) {
  q = q || 1;
  result = result || [];
  const m = q * Math.round(n / divisor / q);
  result.push(m);
  n -= m;
  if( --divisor > 1) return split(n, divisor, q, result);
  else {
    result.push(n);
    return result.sort((a,b) => a - b); // сортировка по возрастанию, на всякий случай
  }
}


split(20, 3) // [6, 7, 7]
split(20, 3, 0.1) // [6.6000000000000005, 6.7, 6.7]
split(27.8, 4, 0.1) // [6.9, 6.9, 7, 7]
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы