F# でオーバーフローをチェックしない sum


F# の sum 関数はオーバーフローチェックします。なので例えば次のコードはオーバーフロー例外が出ます。

Seq.sum <| seq { 1 .. 1000000 }  // OverflowException

F# は適切な型を宣言すればいろいろな関数が利用できます。整数をラップする型を作ってオーバーフローしない方法を試みます。

[<Struct>]
type Int32 (value : System.Int32) =
   member this.Value = value
   static member Zero = Int32 (0)
   static member One = Int32 (1)
   static member (+) (x : Int32, y : Int32) = Int32 (x.Value + y.Value)

.NET Framework 標準の型と名前がかぶっているのは行儀が悪い作法ですが,ここでは気にしないでください。これを使って, sum を実行してみます。

Seq.sum <| seq { Int32 (1) .. Int32 (1000000) }
(* |> fun s -> s.Value  // 1784293664 *)

オーバーフローしても問題なく和が計算できました。

おまけ

上記の方法はパフォーマンスが悪いです。次のようにした方が 8 倍くらい速いです。

Seq.fold (+) 0 <| seq { 1 .. 1000000 }  // 1784293664