Как насчет использования математических свойств журнала - что-то вроде
{-# LANGUAGE ScopedTypeVariables #-}
logBaseRational :: forall a . (RealFloat a, Floating a) => Rational -> Rational -> a
logBaseRational k n | isInfinite (fromRational n :: a) = logBaseRational k (n/k) + 1
logBaseRational k n | isDenormalized (fromRational n :: a) = logBaseRational k (n*k) - 1
logBaseRational k n = logBase (fromRational k) (fromRational n)
Что-то более эффективное можно сделать, если вам нужно обрабатывать действительно большие числа, но это должно быть сделано для интересующего вас диапазона.
Использование ScopedTypeVariables
просто для того, чтобы гарантировать, что isInfinite
и isDenormalized
тесты выполнены в правильном типе.
Кроме того, isDenormalized
не является полнымпроверить нижний предел диапазона - вам нужно проверить и это (из-за проблем с потерей точности), а также то, является ли преобразованное значение 0
, если не преобразованное значение - но, так как этот вопрос о большомтолько цифры, это не важно, я просто добавил, чтобы мой ответ был более общим.