同等のテストはフロート変数では信頼できないが、整数では問題ないことを生徒に説明しました。私が使用している教科書では、> =と<=よりも>と<の方が読みやすいと述べています。ある程度は同意しますが、Forループでは?ループで開始値と終了値を指定する方が明確ではありませんか?
教科書の著者が正しいと思うものがありませんか?
別の例は、次のような範囲テストです。
スコア> 89グレード= 'A'の
場合スコア> 79グレード= 'B'の場合...
なぜ単に言わないのですか:スコア> = 90の場合?
同等のテストはフロート変数では信頼できないが、整数では問題ないことを生徒に説明しました。私が使用している教科書では、> =と<=よりも>と<の方が読みやすいと述べています。ある程度は同意しますが、Forループでは?ループで開始値と終了値を指定する方が明確ではありませんか?
教科書の著者が正しいと思うものがありませんか?
別の例は、次のような範囲テストです。
スコア> 89グレード= 'A'の
場合スコア> 79グレード= 'B'の場合...
なぜ単に言わないのですか:スコア> = 90の場合?
回答:
ゼロベースの配列を持つカーリーブレースされたプログラミング言語では、次のforようなループを記述するのが習慣です。
for (int i = 0; i < array.Length, i++) { }
これは、配列内のすべての要素を走査し、最も一般的なケースです。<=またはの使用を回避します>=。
これを変更する必要があるのは、最初または最後の要素をスキップするか、反対方向にトラバースするか、異なる開始ポイントから異なるエンドポイントに移動する必要がある場合だけです。
コレクションの場合、イテレーターをサポートする言語では、これを見るのがより一般的です:
foreach (var item in list) { }
これにより、比較が完全に回避されます。
<=vs をいつ使用するかについての厳格で速いルールを探しているなら<、それはありません。意図を最もよく表すものを使用してください。コードで「時速55マイル以下」という概念を表現する必要がある場合は、「<=ではなく」と言う必要があり<ます。
90は89ではなく実際の境界値であるため、グレード範囲に関する質問に答えるの>= 90はより理にかなっています。
forこのようなループの最も一般的な使用例だからです。forここで提供したループの形式は、わずかな経験を持つ開発者であればすぐに認識できます。より具体的なシナリオに基づいて、より具体的な回答が必要な場合は、質問にそれを含める必要があります。
関係ありません。
しかし、議論のために、2つのオプションを分析しましょう:a > bvs a >= b。
待って!それらは同等ではありません!
OK、その後、a >= b -1対a > bまたはa > b対a >= b +1。
フム、a >bそしてa >= bよりも良好な外観の両方a >= b - 1とa >= b +1。1とにかくこれらはすべて何ですか?そのため、ランダムs を追加または削除する必要があるため、>代わりに>=またはその逆を使用することによる利点はなくなり1ます。
しかし、それが数字の場合はどうでしょうか?それは言う方が良いですa > 7かa >= 6?一瞬待って。>vs を使用し>=てハードコードされた変数を無視する方が良いかどうか真剣に議論していますか?だから、それは本当に... a > DAYS_OF_WEEKより良いかどうかの問題になりますか?それとも対ですか?そして、今回は変数名でのみsの加算/減算に戻ります。または、しきい値、制限、最大値を使用するのが最善かどうかを議論するかもしれません。a >= DAYS_OF_WEEK_MINUS_ONEa > NUMBER_OF_LEGS_IN_INSECT_PLUS_ONEa >= NUMBER_OF_LEGS_IN_INSECT1
そして、それは一般的なルールがないように見えます:それは比較されているものに依存します
しかし、実際には、コードを改善するためのはるかに重要なものと、例外を含むはるかに客観的で合理的なガイドライン(たとえば、行ごとのX文字制限)があります。
>vs >=の議論についてですか、それとも>vs の議論>=が有意義かどうかについての議論ですか?おそらくこれについて議論するのを避けるのが最善でしょう:p
計算上使用してコストの違いはありません<か>と比べ<=たりは>=。同等に高速に計算されます。
ただし、ほとんどのforループは0からカウントされます(多くの言語では配列に0インデックスが使用されているため)。したがって、これらの言語の標準的なforループは
for(int i = 0; i < length; i++){
array[i] = //...
//...
}
でこれを行うに<=は、オフバイワンエラーを避けるためにどこかに-1を追加する必要があります
for(int i = 1; i <= length; i++){
array[i-1] = //...
//...
}
または
for(int i = 0; i <= length-1; i++){
array[i] = //...
//...
}
もちろん、言語が1から始まるインデックスを使用する場合は、制限条件として<=を使用します。
重要なのは、条件で表現された値が問題の説明からのものであることです。読みやすい
if(x >= 10 && x < 20){
} else if(x >= 20 && x < 30){
}
半開間隔よりも
if(x >= 10 && x <= 19){
} else if(x >= 20 && x <= 29){
}
そして、19から20の間に可能な値がないことを知るために数学をしなければなりません
for(markup = 5; markup <= MAX_MARKUP; ++markup)。他のものはそれを過度に複雑にします。
ポイントは、>または> =のどちらを使用すべきかではありません。ポイントは、表現力豊かなコードを記述できるものなら何でも使用することです。
一方を追加または減算する必要がある場合は、もう一方の演算子の使用を検討してください。ドメインの良いモデルから始めると、良いことが起こることがわかります。その後、ロジックはそれ自体を書き込みます。
bool IsSpeeding(int kilometersPerHour)
{
const int speedLimit = 90;
return kilometersPerHour > speedLimit;
}
これは、
bool IsSpeeding(int kilometersPerHour)
{
const int speedLimit = 90;
return kilometersPerHour >= (speedLimit + 1);
}
他の場合には、他の方法が望ましい:
bool CanAfford(decimal price, decimal balance)
{
return balance >= price;
}
はるかに良い
bool CanAfford(decimal price, decimal balance)
{
const decimal epsilon = 0e-10m;
return balance > (price - epsilon);
}
「原始的な強迫観念」を許してください。ここでは、それぞれVelocityタイプとMoneyタイプを使用したいのは明らかですが、簡潔にするために省略しました。ポイントは次のとおりです。より簡潔で、解決したいビジネス上の問題に集中できるバージョンを使用します。
質問で指摘したように、フロート変数の等価性のテストは信頼できません。
とについて<=も同様です>=。
ただし、整数型にはこのような信頼性の問題はありません。私の意見では、著者はどちらがより読みやすいかについて彼女の意見を表明していた。
あなたが彼に同意するかどうかは、もちろんあなたの意見です。
<か、それに<=基づいて選択することを好みます。他の人が指摘したように、FORループ<ではC型言語の方が理にかなっています。を好む他のユースケースがあります<=。いつでもどこでも、自由にすべてのツールを使用してください。
for (unsigned int i = n; i >= 0; i--)またはfor (unsigned int i = x; i <= y; i++)場合がyあることを起こりますUINT_MAX。おっと、それらは永遠にループします。
関係の各<、<=、>=、>とも ==及び!=2つの浮動小数点値を比較するために彼らのユースケースを持っています。それぞれに特定の意味があり、適切なものを選択する必要があります。
それぞれに正確にこの演算子が必要な場合の例を示します。(ただし、NaNに注意してください。)
f入力として浮動小数点値を取る高価な純関数があります。計算を高速化するために、最新の計算値のキャッシュ、つまりにマッピングxするルックアップテーブルを追加することにしましたf(x)。==引数を比較するのに本当に使いたいでしょう。xですか?おそらく使用したいでしょうx != 0.0。xが単位間隔内にあるかどうかを知りたいですか?(x >= 0.0) && (x < 1.0)正しい状態です。d行列の行列式を計算し、それが正定かどうかを見たいですか?以外を使用する理由はないd > 0.0。alpha <= 1.0ます。浮動小数点演算(一般)は正確ではありません。しかし、それはあなたがそれを恐れ、魔法として扱い、2つの浮動小数点量が内にある場合は常に等しいとは限らないことを意味しません1.0E-10。そうすることは本当にあなたの数学を壊し、すべての奇妙なことを引き起こすでしょう。
x != 0.0およびyが有限の浮動小数点値であっても、有限であるy / x必要はありません。ただしy / x、オーバーフローが原因で有限であるかどうか、または最初は操作が数学的に明確に定義されていなかったためかどうかを知ることは重要です。xが単位間隔[0、1)にある必要があるという前提条件を持つ関数がある場合、x == 0.0またはで呼び出されたときにアサーションエラーが発生した場合、私は本当に動揺しx == 1.0 - 1.0E-14ます。1.0E-30、何も得られません。あなたがしたことは、間違った答えをする可能性を高めることだけでした。alphaは丸め誤差の影響を受ける可能性があり、したがってalpha <= 1.0式の真の数学値alphaが実際に1より大きくても、真である可能性があります。しかし、この時点でできることはありません。ソフトウェアエンジニアリングの場合と同様に、エラーは適切なレベルで処理し、一度だけ処理します。1.0E-10浮動小数点数を比較するたびに(これはほとんどの人が使用する魔法の値であると思われますが、理由はわかりません)の丸め誤差を追加すると、すぐに次の誤差が発生します1.0E+10…
ループで使用される条件のタイプは、コンパイラが実行できる最適化の種類を、良くも悪くも制限する場合があります。たとえば、次の場合:
uint16_t n = ...;
for (uint16_t i=1; i<=n; i++)
... [loop doesn't modify i]
コンパイラは、nが65535になり、iがnを超える以外の方法でループが終了しない限り、上記の条件により、n番目のパスループの後にループが終了すると想定できます。これらの条件が当てはまる場合、コンパイラは、上記の条件以外でループが終了するまでループを実行するコードを生成する必要があります。
代わりにループが次のように記述されていた場合:
uint16_t n = ...;
for (uint16_t ctr=0; ctr<n; ctr++)
{
uint16_t i = ctr+1;
... [loop doesn't modify ctr]
}
コンパイラーは、ループをn回以上実行する必要がないと安全に想定できるため、より効率的なコードを生成できる可能性があります。
符号付き型のオーバーフローは、厄介な結果になる可能性があることに注意してください。与えられた:
int total=0;
int start,lim,mult; // Initialize values somehow...
for (int i=start; i<=lim; i++)
total+=i*mult;
コンパイラは、それを次のように書き換えます。
int total=0;
int start,lim,mult; // Initialize values somehow...
int loop_top = lim*mult;
for (int i=start; i<=loop_top; i+=mult)
total+=i;
このようなループは、計算でオーバーフローが発生しない場合は元のループと同じように動作しますが、通常、整数オーバーフローが一貫したラッピングセマンティクスを持つハードウェアプラットフォームでも永久に実行できます。