2016-08-11 8 views
5

私は貪欲アルゴリズムを使ってクライアントに変更を返すために必要なコインの数を決定する非常に簡単なプログラムを作成していました。 アルゴリズムは本当に明白です。あなたが使用できる大きなコインを決定し、その値を変更から減算し、コインカウンタを更新する必要があります。いくつかの文と条件を持つ単一のループは、いくつかの単純なループよりも優れていますか?

私は2つの本当に似た実装を考えました。

注:changeIntは変更を100倍して整数に変換したものです。

1)シングル "複雑な" ループ

while(changeInt != 0) { 
     if(changeInt - 25 >= 0){ 
      changeInt -= 25; 
      coins++; 
     } 
     else if(changeInt - 10 >= 0){ 
      changeInt -= 10; 
      coins++; 
     } 
     else if(changeInt - 5 >= 0){ 
      changeInt -= 5; 
      coins++; 
     } 
     else if(changeInt - 1 >= 0){ 
      changeInt -= 1; 
      coins++; 
     } 

    } 

2)複数の単純なループ今

while(changeInt - 25 >= 0) 
    { 
     changeInt -= 25; 
     coins++; 
    } 
    while(changeInt - 10 >= 0) 
    { 
     changeInt -= 10; 
     coins++; 
    } 

    while(changeInt - 5 >= 0) 
    { 
     changeInt -= 5; 
     coins++; 
    } 

    while(changeInt - 1 >= 0) 
    { 
     changeInt -= 1; 
     coins++; 
    } 

、私はパフォーマンスはおそらくアルゴリズムいるので、どちらの場合も、同様のになります知っています同じですが、私はどちらのアプローチが良いのだろうと思っていました。

私が思いついた最初のアイデアは、最初のアイデアでした。そして、私は2番目の方法を考えました。それは直感的に私にとっては良いようです。

が、私は本当に私の正確なシナリオを気にしない、私は一般的なもので、より興味が(いくつかのより複雑なループ対いくつかの単純なループ)

1)パフォーマンスの面で優れているアプローチは?

2)少なくとも巨大な数値で作業する場合は、違いが目立っていますか?

3)1つのアプローチは、他のアプローチよりもかなり読みやすいですか? (私がここでそれを聞くことができるか分からない)

ありがとう!

+1

@mauroSabella: 'changeInt> = X'ではなく' chageInt - X> = 0'とする理由で、一時変数を追加していますか?彼らは同等です、それは本当に文体的な質問ですか?なぜあなたはあなたがやったようにそれをすることを選んだのですか? – rjp

+1

@trincotどういう意味ですか?私は同じ結果を得る。なぜあなたはアルゴリズムが同じではないと言っていますか?両方とも私が見ることができるものと全く同じことを同じ順序で行います。 – mauroSabella

+0

あなたは正しいです。私は最初のコードブロックを誤って判断しました。 – trincot

答えて

1

説明したループの手法の中から選択する必要がある場合は、2番目の方法が推奨されます(わずかなバリエーションがあります)。それはよりクリーンで、ほとんどの場合、不必要なテストを避けます。 「 - X changeIntは」決してラップアラウンドしない

はここで、これは提供しています

while(changeInt >= 25) { 
    changeInt -= 25; 
    coins++; 
} 

while(changeInt >= 10) { 
    changeInt -= 10; 
    coins++; 
} 

while(changeInt >= 5) { 
    changeInt -= 5; 
    coins++; 
} 

while(changeInt > 0) { 
    changeInt -= 1; 
    coins++; 
} 

主な利点は、それがいることを保証するのに役立つということです...わずかな変化です。あなたの記事に書かれていることから、それが問題になることはまずありませんが、型が符号付き整数から符号なし整数に変更された場合は、バグの場所を特定しようとしている可能性があります。

また、除算とモジュラス演算子の組み合わせを使用して変更を計算し、ループを回避することもできます。

これが役に立ちます。

+0

ありがとうございます。モジュラス演算子を使用する可能性があるので、バリエーションについてはまったく正しいです。しかし、私は、多くの単純なループではなく、複雑なループを使用するという一般的な考えにもっと興味があります。私は2番目のアプローチが全体的に(私の場合は)比較回数が少なくて済みますので、より良いと思っていますが、これがどのようにパフォーマンスに影響するかは分かりません。巨大な数値を扱うときに目立った違い(小さなものさえ)がありますか、それとも本当に読みやすさの問題ですか? (もちろんモジュラスを使う方が良いかもしれませんが、私は比較に興味があります) – mauroSabella

