I\'m just learning haskell (on my own, for fun) and I\'ve come up against a wall.
My Question:
How can I define a function
flrt = (floor . s
As copumpkin remarked, it might actually be a bad idea to convert to floating point here, because this comes with loss of precision and therefore might, even with rounding, yield incorrect results for sufficiently large integer inputs.
I assume all numbers you're dealing with will at least be small enough that there is some floating-point representation for them, e.g. all are < 10300. But, for instance
Prelude> round(sqrt.fromInteger$10^60 :: Double) ^ 2
1000000000000000039769249677312000395398304974095154031886336
Prelude> {- and not -} 10^60 {- == (10^30)^2 == (sqrt$10^60) ^ 2 -}
1000000000000000000000000000000000000000000000000000000000000
Which is way off, in terms of absolute difference. Still it's certainly a rather good approximation relative to the numbers themselves, so you can use it as a quickly determined starting point for an algorithm to find the exact result. You can implement Newton/Raphson (in this case AKA Heron) with Integer
s:
flrt :: Integer -> Integer -- flrt x ≈ √x, with flrt x^2 ≤ x < flrt(x+1)^2
flrt x = approx (round . (sqrt::Double->Double) . fromInteger $ x)
where approx r
| ctrl <= x, (r+1)^2 > x = r
| otherwise = approx $ r - diff
where ctrl = r^2
diff = (ctrl - x) // (2*r) -- ∂/∂x x² = 2x
a//b = a`div`b + if (a>0)==(b>0) then 1 else 0 -- always away from 0
This now works as desired:
*IntegerSqrt> (flrt $ 10^60) ^ 2
1000000000000000000000000000000000000000000000000000000000000
The division always away from 0 in the Newton-Raphson correction is here necessary to prevent getting stuck in an infinite recursion.