24

直角三角形の斜辺の2乗は、他の2つの辺の2乗の合計に等しくなります。

これがピタゴラスの定理です。辺の長さ「a」と「b」に基づいて斜辺を計算する関数は、sqrt(a * a + b * b)を返します。

問題は、適切なメソッドを実装する任意のタイプで使用できるように、Scalaでそのような関数をどのように定義するかということです。

コンテキストとして、実行していること、および速度、精度、精度、範囲の要件に応じて、Int、Double、Int-Rational、Double-Rational、BigInt、またはBigInt-Rationalタイプで使用する数学定理のライブラリ全体を想像してください。 。

4

4 に答える 4

24

これはScala2.8でのみ機能しますが、機能します。

scala> def pythagoras[T](a: T, b: T, sqrt: T => T)(implicit n: Numeric[T]) = {
     | import n.mkNumericOps
     | sqrt(a*a + b*b)
     | }
pythagoras: [T](a: T,b: T,sqrt: (T) => T)(implicit n: Numeric[T])T

scala> def intSqrt(n: Int) = Math.sqrt(n).toInt
intSqrt: (n: Int)Int

scala> pythagoras(3,4, intSqrt)
res0: Int = 5

より一般的に言えば、特性Numericは事実上、このタイプの問題を解決する方法に関する参照です。も参照してくださいOrdering

于 2009-09-06T05:32:22.943 に答える
18

最も明白な方法:

type Num = {
  def +(a: Num): Num
  def *(a: Num): Num
}

def pyth[A <: Num](a: A, b: A)(sqrt: A=>A) = sqrt(a * a + b * b)

// usage
pyth(3, 4)(Math.sqrt)

これは多くの理由で恐ろしいです。まず、再帰型の問題がありNumます。これは、オプションを整数値に設定してこのコードをコンパイルする場合にのみ許可-Xrecursiveされます(数値には5で十分です)。次に、タイプNumは構造的です。つまり、タイプが定義するメンバーの使用法は、対応するリフレクティブ呼び出しにコンパイルされます。控えめに言って、このバージョンのバージョンは、従来の実装よりも数十万倍も遅く、pythひどく非効率的です。ただし、を定義し、関数が存在するを定義する場合は、構造型を回避する方法はありません。pyth+*sqrt

最後に、最も基本的な問題に行き着きます。それは過度に複雑です。なぜこのように関数を実装するのが面倒なのですか?実際には、適用する必要があるタイプは実際のScala番号だけです。したがって、次のことを行うのが最も簡単です。

def pyth(a: Double, b: Double) = Math.sqrt(a * a + b * b)

すべての問題が解決しました!この関数は、暗黙の変換の驚異のおかげで、タイプDouble、、、Intの値Float、さらには奇妙な値でも使用できます。Shortこの関数は、構造的に型指定されたバージョンよりも技術的に柔軟性が低いことは事実ですが、はるかに効率的で、非常に読みやすくなっています。+とを定義する予期しない型のピタグリアン定理を計算する機能を失った可能性がありますが、*その機能を見逃すことはないと思います。

于 2009-01-28T05:29:38.003 に答える
2

ダニエルの答えに関するいくつかの考え:

に一般化することを実験しました。これは、この関数が関数を提供するのにより適しています。これにより、次のようになります。NumericRealsqrt

def pythagoras[T](a: T, b: T)(implicit n: Real[T]) = {
   import n.mkNumericOps
   (a*a + b*b).sqrt
}

このような汎用関数でリテラル数を使用するのは難しいですが、可能です。

def pythagoras[T](a: T, b: T)(sqrt: (T => T))(implicit n: Numeric[T]) = {
   import n.mkNumericOps
   implicit val fromInt = n.fromInt _

   //1 * sqrt(a*a + b*b)   Not Possible!
   sqrt(a*a + b*b) * 1    // Possible
}

sqrtが 2 番目のパラメーター リストで渡された場合、型推論はより適切に機能します。

パラメータabオブジェクトとして渡されますが、@specialized でこれを修正できます。残念ながら、数学演算にはまだいくらかのオーバーヘッドがあります。

mkNumericOps をインポートしなくてもほとんどできます。悔しい思いで近寄ってきました!

于 2010-03-05T16:48:17.587 に答える
0

java.lang.Mathには次のメソッドがあります。

public static double hypot (double x, double y)

javadocsが主張するもの:

中間のオーバーフローまたはアンダーフローなしでsqrt(x2 + y2)を返します。

src.zipを調べると、Math.hypotはネイティブメソッドであるStrictMathを使用しています。

public static native double hypot(double x, double y);
于 2010-03-05T14:25:43.037 に答える