+1

@mauroSabella:あなたのコードで他のものよりもパフォーマンスが優れていることをはっきりと確かめるまで、重要なのは大きなO表記です。および可読性。 –

0

あなたが言ったように、両方ともかなり似ています。私が最初のものを好む読みやすさについて話しているのですが(それは主観的意見です)。

私たちがパフォーマンスで考えると、IMHOは前のモデルより少し速いです。

1)シングル "複雑な" ループ(およそ10mlの液体フッ化水素を圧入ASM用のx86-64)

jmp 
mov 
sub 
test 
js 
sub 
add 
jmp 
mov 
sub 
test 
js 
sub 
add 
jmp 
mov 
sub 
test 
js 
sub 
add 
jmp 
mov 
sub 
test 
js 
sub 
add 
cmp 
jne 

2)複数の単純なループ(およそ10mlの液体フッ化水素を圧入ASMのx86-64で):私たちは、詳細な比較のためにASMにtraslateしようとすることができます

jmp 
sub 
add 
mov 
sub 
test 
jns 
jmp 
sub 
add 
mov 
sub 
test 
jns 
jmp 
sub 
add 
mov 
sub 
test 
jns 
jmp 
sub 
add 
mov 
sub 
test 
jns 

我々はx86-64でのASM命令数える場合:

jmp: 4 
mov: 4 
sub: 8 
test: 4 
add: 4 
js: 4 
cmp: 1 
jne: 1 

0123をそして、総括する
jmp: 4 
mov: 4 
sub: 8 
test: 4 
add: 4 
jns: 4 

jns 4 

js 4 
cmp 1 
jne 1 

そして "jsが" "JNS" に似ています。

しかし、これは他のコンパイラやアーキテクチャーでも変わる可能性があります。それでも、第2のものは最初のものより少し速いと思います。

+3

あなたの数え方を尊重していますが、間違っていると思います。パイプライン化された場合、ほとんどの命令はゼロクロックで影響を受けて実行されます。プロセッサは**両方の**パスを取り、誤ったパスをロールバックするため、(条件付き)ジャンプ/分岐のみが高価です。ループ内で条件が多すぎると、パイプラインがいつもどこかで壊れてしまいます。 (レジスタの割り当て/キャッシュの局所性とそれ以外はすべて)通常、* thinループ*はループ本体の_about_ゼロクロックで実行され、ループ機構の場合はさらにいくつか実行されます。 – wildplasser

+0

ありがとう、これはまさに私が求めていたものです。 – mauroSabella

+0

@wildplasser私はあなたが正しいと思いますが、私は答えを簡略化しましたが、あなたの(非常に重要な)考察で考えるならば、あなたの答えは同じでなければなりません。 –

2

他にも言及したように、第2のアプローチは、比較が少ないので好ましい。

クリーナー、より簡潔な方法は、除算およびモジュラスを使用することです:

int current = changeInt; 
coins += current/25; 
current %= 25; 
coins += current/10; 
current %= 10; 
coins += current/5; 
current %= 5; 
coins += current; 

DIVとMOD演算子は、減算よりも高価ですが、changeIntの大きな値のために高速になりそうだし、そこにあります枝はありません。

+0

'current <0'のときに機能が異なることに注意してください。 – chux

0

なぜこのようなループが必要なのかわかりません。

int tempChangeInt; 

tempChangeInt = changeInt; 
coins = changeInt/25; 
tempChangeInt = changeInt % 25; 
if (tempChangeInt != 0) 
{ 
    coins += tempChangeInt/10; 
    tempChangeInt = tempChangeInt % 10; 
} 
if (tempChangeInt != 0) 
{ 
    if (tempChangeInt >= 5) 
     coins += (tempChangeInt - 5) + 1; 
    else 
     coins += tempChangeInt; 
} 
+0

私はループを必要としません。ループを使用して、私の質問が何であるかを示しました。それは、複雑なループといくつかの単純なループのどちらが優れているかです。 – mauroSabella

+2

これは正しいかもしれませんが、質問に答えません。 – nhouser9

+0

'tempChangeInt <0'のときに機能が異なることに注意してください。 – chux

関連する問題