我在 PHP 中实现毕达哥拉斯平均值,算术和几何平均值是小菜一碟,但我很难想出一个可靠的调和平均值实现。
这是 PHP 中的等效实现:
function harmonicMeanV1()
{
$result = 0;
$arguments = func_get_args();
foreach ($arguments as $argument)
{
$result += 1 / $argument;
}
return func_num_args() / $result;
}
现在,如果任何参数是0
这将引发除以 0 警告,但由于与n -11 / n
相同并且优雅地返回常量而不引发任何错误,我可以将其重写为以下内容(如果它仍然会引发错误没有论据,但现在让我们忽略它):pow(0, -1)
INF
function harmonicMeanV2()
{
$arguments = func_get_args();
$arguments = array_map('pow', $arguments, array_fill(0, count($arguments), -1));
return count($arguments) / array_sum($arguments);
}
两种实现在大多数情况下都可以正常工作(例如v1、v2和WolframAlpha),但是如果1 / n i系列的总和 为 0 ,它们会失败,我应该得到另一个除以 0 的警告,但我不...
考虑以下集合:(-2, 3, 6
WolframAlpha说它是一个复数无穷大):
1 / -2 // -0.5
+ 1 / 3 // 0.33333333333333333333333333333333
+ 1 / 6 // 0.16666666666666666666666666666667
= 0
但是,我-2.7755575615629E-17
的两个实现都返回总和(v1,v2)而不是0
.
虽然 CodePad 上的返回结果是-108086391056890000
我的开发机器(32 位)说它是-1.0808639105689E+17
,但它仍然不像我所期望的0
那样。INF
我什至尝试调用is_infinite()
返回值,但它false
按预期返回。
我还找到了作为 PECL 扩展stats_harmonic_mean()
的一部分的函数stats
,但令我惊讶的是,我得到了完全相同的错误结果:-1.0808639105689E+17
如果有任何参数是0
,0
则返回但不检查系列的总和,如您所见在第 3585 行:
3557 /* {{{ proto float stats_harmonic_mean(array a)
3558 Returns the harmonic mean of an array of values */
3559 PHP_FUNCTION(stats_harmonic_mean)
3560 {
3561 zval *arr;
3562 double sum = 0.0;
3563 zval **entry;
3564 HashPosition pos;
3565 int elements_num;
3566
3567 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) {
3568 return;
3569 }
3570 if ((elements_num = zend_hash_num_elements(Z_ARRVAL_P(arr))) == 0) {
3571 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The array has zero elements");
3572 RETURN_FALSE;
3573 }
3574
3575 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
3576 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&entry, &pos) == SUCCESS) {
3577 convert_to_double_ex(entry);
3578 if (Z_DVAL_PP(entry) == 0) {
3579 RETURN_LONG(0);
3580 }
3581 sum += 1 / Z_DVAL_PP(entry);
3582 zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
3583 }
3584
3585 RETURN_DOUBLE(elements_num / sum);
3586 }
3587 /* }}} */
这看起来像一个典型的浮动精度错误,但我无法真正理解原因,因为单个计算非常精确:
Array
(
[0] => -0.5
[1] => 0.33333333333333
[2] => 0.16666666666667
)
gmp
是否可以在不恢复到/bcmath
扩展名的情况下解决此问题?