2016-05-06 7 views
15

私はList<string>に二重の配列に変換するには、次の方法があります:C#持つDouble.toString()パフォーマンス上の問題

List.Addを(行う
static Dest Test(Source s) 
    { 
     Dest d = new Dest(); 

     if (s.A24 != null) 
     { 
      double[] dd = s.A24; 

      int cnt = dd.Length; 

      List<string> lst = new List<string>(); 

      for (int i = 0; i < cnt; i++) 
       lst.Add(((double)dd[i]).ToString()); 

      d.A24 = lst; 
     } 
     else 
     { 
      d.A24 = null; 
     } 

     return d; 
    } 

)をループ内で最速の方法のように思える私に従っベンチマークはさまざまなLINQとConvertのすべての技を打ち破っています。

これはです。実際はです。 100万コール(すべてのCPU、64ビットを好む)に対して2400ms。だから私はそれをもっと速くするための様々な方法を試していました。明らかに私がソースやdestリストなどをキャッシュできないと仮定しましょう。

とにかく私はここで奇妙なものを見つけました... lst.Add()行をdouble型ではなく小数型にキャストするように変更すると、はるかに高速です。 900ms対2400ms。

はここ

1)小数点は、ダブル、その後、より高い精度を持っている私の質問ですので、私は正しいタイプキャストでは何も、失うべきではないのですか?

2)なぜDecimal.ToString()はDouble.ToString()よりもずっと速いのですか?

3)これは合理的な最適化ですか、これが私をかまえるために戻ってくる重要な詳細が欠けていますか?

私はもう少しメモリを使い切ることに心配していません。私はパフォーマンスだけを心配しています。

だけ使用して、この時点でのテストデータのための洗練された何も、:

s.A24 = new double[] { 1.2, 3.4, 5.6 }; 
+1

あなたは[mcve]を投稿できますか?ところで、dd.Lengthを使うことができるときにLinQを使って 'dd.Count()'を呼び出す必要はありません。 – nvoigt

+0

'lst.AddRange(dd.Select(x => x.ToString()));'これより高速ですか? –

+2

値は何か、それらから必要とされる精度はどれくらいあり、どの形式が必要ですか? (私は途中で同じ振る舞いを見ています...) –

答えて

2

何が価値があるのは、私は次のことを実行し、異なる結果を得た、小数は通常、少し時間がかかる(しかし、両方の呼び出しでlst.Add()とnumber.ToString()の呼び出しはほぼ同等です)。

あなたのコードにはどのような種類のコレクションがありますか?あなたが見ている追加のオーバーヘッドが実際にキャスティングにあるか、現在見ていないものであれば、私は驚くことはありません。

var iterations = 1000000; 

var lst = new List<string>(); 

var rnd = new Random(); 
var dblArray = new double[iterations]; 
for (var i = 0; i < iterations; i++) 
    //INTERESTING FINDING FROM THE COMMENTS 
    //double.ToString() is faster if this line is rnd.NextDouble() 
    //but decimal.ToString() is faster if hard-coding the value "3.5" 
    //(despite the overhead of casting to decimal) 
    dblArray[i] = rnd.NextDouble(); 

var sw = new Stopwatch(); 
sw.Start(); 
for (var i = 0; i < iterations; i++) 
    lst.Add(dblArray[i].ToString()); 
sw.Stop(); 
//takes 280-300 MS 
Debug.WriteLine("Double loop MS: " + sw.ElapsedMilliseconds); 

//reset list 
lst = new List<string>(); 
sw.Restart(); 
for (var i = 0; i < iterations; i++) 
    lst.Add(((decimal)dblArray[i]).ToString()); 
sw.Stop(); 
//takes 280-320 MS 
Debug.WriteLine("Decimal loop MS: " + sw.ElapsedMilliseconds); 
+1

あなたは10進*算術*をやっていますが... OPはそうではありません。彼らは単に既存の 'double'値をキャストしています。 –

+1

2番目の 'sw.Start()'呼び出しが間違っています。それを 'Restart()'に変更してください。 –

+0

あなたのすべてが正しいです!ありがとう!私はときどきSOの答えであまりにも速く/不愉快にコード化します。 : -/ – Colin

1

DecimalとDoubleはしばしば混乱し交換されますが、プロセッサレベルでは全く異なる動物です。 Double.ToString()のコードを書くことを想像しなければならない場合、私は問題を見ることができます...それは難しいです。 Decimal.ToString()のコードを書くのはInt32.ToString()よりも難しいはずです。 Int32.ToString()とDecimal.ToString()を比較すると、結果が非​​常に近いことがわかります。

FYI:DoubleとFloat(Single)は正確ではなく、Doubleで多くの数値を表現することはできません。あなたの例では、実際には1 + 1/5の1.2を与えます。それは真の二重として存在することはできません(たとえVS IDEがそれをカバーしていても)。 1.1999999999999998のようなものが得られます。パフォーマンスが必要な場合は、小数点を使用します。

+0

私のシステムでは、 'Decimal.ToString(CultureInfo.InvariantCulture)'は 'Int32.ToString(CultureInfo.InvariantCulture)'の約1.6倍です。 'Double.ToString(CultureInfo.InvariantCulture)'は約3.5倍遅い(単純な 'Stopwatch'フェンスループでテストされ、' List.Add'は関係しません)。だからあなたは遠く離れているわけではありませんが、「非常に近い」というのはちょっとした過ぎです。 –

+0

ダーン...ええ、小数点以下のキャストを行うことは、そこのケースの99%で動作すると思います。小数点は完全な精度で空間点を保持することさえできます。私はちょうど二重のオーバーヘッドで生きなければならないと思う。 .NETは実際にはCLR内のネイティブメソッドを呼び出して書式設定を行うので、Double.ToString()のコードを実際に見ることはできません。 – SledgeHammer

+0

また、他の興味深いメモの1つは、32ビットの優先度を指定すると、コードは833msと2400msの間でかなり高速です。 – SledgeHammer

0

2)なぜ、Decimal.ToString()がDouble.ToString()よりもずっと速いのですか?

  1. Double.ToString()は、実際にははるかに複雑であるため。Decimal.ToString()Double.ToString()のコア実装を比較すると、の精度はオンデマンドであるのに対し、Decimal.ToString()は固定精度を持ちます。 DoubleIEEE floating point definitionであり、Decimalよりはるかに複雑です。

  2. 現在のDouble.ToString()実装は、Windowsでは_ecvtsnprintf on Linuxに依存しています。それらは非効率的です(特にLinux実装の場合)。効率的な方法でDouble.ToString()を書き換えて_ecvtsnprintfの依存関係を取り除くためのin-progress PRがあります。