决定运行一个快速测试,看看bcmath
如何在各种版本的PHP上运行,并注意到与4.3相比,最新和最新的版本在速度上明显不足,
我想知道是否有人知道这背后的原因,和/或如何在5+上提高速度,使其与4.3相当。
还要注意,5.6+的内存消耗是4.3相同操作所需的三倍:
性能测试结果(Waterflow)
它不会更快。您看到的图形不仅包括bcmath
调用,还包括启动&关闭开销。
$start = microtime(true);
for ($i = 0; $i < 1000; ++$i) {
bcdiv(40075036, 86164.098903691, 40);
}
echo microtime(true) - $start;
此片段将衡量bcdiv
的性能:http://3v4l.org/unrRL
正如你所看到的,性能基本相同。
注意:你可以看到这些数字非常小,这意味着你不能完全信任它们,你应该明白机器上的任何额外负载都会影响测试结果。
只是出于好奇。我决定我不需要bcmath的荒谬准确性,但我确实想把自己从IEEE 754舍入异常中拯救出来,并创建了我自己的非常简单的FixedNumber类:
class FixedNumber {
private static $radix = [
0 => 1,
1 => 10,
2 => 100,
3 => 1000,
4 => 10000,
];
private int $decimal_places;
public function __construct(
protected int $value,
int $decimal_places=2
)
{
$this->decimal_places = $decimal_places;
}
public function __toString() {
return sprintf('%.'.$this->decimal_places.'f', $this->value/self::$radix[$this->decimal_places]);
}
public function __toFloat() {
return $this->value/self::$radix[$this->decimal_places];
}
public function __add(FixedNumber $other) {
if ($this->decimal_places != $other->decimal_places) {
throw new Exception('Cannot add FixedNumber with different decimal places');
}
return new FixedNumber($this->value + $other->value, $this->decimal_places);
}
public function __sub(FixedNumber $other) {
if ($this->decimal_places != $other->decimal_places) {
throw new Exception('Cannot subtract FixedNumber with different decimal places');
}
return new FixedNumber($this->value - $other->value, $this->decimal_places);
}
public function __mul(FixedNumber $other) {
if ($this->decimal_places != $other->decimal_places) {
throw new Exception('Cannot multiply FixedNumber with different decimal places');
}
return new FixedNumber((int)round($this->value * $other->value / self::$radix[$this->decimal_places]), $this->decimal_places);
}
public function __div(FixedNumber $other) {
if ($this->decimal_places != $other->decimal_places) {
throw new Exception('Cannot divide FixedNumber with different decimal places');
}
return new FixedNumber((int)round(($this->value / $other->value) * self::$radix[$this->decimal_places]), $this->decimal_places);
}
}
并尝试了这个小测试设置:
define("SET_SIZE",1000,false);
$start = microtime(true);
$d = 0.0;
for ($i = 0; $i < SET_SIZE; ++$i) {
$d = 40075036+86164.098903691;
}
printf('%f<br>', microtime(true) - $start);
$start = microtime(true);
for ($i = 0; $i < SET_SIZE; ++$i) {
bcadd("40075036", "86164.098903691", 16);
}
printf('%f<br>', microtime(true) - $start);
$start = microtime(true);
for ($i = 0; $i < SET_SIZE; ++$i) {
$a = new 'FixedNumber(40075036);
$b = new 'FixedNumber(861600);
$c = $a->__add($b);
}
printf('%f<br>', microtime(true) - $start);
只是为了发现,尽管bcmath比普通数学慢20个数量级,但它仍然比我的简单FixedNumber类高0.11个数量级。1.000.000的集合大小的数字:
0.009088
0.224396
0.366447
似乎创建对象和在用户空间中的开销使bcmath成为一个更好的交易。
如果固定点算术能被包含在货币价值、学校格栅等方面,那就太好了,因为浮点数是错误的。