Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:7681 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 4644 invoked by uid 1010); 10 Feb 2004 00:30:06 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 4429 invoked from network); 10 Feb 2004 00:30:04 -0000 Received: from unknown (HELO mra02.ex.eclipse.net.uk) (212.104.129.89) by pb1.pair.com with SMTP; 10 Feb 2004 00:30:04 -0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by mra02.ex.eclipse.net.uk (Postfix) with ESMTP id 536D0406E8A for ; Tue, 10 Feb 2004 00:28:57 +0000 (GMT) Received: from mra02.ex.eclipse.net.uk ([127.0.0.1]) by localhost (mra02.ex.eclipse.net.uk [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 02138-01-39 for ; Tue, 10 Feb 2004 00:28:56 +0000 (GMT) Received: from mooby (unknown [213.152.58.41]) by mra02.ex.eclipse.net.uk (Postfix) with ESMTP id 1F4B8406E6B for ; Tue, 10 Feb 2004 00:28:56 +0000 (GMT) To: Date: Tue, 10 Feb 2004 00:30:02 -0000 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0000_01C3EF6D.0631B320" X-Mailer: Microsoft Office Outlook, Build 11.0.5510 Thread-Index: AcPvbQXSKrirEUZHTXmUJmwM4FdlsQ== X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 Message-ID: <20040210002856.1F4B8406E6B@mra02.ex.eclipse.net.uk> X-Virus-Scanned: by Eclipse VIRUSshield at eclipse.net.uk Subject: [PATCH] Bug #24064: Standard deviation From: webjedi@hudzilla.eclipse.co.uk ("Paul Hudson") ------=_NextPart_000_0000_01C3EF6D.0631B320 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi there, Bug #24064 (submitted by tularis@php.net) requests a standard deviation function for PHP. I realise that any of you could implement this in 10 minutes, but according to the bug database it is still Open so I figured I would give it a try myself! There are probably a dozen errors in the code and/or places where it could be better optimised, but I'm hoping one of you might be able to help with that. So, the attached diff file implements the function array_std_dev(), to calculate standard deviation using the deviation method. With the function in place, standard deviation is calculated like this: My first attempt at implementing this was using an extra array to buffer the deviations - this was more out of curiosity to see how the array stuff works. Sadly, it caused PHP to segfault and I couldn't figure out why - can any of you help me spot the brain fart? (I've attached the offending code in bad_stddev_code.txt) Yours, Paul PS: I'm not on the internals list, so I would appreciate it if you would CC me on your reply. ------=_NextPart_000_0000_01C3EF6D.0631B320 Content-Type: text/plain; name="bad_stddev_code.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="bad_stddev_code.txt" /* {{{ proto mixed array_std_dev(array input) Returns the standard deviation of the array entries */ PHP_FUNCTION(array_std_dev) { zval **input, **entry, *entry_n, *squareddev; int argc =3D ZEND_NUM_ARGS(); HashPosition pos; double dval; double total; double mean; int numelements =3D 0; // note this is calcuated by hand, not using = zend_hash_num_elements() double deviation; if (argc !=3D 1 || zend_get_parameters_ex(argc, &input) =3D=3D FAILURE) = { WRONG_PARAM_COUNT; } if (Z_TYPE_PP(input) !=3D IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an = array"); return; } ZVAL_LONG(return_value, 0); total =3D 0; // step one: sum the values of the array for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, = &pos) =3D=3D SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) { if (Z_TYPE_PP(entry) =3D=3D IS_ARRAY || Z_TYPE_PP(entry) =3D=3D = IS_OBJECT) continue; entry_n =3D *entry; zval_copy_ctor(entry_n); convert_scalar_to_number(entry_n TSRMLS_CC); convert_to_double(entry_n); total +=3D Z_DVAL_P(entry_n); // this is incremented by hand so that it doesn't count object and = array elements as an element numelements++; } // step two: calculate the mean of the input array mean =3D total / numelements; // step three: get the deviation from the mean of each number in the = input array, and add it to the squareddev array MAKE_STD_ZVAL(squareddev); array_init(squareddev); for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, = &pos) =3D=3D SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) { if (Z_TYPE_PP(entry) =3D=3D IS_ARRAY || Z_TYPE_PP(entry) =3D=3D = IS_OBJECT) continue; entry_n =3D *entry; zval_copy_ctor(entry_n); convert_scalar_to_number(entry_n TSRMLS_CC); convert_to_double(entry_n); Z_DVAL_P(entry_n) -=3D mean; zend_hash_next_index_insert(Z_ARRVAL_P(squareddev), entry_n, = sizeof(zval *), NULL); } // step four: sum the squared deviation array total =3D 0; for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(squareddev), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(squareddev), (void = **)&entry, &pos) =3D=3D SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(squareddev), &pos)) { entry_n =3D *entry; zval_copy_ctor(entry_n); convert_scalar_to_number(entry_n TSRMLS_CC); convert_to_double(entry_n); total +=3D Z_DVAL_P(entry_n); } // step five: divide the sum of the squared deviation array by the = number of elements - 1 total /=3D numelements - 1; Z_DVAL_P(return_value) =3D sqrt(total); } /* }}} */ ------=_NextPart_000_0000_01C3EF6D.0631B320--