Er, either the php-internals MARC archive doesn't show all attachments, or my diff file got stripped en route for not having a .txt extension. I've attached it again, just to make sure.
Paul -- -----Original Message----- From: Paul Hudson [mailto:[EMAIL PROTECTED] Sent: 10 February 2004 00:30 To: '[EMAIL PROTECTED]' Subject: [PATCH] Bug #24064: Standard deviation Hi there, Bug #24064 (submitted by [EMAIL PROTECTED]) 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: <?php $scores = array(18,5,7,18,3,2,10); print array_std_dev($score); // prints 6.6833125519211 ?> 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.
diff -rubB php-snap/ext/standard/array.c php-new/ext/standard/array.c --- php-snap/ext/standard/array.c 2004-01-28 21:08:16.000000000 +0000 +++ php-new/ext/standard/array.c 2004-02-09 23:57:14.590206400 +0000 @@ -4229,6 +4229,77 @@ } /* }}} */ + +/* {{{ 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; + int argc = ZEND_NUM_ARGS(); + HashPosition pos; + double total = 0; + double mean; + int numelements = 0; // note this is calcuated by hand, not using zend_hash_num_elements() + double deviation = 0; + + if (argc != 1 || zend_get_parameters_ex(argc, &input) == FAILURE) { + WRONG_PARAM_COUNT; + } + + if (Z_TYPE_PP(input) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); + return; + } + + ZVAL_LONG(return_value, 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) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) { + + if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT) + continue; + + entry_n = *entry; + zval_copy_ctor(entry_n); + convert_scalar_to_number(entry_n TSRMLS_CC); + convert_to_double(entry_n); + total += 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 = total / numelements; + + // step three: add up the squared deviations for each array element + total = 0; + + 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) == SUCCESS; + zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) { + + if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT) + continue; + + entry_n = *entry; + zval_copy_ctor(entry_n); + convert_scalar_to_number(entry_n TSRMLS_CC); + convert_to_double(entry_n); + deviation = Z_DVAL_P(entry_n) - mean; + total += deviation * deviation; + } + + // step four: divide the sum of the squared deviation array by the number of elements - 1 + total /= numelements - 1; + ZVAL_DOUBLE(return_value, sqrt(total)); +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff -rubB php-snap/ext/standard/basic_functions.c php-new/ext/standard/basic_functions.c --- php-snap/ext/standard/basic_functions.c 2004-01-19 19:11:00.000000000 +0000 +++ php-new/ext/standard/basic_functions.c 2004-02-09 18:16:31.314160000 +0000 @@ -794,6 +794,7 @@ PHP_FE(array_chunk, NULL) PHP_FE(array_combine, NULL) PHP_FE(array_key_exists, NULL) + PHP_FE(array_std_dev, NULL) /* aliases from array.c */ PHP_FALIAS(pos, current, first_arg_force_ref) diff -rubB php-snap/ext/standard/php_array.h php-new/ext/standard/php_array.h --- php-snap/ext/standard/php_array.h 2004-01-08 18:07:44.000000000 +0000 +++ php-new/ext/standard/php_array.h 2004-02-09 18:15:27.892964800 +0000 @@ -93,6 +93,7 @@ PHP_FUNCTION(array_key_exists); PHP_FUNCTION(array_chunk); PHP_FUNCTION(array_combine); +PHP_FUNCTION(array_std_dev); HashTable* php_splice(HashTable *, int, int, zval ***, int, HashTable **); PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC);
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php