2012-03-26 12 views

答えて

13

それは、整数オーバフローしないことが非常に重要である場合は、あなたがあなた自身のオーバーフローを引く操作を定義することができるが、例えば:

def +?+(i: Int, j: Int) = { 
    val ans = i.toLong + j.toLong 
    if (ans < Int.MinValue || ans > Int.MaxValue) { 
    throw new ArithmeticException("Int out of bounds") 
    } 
    ans.toInt 
} 

あなたはこれをオンにするエンリッチあなたのライブラリパターンを使用することができる可能性が演算子に; JVMが正しくエスケープ解析を行うために管理している場合、あなたはそれのためにペナルティのあまりを得ることはありません。例えば

class SafePlusInt(i: Int) { 
    def +?+(j: Int) = { /* as before, except without i param */ } 
} 
implicit def int_can_be_safe(i: Int) = new SafePlusInt(i) 

scala> 1000000000 +?+ 1000000000 
res0: Int = 2000000000 

scala> 2000000000 +?+ 2000000000 
java.lang.ArithmeticException: Int out of bounds 
    at SafePlusInt.$plus$qmark$plus(<console>:12) 
    ... 

それはが非常に重要でない場合は、標準的な単体テストやコードレビューなどは大多数のケースで問題を捉えるはずです。 BigIntを使用することは可能ですが、計算を100倍ほど遅くし、Intを取る既存のメソッドを使用する必要がある場合は役に立ちません。

+0

こんにちはRex、迅速な返信をいただきありがとうございます!合理的な解決策がありますが、いくつかの再要因を必要とするかもしれません。複雑なタイプのシステムを考慮して、標準の「演算子」関数にオーバーフローチェックフラグを追加するIntegerベースクラスを改ざんすることはどれほど難しいでしょうか? – IODEV

+0

Btw、 "+ +?+" "に関して、Scalaのネーミングコンバージョンが標準で使用されるべきですか? /事前にお礼します – IODEV

+0

@IODEV - あなたはラッパークラスを追加することができますが、実際にはJVMの 'int'プリミティブにマップされているため、特別なコンパイラマジックをたくさん持っているので、ベースクラスを賢明に改ざんすることはできません。 「?」の選択は私によって恣意的であった。 '+'で始めると演算子の優先順位は同じに保たれます。対称が好きです(そして他のものは十分ですので、これは私には分かりませんが、少なくとも慣れています)ので、最後に別の '+' 。 '+ @'も同様に動作します。 –

4

共通一般的な整数オーバーフローについては、プログラマは問題が存在するかどうかを知り、発生する可能性のあるケースを監視し、オーバーフローが発生するように適切なチェックを行うか、 (a * b)/ cではなく*(b/c)をするようなことが起きる。プロジェクトで単体テストが使用されている場合は、オーバーフローが発生するように強制するケースが含まれます。

それ以上のものを必要としているチームのコードは見たことがないので、ほぼすべてのソフトウェアで十分です。

オーバーフローを防ぐために実際には正直なスパゲッティモンスターが必要だと私は見てきましたが、起こったように見える行ごとにオーバーフローが起こり得ないことを証明しました。

+3

アンダーフローは、 'a *(b/c)'があなたに与える悪影響も同じです。一般的に '((a * b).toLong/c).toInt'や' Double'と等価でなければなりません。 –

+0

オーバーフローと同様に、アンダーフローに対処する方法は、プログラマがその可能性を認識し、彼または彼女の判断を使用することです。あなたの議論を広げ、数学を行うたびに結果を絞り込むことは、パフォーマンスやコードの読みやすさに悪影響を及ぼし、最終的な結果がオーバーフローまたはアンダーフローする場合は機能しません。 – mjfgates

+0

コードがどの程度パフォーマンスに重要かによって異なります。非常に低い性能は、任意精度の整数で得ることができます。ディーセント・パフォーマンスは、拡大/縮小によって得ることができます。高性能を実現するためには、プログラマは許容値がどのようなものなのかを理解する必要があるため、拡大/縮小は不要です。何とか分割を完全に避けることができれば、超高性能が最も効果的です。 –

6

あなたはScalaのを(と私はあなたがいると仮定していたタグに基づいて)使用している場合、1つの非常に一般的な解決策はscala.math.Integral型クラスに対するあなたのライブラリのコードを記述することです:

def naturals[A](implicit f: Integral[A]) = 
    Stream.iterate(f.one)(f.plus(_, f.one)) 

あなたはできるもよりよい構文のコンテキスト境界を使用してIntegral.Implicits

import scala.math.Integral.Implicits._ 

def squares[A: Integral] = naturals.map(n => n * n) 

必要に応じて今あなたがのインスタンス以来、IntまたはLongまたはBigIntのいずれかでこれらのメソッドを使用することができますは、それらのすべてのために存在する:

scala> squares[Int].take(10).toList 
res0: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) 

scala> squares[Long].take(10).toList 
res0: List[Long] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) 

scala> squares[BigInt].take(10).toList 
res1: List[BigInt] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100) 

ライブラリのコードを変更する必要はありません:オーバーフローがそうでない関心とIntここだけLongまたはBigIntを使用しています。

あなたはパフォーマンスに関していくらかのペナルティを支払うでしょうが、一般性とIntまたはBigIntの決定を延期する能力は価値があるかもしれません。

+0

「Long」を使用すると、再びオーバーフロー問題が発生します。測定単位を変数に結びつけるためには、+1 – Jus12

3

@mjfgatesが指摘しているように、単純なマインドフルネスに加えて、スケーリング小数(非浮動小数点)の現実の数量を扱う際に私が常に使用する2つのプラクティスがあります。これはあなたの特定のアプリケーションのためのポイントではないかもしれません - 前もって謝罪していない場合。

最初に、複数の測定単位が使用されている場合、値はそれらが何であるかを明確に識別する必要があります。これは、命名規則または各測定単位に別のクラスを使用することによって行うことができます。私はいつも名前を使用しました。すべての変数名の接尾辞です。 errors from confusion over the unitsを削除することに加えて、対策が単なる数字と考えられる可能性が低いため、オーバーフローについて考えることを推奨します。

第2に、私の最も頻繁に発生するオーバフローの原因は、多くの有効数字が必要なときに通常小節から小節へのリサイズです。たとえば、cmからインチへの換算係数は0.393700787402です。オーバーフローと有効桁数の両方の損失を避けるためには、適切な順序で乗算し、分割するように注意する必要があります。私は長い時間でこれを行っていないが、私は何をしたいことは何かれると信じて:

帳から、Rational.scalaに追加:

def rescale(i:Int) : Int = { 
     (i * (numer/denom)) + (i/denom * (numer % denom)) 

を次に、specs2からの結果(短縮として取得しますテスト):

val InchesToCm = new Rational(1000000000,393700787) 
    InchesToCm.rescale(393700787) must_== 1000000000 
    InchesToCm.rescale(1) must_== 2 

これは、負のスケーリングファクタを丸めたり、処理したりしません。 プロダクション実装では、numer/denomnumer % denomを除外したい場合があります。

+0

+1。 「文字数」と「バイト数」を混ぜようとすれば、DBCSからUnicodeへの変な変態に苦しんでいたとき、私のベーコンは1年保存されていました。 – mjfgates

関連する問題