В настоящее время я экспериментирую с F #. Статьи, найденные в Интернете, полезны, но как программист на C # я иногда сталкиваюсь с ситуациями, когда я думал, что мое решение поможет, но оно не помогло или помогло частично.
Так что мое незнание F # (и, скорее всего, того, как работает компилятор), вероятно, является причиной того, что я иногда полностью ошеломлен.
Например, я написал программу на C # для определения точных чисел. Он использует известную форму доказательства Евклида, что совершенное число может быть образовано из простого числа Мерсенна 2p − 1 (2p − 1) (где 2p-1 - простое число, а p обозначается как степень).
Поскольку с помощью F # указано, что '**' можно использовать для вычисления мощности, но с плавающей точкой, я попытался создать простую функцию с оператором сдвига битов (<<<) (обратите внимание, что я редактировал этот код для указания на необходимость):
let PowBitShift (y:int32) = 1 <<< y;;
Однако при запуске теста и поиске улучшений производительности я также попробовал форму, которую я помню по использованию Miranda (также язык функционального программирования), которая использует рекурсию и шаблон сопоставитель для расчета мощности. Основное преимущество заключается в том, что я могу использовать переменную y как 64-битное целое число, что невозможно со стандартным оператором битового сдвига.
let rec Pow (x : int64) (y : int64) =
match y with
| 0L -> 1L
| y -> x * Pow x (y - 1L);;
Оказывается, эта функция на самом деле быстрее, но я (пока) не могу понять, почему. Возможно, это менее интеллектуальный вопрос, но мне все же любопытно.
Тогда возникает второй вопрос: при вычислении совершенных чисел вы сталкиваетесь с тем фактом, что int64 не может отображать пересечение больших чисел после нахождения 9-го совершенного числа (которое формируется из степени 31). Я пытаюсь выяснить, можете ли вы использовать объект BigInteger (или тип bigint), но здесь мои знания F # немного блокируют меня.Можно ли создать функцию управления мощностью, которая принимает оба аргумента как bigint?
В настоящее время у меня есть это:
let rec PowBigInt (x : bigint) (y : bigint) =
match y with
| bigint.Zero -> 1I
| y -> x * Pow x (y - 1I);;
Но выдает ошибку, что bigint.Zero не определен. Так что я тоже что-то делаю не так. 0I не принимается в качестве замены, так как выдает следующую ошибку:
Non-primitive numeric literal constants cannot be used in pattern matches because they
can be mapped to multiple different types through the use of a NumericLiteral module.
Consider using replacing with a variable, and use 'when <variable> = <constant>' at the
end of the match clause.
Но средство сопоставления шаблонов не может использовать оператор 'when'. Есть ли другое решение для этого?
Заранее спасибо и простите за мой длинный пост. Я лишь пытаюсь как можно яснее выразить свои «проблемы».