jqGridサーバー側PHPの例の次の行で見つけました
$start = $limit*$page - $limit; // do not put $limit*($page - 1)
違いは何ですか
$start = $limit*$page - $limit;
と
$start = $limit*($page - 1);
著者が 2 番目の方法を推奨しないのはなぜですか?
これは数値計算の問題だと思います。$page
のように が巨大であるとします6.02e231
。それで
($page - 1) = 6.02e231
(まったく同じ浮動小数点表現)、そのため、
$limit*($page - 1) = $limit*$page
任意のプロセッサの観点から。比較
$limit*$page = [SOME HUGE VALUE]
$limit*$page - $limit = [SUBTRACTION OF TWO HUGE VALUES]
これにより、「マイナス 1」表記よりも正確な別の結果が得られます。
したがって、数学の完全な世界では 2 つの表記法は等しくなりますが、コンピューティングの非完全な世界では、最初の表記法は 2 つ目の表記法よりも「壊滅的な相殺」(wiki によると) を起こしやすくなります。
数学的には、両方の式で同じ結果が得られるはずです。
実際には、CPU の浮動小数点演算により (整数のみを考慮していないと仮定して)、これら 2 つの式の結果に大きな違いが生じる可能性があります。
例:
想像$page
は本当に大きな数字です。
その場合、1
式$page - 1
は因数分解され (1 は よりも数桁小さいため$page
)、
式$start = $limit*($page - 1);
は次のようになります$start = $limit*$page;
。最初の方法では、そのような問題はありません。 .
結論:
数学的には、違いはありません。
実際には、CPU (浮動小数点演算装置) が処理できる桁数は限られており、小さい数値は大きな数値と組み合わせると取り除かれることがよくあります。
編集:
例は1000語の価値があります...
このフィドルを見て、2つの数学的に同一の式が異なる結果をもたらす方法を確認してください:
http://jsfiddle.net/EyalAr/Z9BT5/
正直なところ、2 番目のバージョンが推奨されない理由がわかりません。
$c = $a * $b - $a;
抽象的には、これは次のように計算されます。
$a
CPU レジスタ 1 にロードします。$b
CPU レジスタ 2 にロードします。$a
はまだレジスター 1 にあります。それをレジスター 2 から減算し、結果をいずれかのレジスターに保管します。$c
。コンパイラが$a
式の両方のオペランドが同一であることを確認した場合、その行全体で 2 つの CPU レジスタのみが使用されます。
$c = $a * ($b - 1);
$a
します。私が覚えている限りでは、PHP は左から右への評価順序を保証するため、これを最初に行う必要があります。$b
レジスター 2 にロードします。1
明示的にロードする必要はありません。$c
。それは私には同じ努力のように見えます。その後、彼らは全体をプロファイリングし、何らかの理由 (たとえば、行のコンテキストなど) で最初のバージョンの方が効率的であることがわかった可能性があります。
整数演算を想定すると、結果にまったく違いはありません。また、浮動小数点引数についてはあまり共有しません。なぜなら、if$page
が非常に大きい場合でも、どのバージョンを使用するかは問題にならないからです。1
非常に大きな数から差し引いても、効果はありません。または、大きな数と1
別々に同じ係数を掛けてから、減算を実行します。2 つの値は、元の値と同じ桁違いに$page
なり1
ます。
$start = $limit*$page - $limit;
これは最初に乗算演算を実行し、次に制限を差し引いて結果を出します
$start = $limit*($page - 1);
これは、最初に $page を 1 減算し、次に $limit で乗算します
代数と同じように、演算の順序で加算/減算の前に乗算が行われます。PHP の優先度に関するドキュメントを参照してください。したがって、最初の行は $limit * $page を実行し、次に limit を減算します。これは、実際には と同じ$page * ($limit-1)
です。
それをほのめかす理由は、代数ではステートメントが数学的に同じであるが、プログラミングではそうではないためだと思います(かっこは、量の表現ではなく、操作の順序インジケーターとして使用されます)
古い言語/コンパイラでは、2 番目のステートメントの結果が-0
. これ-0
により、計算で別の問題が発生するため、最初の方法が優先されます。
ここで実行されている上記を確認できます: PHP のコード (観察なし-0
)およびLua のコード (-0
出力で観察)
プログラマーは正確さに気をつけすぎていました。
数学的にはまったく違いはありません。
プログラマの観点からは、変数は基本的な数値であるため、演算子の優先順位は重要ではありません。(オーバーロードされた演算子を持つ foo クラスのインスタンスである場合、話は異なります)
フォームの精度が失われる可能性があります$limit*$page - $limit
。これに関するrody_oの回答を参照してください。しかし、$page と $limit が 10^38 か何かのオーダーであるとは考えていないので、それは起こりません。しかし、php は数値の処理方法を知っています。そして覚えておいてください、私たちはそれらがフロートであることさえ知りません!
他の人も実行速度について言及しているように、これはプログラマーが念頭に置いていたものではない可能性があります。コードにどのフォームを書くか、本当に気にしますか? あるフォームを別のフォームから選択することは、マイクロ最適化でさえありません。
2 番目の形式を絶対に使用してはならないことを他の人に伝える理由はありません。大丈夫です。