正整数n的整数平方根是正方形为的最大整数 小于或等于n。 (例如,7的整数平方根为2,而9的整数平方根为3)。
这是我的尝试:
intSquareRoot :: Int -> Int
intSquareRoot n
| n*n > n = intSquareRoot (n - 1)
| n*n <= n = n
我猜它不起作用,因为n随着递归的增加而减少,但由于这是Haskell,你不能使用变量来保留原始的n。
答案 0 :(得分:7)
...但由于这是Haskell,你不能使用变量来保留原始的n。
我不知道是什么让你这么说。以下是如何实现它:
intSquareRoot :: Int -> Int
intSquareRoot n = aux n
where
aux x
| x*x > n = aux (x - 1)
| otherwise = x
这足以解决问题,但这不是一个非常有效的实现。在Haskell's wiki上可以找到更好的一个:
(^!) :: Num a => a -> Int -> a
(^!) x n = x^n
squareRoot :: Integer -> Integer
squareRoot 0 = 0
squareRoot 1 = 1
squareRoot n =
let twopows = iterate (^!2) 2
(lowerRoot, lowerN) =
last $ takeWhile ((n>=) . snd) $ zip (1:twopows) twopows
newtonStep x = div (x + div n x) 2
iters = iterate newtonStep (squareRoot (div n lowerN) * lowerRoot)
isRoot r = r^!2 <= n && n < (r+1)^!2
in head $ dropWhile (not . isRoot) iters
答案 1 :(得分:5)
您可能没有可编辑的变量,但可以递归传递参数....
intSquareRoot :: Int -> Int
intSquareRoot n = try n where
try i | i*i > n = try (i - 1)
| i*i <= n = i
给
ghci> intSquareRoot 16
4
ghci> intSquareRoot 17
4
答案 2 :(得分:1)
您的初始尝试以及对user2989737的良好更正会尝试从n到解决方案的每个数字。对于大数字来说非常慢,复杂度是O(n)。从0开始到解决方案会更好,这会将复杂性提高到O(sqrt n):
intSquareRoot :: Int -> Int
intSquareRoot n = try 0 where
try i | i*i <= n = try (i + 1)
| True = i - 1
但是这里有一个使用巴比伦方法的更有效的代码(Newton&#39方法应用于平方根):
squareRoot :: Integral t => t -> t
squareRoot n
| n > 0 = babylon n
| n == 0 = 0
| n < 0 = error "Negative input"
where
babylon a | a > b = babylon b
| True = a
where b = quot (a + quot n a) 2
它没有Pedro Rodrigues解决方案(GNU的多精度库算法)快,但它更简单,更容易理解。它还需要使用内部递归才能保留原始n。
为了使其完整,我将其推广到任何积分类型,检查负输入,并检查n == 0以避免除以0.
答案 3 :(得分:0)
提议的解决方案不起作用,因为在每个递归调用中都与n
参数重叠。
以下解决方案使用二进制搜索并在O(log(n))
中找到整数平方根:
intSquareRoot :: Int -> Int
intSquareRoot n = bbin 0 (n+1)
where bbin a b | a + 1 == b = a
| otherwise = if m*m > n
then bbin a m
else bbin m b
where m = (a + b) `div` 2
在每个递归调用([a,b)
或[a,m)
)上将范围[m,b)
除以2,这取决于平方根的位置。