Комментарии 6
Вангую, что вот в таком фрагменте
factorial(points.Length - 1) / (factorial(i) * factorial(points.Length - 1 - i))
вы наступите на обалденные грабли. Факториал растет чуть медленнее, чем x
x
, поэтому на 13!
происходит переполнение как int
, так и uint
, и в unchecked
контексте получится ерунда (не знаю как там Unity работает с числами).
Есть так же ненулевой шанс отхватить при умножении Point
на факториал большого числа (что будет вычислено первым), после чего получить Point
с потерянной точностью (вы используете float
— поля), и уже его делить на оставшиеся факториалы (если я правильно помню приоритет операторов и направление вычисления).
Вы на каждом шаге вычисляете factorial(points.Length - 1)
, хотя его можно было бы закешировать.
Я уже не говорю о том, что вычисление биномиальных коэффициентов можно упростить и избавиться от деления больших чисел, например Ckn = ((k + 1) * (k + 2) * ... * n) / (n -k)!
в случае когда k > n / 2
(для k < n / 2
можно воспользоваться симметрией), что требует меньше вычислительных операций. Так C810 это всего лишь 9 * 10 / 1 / 2 = 45
, а не 3628800 / 40320 / 2
.
Ну и большинство значений как факториала так и биномиального коэффициента можно посчитать в одну прогонку по заданному points.Length
и затем использовать по необходимости.
Ну вы можете использовать double
для вычислений и кастовать к float
когда изменяете transform
объекта, сохраняя точность максимально долго.
Я описал не оптимизации, есть действительно оптимальные способы это считать, я описал элементарную вещь которую стоит держать в голове когда вы начинаете совершать операции над большими числами в цикле.
Как и в моделировании физических процессов для научных робот так и для симуляции в играх неоспоримо важна скорость не теряя точности.
В данном случае, алгоритм вычисления факториала имеет свой большой «плюс» — очень прост и понятен, и не отвлекает от главной цели статьи.
Но, все же, если хотите ускорить или оптимизировать его расчет можно воспользоваться Гамма-функцией (там все очень просто) и двумя аппроксимированными формулами Стирлинга (Stirling) и Рамануджана (Ramanujan).
Замечу, что точное значение они рассчитывают до 11 (Ст.) и 9 (Рам.) соответственно. И вроде бы формула Стирлинга дает лучшее быстродействие.
Что бы «облегчить жизнь», даю ссылку на код C# по вычислению факториала: . Unit-тесты прилагаются и замеры скорости вычисления с помощью разных способов, в том числе реализацию через указатели и небезопасный код и многопоточность при расчете массива факториалов.
Также, замечу, что
написать свой типне нужно, в C# уже давно есть для этого такой тип как BigInteger (неизменяемый), которому не страшны никакие переполнения. А вот и ссылка на него . Я его также реализовал в коде.
Чем смог тем помог, пользуйтесь на здоровье! Удачи!
Немного о графиках, сплайнах и генерации ландшафта