我需要一个简单的函数如何确定Int是否是Haskell中的完美正方形?
is_square :: Int -> Bool
,其确定一个Int N A完美的正方形(是否有一个整数x,使得x * X = N)。
当然我可以只写类似
is_square n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n::Double)
,但它看起来很可怕!也许有一个简单的方法来实现这样的谓词?
我需要一个简单的函数如何确定Int是否是Haskell中的完美正方形?
is_square :: Int -> Bool
,其确定一个Int N A完美的正方形(是否有一个整数x,使得x * X = N)。
当然我可以只写类似
is_square n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n::Double)
,但它看起来很可怕!也许有一个简单的方法来实现这样的谓词?
哦,今天我需要确定一个数字是否是完美的立方体,而类似的解决方案非常慢。
所以,我想出了一个非常聪明的替代
cubes = map (\x -> x*x*x) [1..]
is_cube n = n == (head $ dropWhile (<n) cubes)
很简单。我认为,我需要使用树来进行更快速的查找,但现在我会尝试这种解决方案,也许它对我的任务来说足够快。如果没有,我会适当的数据结构
我不知道这是否会比原来的更快。它需要更多的指令来执行。这可能会更快,具体取决于Haskell如何做'head'/'dropWhile'以及您的数字有多大。 – earlNameless 2010-05-13 17:35:07
它在实践中速度更快。 – 2010-05-13 17:42:12
使用不同的数据结构('Seq','Vector')和一个二进制搜索将可能是更快的秩序 – 2015-08-01 14:40:51
维基百科的article on Integer Square Roots算法可以适应您的需要。牛顿的方法很好,因为它以二次方式收敛,即每一步你得到两倍的正确数字。
如果输入可能大于2^53
,那么我建议您远离Double
,在这之后不是所有整数都可以精确地表示为Double
。
我不需要非常复杂的algorythm,我只是认为有一个简单而美丽的解决方案没有两种类型转换:) – 2010-05-11 03:32:37
@valya:编写'isqrt'函数可以消除类型转换。 – 2010-05-11 20:55:45
我想您所提供的代码是最快的,你会得到:
is_square n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n::Double)
的这段代码的复杂性:一个平方根,一个双乘法,一个投(dbl-> INT)和一个比较。您可以尝试使用其他计算方法来替换sqrt和乘法,只用整数算术和移位,但有可能它不会比一个sqrt和一个乘法更快。
可能值得使用另一种方法的唯一地方是,如果您运行的CPU不支持浮点运算。在这种情况下,编译器可能必须在软件中生成sqrt和double乘法,并且可以在针对特定应用程序进行优化时获得优势。
正如其他答案所指出的那样,大整数仍然存在限制,但除非您打算遇到这些数字,否则利用浮点硬件支持可能比编写自己的算法更好。
我只是认为有一个简单而美观的解决方案,没有两种类型的转换:)好的,谢谢! – 2010-05-11 03:33:09
分析我的应用程序显示在is_square函数中花费了57%的时间:( – 2010-05-11 03:44:58
您可能需要做一些缓存(不要计算相同的整数两次),或者最初预先计算所有整数。 bool [] isSquare = new bool [100000]; for(int i = 1; i
这不是特别漂亮或快,但这里是基于牛顿法的作品(慢)的自由铸造,FPA-免费版任意大的整数:
import Control.Applicative ((<*>))
import Control.Monad (join)
import Data.Ratio ((%))
isSquare = (==) =<< (^2) . floor . (join g <*> join f) . (%1)
where
f n x = (x + n/x)/2
g n x y | abs (x - y) > 1 = g n y $ f n y
| otherwise = y
它也许可以用加速一些额外的数字理论欺骗。
谢谢!但它与我的任务相反 – 2010-05-11 17:17:59
有时编辑答案你不应该划分问题转化成过小零件(如检查is_square
):
intersectSorted [] _ = []
intersectSorted _ [] = []
intersectSorted xs (y:ys) | head xs > y = intersectSorted xs ys
intersectSorted (x:xs) ys | head ys > x = intersectSorted xs ys
intersectSorted (x:xs) (y:ys) | x == y = x : intersectSorted xs ys
squares = [x*x | x <- [ 1..]]
weird = [2*x+1 | x <- [ 1..]]
perfectSquareWeird = intersectSorted squares weird
哦,非常有趣!我会考虑如何使它更适合我 – 2010-05-11 18:57:03
有一个很简单的方法来测试完美正方形 - 从字面上看,你检查数字的平方根是否在其小数部分不是零。
我假设平方根函数返回一个浮点,在这种情况下,你可以做的(伪代码):
func IsSquare(N) sq = sqrt(N) return (sq modulus 1.0) equals 0.0
isSquare b n =(mod'(logBase b n)1.0)== 0.0 - Mod'from Data.Fixed – JayJay 2014-12-21 03:40:07
在另一个回答这个问题评论,您讨论memoization 。请记住,这种技术有助于探针图案表现出良好的密度。在这种情况下,这意味着一遍又一遍地测试相同的整数。你的代码有多大可能重复相同的工作,从而从缓存的答案中受益?
你没有给我们您输入的分布的概念,所以考虑采用了优秀的criterion包快速基准:
module Main
where
import Criterion.Main
import Random
is_square n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n::Double)
is_square_mem =
let check n = sq * sq == n
where sq = floor $ sqrt $ (fromIntegral n :: Double)
in (map check [0..] !!)
main = do
g <- newStdGen
let rs = take 10000 $ randomRs (0,1000::Int) g
direct = map is_square
memo = map is_square_mem
defaultMain [ bench "direct" $ whnf direct rs
, bench "memo" $ whnf memo rs
]
这个工作量可能会或可能不会是一个公平代表什么你正在做,但写的,高速缓存未命中率显得过高:
认为它这样,如果你有一个积极INT n
,那么你基本上干什么g在1 .. n的数字范围上进行二进制搜索,找到第一个数字n'
,其中n' * n' = n
。
我不知道哈斯克尔,但F#应该很容易转换:
let is_perfect_square n =
let rec binary_search low high =
let mid = (high + low)/2
let midSquare = mid * mid
if low > high then false
elif n = midSquare then true
else if n < midSquare then binary_search low (mid - 1)
else binary_search (mid + 1) high
binary_search 1 n
保证是O(log n)的。易于修改完美的立方体和更高的权力。
我非常喜欢这个解决方案。我一直很惊讶,二进制搜索对于不同的事情有多么有用。但是,O(log n)是误导性的。你将执行O(log n)迭代,但是在每次迭代中你都有一个隐藏的mid * mid。平方数大约为O(mlogm)。 m在sqrt(n)上关闭,所以假设m = sqrt(n)。对于m = sqrt(n),这最终的效率实际上是O(log n)* O(m log m)。仍然,二分搜索+1:P – Rubys 2010-05-11 20:06:18
问题指定Haskell中的“Int”是固定精度(通常为32位),所以我更喜欢在问题中使用的浮点方法。如果'N'是一个'Integer'(任意精度),我会使用你的方法。 – finnw 2010-07-23 14:07:06
有一个精彩库包含在arithmoi
包中包含的Haskell中的大多数数论相关问题。使用Math.NumberTheory.Powers.Squares
库。
具体为isSquare'
函数。
is_square :: Int -> Bool
is_square = isSquare' . fromIntegral
图书馆作为图书馆的演进优化,深受人们更专注于效率的审核,那么你或I.虽然目前没有this kind of shenanigans引擎盖下的机制,它可以在未来,获得更多优化。 View the source code了解它是如何工作的!
不要重新发明轮子,在可用时总是使用图书馆。
我正在写有趣的我自己的数字理论库。我的观点是了解我在其中的功能是如何工作的。该库函数的最坏情况是: – Sean 2015-02-27 14:37:57
[确定整数的平方根是否为整数的最快方法](http:// stackoverflow。com/questions/295579 /最快的方式来确定如果一个整数平方根是一个整数) – finnw 2010-07-23 14:02:27