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

Reply via email to