1

この関数のようにベクトルを正規化しています:

member this.Normalize =
    if  this.Length > _zerotolerance  then
        let inv:float = 1.0 / this.Length 
        this.x <- this.x *= inv   // overloaded
        this.y <- this.y *= inv   // overloaded

ただし、浮動小数点数の乗算代入演算子 *= はデフォルトでは使用できないため、作成する必要がありました。

MSDN http://msdn.microsoft.com/en-us/library/dd233204%28v=vs.110%29によると、次の方法で演算子をオーバーロードする必要があります。

static member ( *= ) (arg1 : type, arg1: type) = ...code etc...

そのため、次のように、F# コードファイルで乗算代入のために次の演算子をオーバーロードしました。

// Operator
static member ( *= ) ( v1:vector2, v2:vector2 ) =
   v1.x <- v1.x + v1.x * v2.x 
   v1.y <- v1.y + v1.y * v2.y 

static member ( *= ) ( v1:vector2, v2:float )  = 
   v1.x <- v1.x + v1.x * v2
   v1.y <- v1.y + v1.y * v2 

// Operator
static member ( *= ) ( f1:float, f2:float ) = 
    f1 <- f1 + f1 * f2

そして、それはうまくいかないようです。演算子をオーバーロードした後でも、次の問題があります。

vector2.fs(107,36): エラー FS0001: タイプ 'float' は '*=' という名前の演算子をサポートしていません

そのため、演算子 *= はフロートに対して機能しません。ここで失敗しています(正規化機能):

this.X <- this.X *= inv

演算子の他のオーバーロードを確認するために、Vector2 のテスト関数を一時的に作成しました。

member this.MultiplyAssignmentTest_1(v1:vector2,v2:vector2):vector2 = v1 *= v2

member this.MultiplyAssignmentTest_2(v1:vector2,v2:float):vector2 = v1 *= v2

オペレーターはVector *= VectorVector *= Floatの両方のテストに合格しましたが、 Float *= Float を実行しようとすると引き続き失敗します

3 番目のテスト関数 - float *= float : まったく同じエラーで完全に失敗します。

member this.MultiplyAssignmentTest_3(v1:float,v2:float):float = v1 *= v2

OFC 私はいつでも と書くことができますがthis.X <- This.X + This.X *= inv、短い数式には問題ありません。しかし、これを使って多くのベクトル化された数学を書き始めると、それはあまり経済的ではありません。

  1. 私は何を台無しにしましたか?なんらかの方法でオーバーロードを本当に台無しにしたのでしょうか、それとも私が知らないバグがありますか?

  2. Vector2 *= Float では機能するのに、Float *= Floatでは機能しないのはなぜですか?

  3. それとも、自分では気付いていないタイプミス/大文字小文字のエラーがあるのでしょうか?

4

2 に答える 2

2

ジョンが言ったように、ミュータブルでの作業は避けたほうがいいです。もう1つの問題は、floatの演算子(* =)をオーバーロードしたいのですが、float Typeの定義がないため、クラスの定義でそれを実行しようとしています。パラメータはクラスのタイプ(vector2)です。

他の2つのオーバーロードは、オーバーロードに関係する少なくとも1つのパラメーターがタイプ(vector2)であり、解決されるため、正常に機能します。

グローバルレベルで(= *)を定義できますが、vector2では機能しないため、グローバルレベルでの定義ですべてのオーバーロードを指定する必要があります。

オーバーロードに独立したクラスを使用するこのコードを試すことができます。

type vector2 = {x:float; y:float} with

// Operator
    static member ( *= ) ( v1:vector2, v2:vector2 ) =
       {x = v1.x + v1.x * v2.x; y = v1.y + v1.y * v2.y }

    static member ( *= ) ( v1:vector2, v2:float )  = 
       {x = v1.x + v1.x * v2; y = v1.y + v1.y * v2 }

type Overloads = Overloads with
    static member (?<-) (a:vector2, Overloads, b:vector2) = a *= b
    static member (?<-) (a:vector2, Overloads, b:float)   = a *= b
    static member (?<-) (a:float  , Overloads, b:float)   = a *  b

let inline ( *= ) f1 f2 =  f1 ? (Overloads) <- f2

// now you can add more methods for vector2 using the global definition of ( *=)
type vector2 with 
    static member Length (v1:vector2) = sqrt( v1.x ** 2.0 + v1.y ** 2.0)
    // more methods

このトリックを行うと、floatとvector2の両方に(* =)を使用できます。また、ミュータブルを削除したことにも注意してください。

于 2012-06-22T07:58:45.357 に答える
2

これも機能します:

let inline ( *= ) (p : byref<_>) x = p <- p * x

[<Literal>]
let _zerotolerance = 1e-3

type A(x0, y0) =
    let mutable x = x0
    let mutable y = y0

    member __.Length = sqrt (x * x + y * y)

    member this.Normalize =
        if this.Length > _zerotolerance  then
            let inv:float = 1.0 / this.Length 
            &x *= inv
            &y *= inv
于 2012-06-22T10:56:07.640 に答える