2017-05-05 3 views
1

私は整数値の平方根を行う必要があるF#でプログラムを構築しています。 私はキャストを使用しないでこれを行うことを可能にする機能を何も発見しておらず、見つけましたint -> floatF#Square Root on Int

不要なキャストなしで整数の平方根を作ることができる関数はありますか?

+2

ビットを踏み戻す:最初に整数の平方根をどのように定義しますか? 8の平方根とは何ですか?それは2(2.828の床)または3(2.828のceil)または3(2.828のMath.round)でなければなりませんか?明確に定義されておらず、アプリケーションによっては、それらのオプションの1つを選択する必要があります。 –

+2

アントンの質問は良いことです。私は別の質問があります:**なぜあなたはこれを必要としますか? (なぜあなたはこれが必要だと思いますか?)なぜ誰かがXが必要な理由を説明せずにXを求め、Xが難しい/不可能である(例えば整数の平方根関数)彼らは本当にYをしようとしていると思うし、XはYを行う唯一の方法だと思っている。だから、 "さて、XをせずにYに行くもう一つの方法があります。それはしばしば難しい/不可能なXより優れた解決策です。 – rmunn

+0

文字通り、ある種のテストでは、int型の平方根を求めています。 – eisterman

答えて

3

あなただけの整数を受け取り、浮動小数点としての平方根を返し、その後、浮動小数点にint型に変換するためにfloat機能を使用して、sqrtを呼び出すと、移動するための方法で機能する場合:

原則として、F#はこの変換を暗黙的に許可することができますが、コメントの議論のように、整数の平方根がどのようなものであるべきなのか明確ではないため、そうしないと思います。 C#ではMath.Sqrt(n)と書くことができますが、これはC#が暗黙的にintからfloatへの変換をプログラム内で許可するためです。

整数を返す整数の場合は平方根が必要な場合は、(コメントで説明したように)それを行う標準的な方法はないので、必要な機能を実装するのはあなた次第です。

0

intの入力がなぜ制限されているのか理解するのは難しいですが、それが重要であれば、除算&征服アルゴリズムを使用できます。これは、ハードウェア浮動を伴う任意のCPUアーキテクチャでは、sqrt (float n)よりもはるかに遅いです。

let isqrt n = 
    let rec loop b e = 
    let i = (b + e) >>> 1 
    let i2 = i*i 
    if i2 = n then 
     i 
    else 
     let nb, ne = 
     if i2 > n then 
      b, i 
     else 
      i, e 
     if nb = b && ne = e then 
     // Check i - 1 and i + 1 to see if either is a better fit than i 
     let imin = i - 1 
     let imax = i + 1 
     let i2min = imin*imin 
     let i2max = imax*imax 
     let d  = n - i2 |> abs 
     let dmin = n - i2min |> abs 
     let dmax = n - i2max |> abs 
     if d < dmin && d < dmax then 
      i 
     elif dmin < dmax then 
      imin 
     else 
      imax 

     else 
     loop nb ne 
    loop 1 n 

open FsCheck 

let isqrtProperty n = 
    n > 1 ==> fun() -> 
    let r  = isqrt n 
    let rmin = r - 1 
    let rmax = r + 1 

    let r2 = r*r 
    let rmin2 = rmin*rmin 
    let rmax2 = rmax*rmax 

    let d  = n - r2  |> abs 
    let dmin = n - rmin2 |> abs 
    let dmax = n - rmax2 |> abs 

    r >= 0 && d <= dmin && d <= dmax 

[<EntryPoint>] 
let main argv = 
    let config = { Config.Quick with MaxTest = 10000; MaxFail = 100000 } 
    Check.One ("isqrt property", config, isqrtProperty) 
    0