我在 jqGrid 服务器端 PHP 示例中找到了下一行
$start = $limit*$page - $limit; // do not put $limit*($page - 1)
有什么区别
$start = $limit*$page - $limit;
和
$start = $limit*($page - 1);
为什么作者不推荐第二种方式?
从数学上讲,两个表达式应该产生相同的结果。
实际上,由于 CPU 中的浮点运算(假设我们不只考虑整数),这两个表达式的结果可能会有很大差异。
示例:
想象$page
是一个非常大的数字。
在这种情况下,1
表达式$page - 1
将被分解(因为 1 比 小几个数量级$page
),
表达式$start = $limit*($page - 1);
将等价于$start = $limit*$page;
第一种方式,我们没有这样的问题,这就是为什么它被推荐.
结论:
从数学上讲,它没有区别。
实际上,CPU(浮点运算单元)只能处理有限的数量级,而较小的数字在与大数字结合时通常会被分解。
编辑:
一个例子值得 1000 字......
看看这个小提琴,看看两个数学上相同的表达式如何产生不同的结果:http:
//jsfiddle.net/EyalAr/Z9BT5/
我怀疑这是一个数值数学问题。假设$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]
这将产生不同的结果,比“减一”表示法更准确。
因此,尽管在完美的数学世界中,这两个符号是相等的,但在非完美的计算世界中,第一个比第二个更容易出现“灾难性取消”(wiki that)。
$start = $limit*$page - $limit;
这将首先执行乘法运算,然后减去结果的限制
$start = $limit*($page - 1);
这将首先将 $page 减去 1,然后与 $limit 相乘
就像在代数中一样,乘法按运算顺序发生在加法/减法之前。请参阅PHP 的优先文档。所以第一行做$limit * $page,然后减去limit,其实和$page * ($limit-1)
.
我认为暗示这一点的原因是,在代数中,语句在数学上是相同的,但在编程中却不是(括号被视为操作顺序指标而不是数量表示)
通常不建议使用第二种方法,因为在较旧的语言/编译器中,第二条语句会导致-0
. 这-0
会在计算中产生一些其他问题,因此,首选第一种方法。
您可以在此处看到上述内容:PHP 中的代码(未-0
观察到)和Lua 中的代码(-0
在输出中观察)
老实说,我不明白为什么不推荐第二个版本。
$c = $a * $b - $a;
在抽象视图中,这将计算如下:
$a
到 CPU 寄存器 1。$b
到 CPU 寄存器 2。$a
仍在寄存器 1 中。从寄存器 2 中减去它,将结果存储在任一寄存器中。$c
.如果编译器看到$a
等式中的两个操作数相同,则整行将仅使用两个 CPU 寄存器。
$c = $a * ($b - 1);
$a
到寄存器 1。这应该首先完成,因为据我所知,PHP 保证了从左到右的评估顺序。$b
到寄存器 2。1
不需要显式加载。$c
.对我来说,这看起来很像同样的努力。再说一次,他们可能已经分析了整个事情,并发现出于某种原因(例如由于行的上下文)第一个版本更有效。
假设整数算术,结果绝对没有区别。我也不完全分享浮点参数,因为如果$page
是这么大的数字,那么您使用哪个版本仍然无关紧要。1
要么从一个非常大的数字中减去,要么没有效果。或者您将大数和1
分别乘以相同的因子,然后执行减法。这两个值在数量级上的差异与原始值相同,$page
并且1
。
程序员对准确性过于谨慎了。
在数学上根本没有区别。
从程序员的角度来看,运算符的优先级并不重要,因为变量是基本数字。(如果它们是具有重载运算符的 foo 类的实例,情况就不同了)
表格可能会失去准确性$limit*$page - $limit
,请参阅rody_o对此的回答。但这不会发生,因为我从不认为 $page 和 $limit 的数量级为 10^38 之类的。但是 php 知道如何处理数字。请记住,我们甚至不知道它们是花车!
正如其他人也提到了执行速度,这不是程序员可能想到的。你真的关心在你的代码中编写哪种形式吗?选择一种形式而不是另一种形式甚至不是微优化。
没有理由告诉别人他们绝对不应该使用第二种形式。没关系。