Ver Mensaje Individual
  #23 (permalink)  
Antiguo 25/11/2013, 18:15
Avatar de dashtrash
dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años, 7 meses
Puntos: 270
Respuesta: Número aleatorio pero evitando uno en particular

Cita:
Iniciado por marlanga Ver Mensaje
Sin array_slice, ¿Qué devuelves?¿Un array de 49 posiciones desordenado? Se debe devolver un array con los números aleatorios, asi pues el array_slice es necesario.
No.Se van a usar 5 posiciones del array.Mientras los números del array se utilicen según índice (bucle), y se muestren 5 resultados, da lo mismo que el array tenga 5 o 49 posiciones.
En cualquier caso, meter array_slice por enmedio significa que no se está comparando array_rand con shuffle.

Cita:
Iniciado por marlanga Ver Mensaje
Esa operación solo corta el array por el principio. Las funciones shuffle y range son mas costosas.
Lo suficiente para hacerla estadisticamente igual a range

Cita:
Iniciado por marlanga Ver Mensaje
Y cuando lo ejecuto yo sobre http://sandbox.onlinephpfunctions.com/, me sale:
Código BASH:
Ver original
  1. Con suffle: 4
  2. Fuerza bruta: 3
  3. Mejor: 3
Código PHP:
Ver original
  1. Con suffle: 8
  2. Fuerza bruta: 3
  3. Mejor: 5
Tienes razón, se me fue otro test.Había algo que no me cuadraba en todo esto.Por algún motivo, en mi ordenador los resultados siguen siendo los mismos.

Cita:
Iniciado por marlanga Ver Mensaje
Pero no hace falta ni ejecutar, es solo cuestión de pensar qué hace cada algoritmo. El único peligro que tiene el algoritmo de fuerza bruta de resultar costoso, es cuando falla muchas veces al tratar de insertar un número aleatorio en un array que ya lo contiene. Y ese caso ocurre cuando el número de números a obtener es una porción significativa del rango de números posibles. No he hecho pruebas, pero estimo que a partir de 1/3, es posible que la fuerza bruta no sea la mejor opción.
Al pensar más profundamente, verás que en el rango de tiempos que nos movemos (8 milisegundos en 1000 iteraciones), interpretar código PHP es tan costoso como mover unos cuantos punteros de C.Según mis pruebas, con 8 números (1/6), el rendimiento es el mismo, según los sandbox online.

Cita:
Iniciado por marlanga Ver Mensaje
La operación shuffle no es atómica. Su implementación por cojones tiene que recorrer todo el array suministrado, y desordenarlo usando seguramente un FOR.
En C.No en PHP.PHP es un lenguaje MUY ineficiente.Todo lo que haga C, es mucho más rápido que lo que haga PHP.En C,49 elementos se recorren en nada.El desordenarlo es una operación simple de punteros.Aunque no sea "atómica", las conversiones necesarias entre un array PHP y la estructura de datos internas usada por el parser, son menos.Y no son triviales (un array PHP no es un array C).
Tu lógica es sencilla...Pero estás suponiendo lo que hace PHP por dentro.array_rand hace chequeos sobre las keys que shuffle no hace.shuffle es casi exclusivamente manipulación de punteros, mas llamadas a rand().array_rand, no.

Cita:
Iniciado por marlanga Ver Mensaje
En cuanto a coste de memoria, tanto el shuffle como el mejorado usan un array de 49 posiciones obtenido con range, y devuelve otro array de 6 posiciones.
Shuffle no devuelve ningún array.Tu función devuelve un array.Se pueden utilizar tranquilamente los 5 primeros elementos sin necesidad de recortar el array.

Cita:
Iniciado por marlanga Ver Mensaje
Si un entero ocupa en php 4 bytes, entonces (49+6)*4=22' bytes.
Sin embargo, el e fuerza bruta sólo hace uso de un array que tendrá 6 posiciones, y una variable. (6+1)*4=28 bytes.
Te pego aqui lo que hace PHP al declarar *una* variable (ni siquiera 1 array,que tiene sus propias estructuras de control)
Código C:
Ver original
  1. PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC)
  2. {
  3.     char *p = NULL;
  4.     char *ip = NULL;        /* index pointer */
  5.     char *index;
  6.     char *var, *var_orig;
  7.     int var_len, index_len;
  8.     zval *gpc_element, **gpc_element_p;
  9.     zend_bool is_array = 0;
  10.     HashTable *symtable1 = NULL;
  11.     ALLOCA_FLAG(use_heap)
  12.  
  13.     assert(var_name != NULL);
  14.  
  15.     if (track_vars_array) {
  16.         symtable1 = Z_ARRVAL_P(track_vars_array);
  17.     }
  18.  
  19.     if (!symtable1) {
  20.         /* Nothing to do */
  21.         zval_dtor(val);
  22.         return;
  23.     }
  24.  
  25.  
  26.     /* ignore leading spaces in the variable name */
  27.     while (*var_name && *var_name==' ') {
  28.         var_name++;
  29.     }
  30.    
  31.     /*
  32.      * Prepare variable name
  33.      */
  34.     var_len = strlen(var_name);
  35.     var = var_orig = do_alloca(var_len + 1, use_heap);
  36.     memcpy(var_orig, var_name, var_len + 1);
  37.  
  38.     /* ensure that we don't have spaces or dots in the variable name (not binary safe) */
  39.     for (p = var; *p; p++) {
  40.         if (*p == ' ' || *p == '.') {
  41.             *p='_';
  42.         } else if (*p == '[') {
  43.             is_array = 1;
  44.             ip = p;
  45.             *p = 0;
  46.             break;
  47.         }
  48.     }
  49.     var_len = p - var;
  50.  
  51.     if (var_len==0) { /* empty variable name, or variable name with a space in it */
  52.         zval_dtor(val);
  53.         free_alloca(var_orig, use_heap);
  54.         return;
  55.     }
  56.  
  57.     /* GLOBALS hijack attempt, reject parameter */
  58.     if (symtable1 == EG(active_symbol_table) &&
  59.         var_len == sizeof("GLOBALS")-1 &&
  60.         !memcmp(var, "GLOBALS", sizeof("GLOBALS")-1)) {
  61.         zval_dtor(val);
  62.         free_alloca(var_orig, use_heap);
  63.         return;
  64.     }
  65.  
  66.     index = var;
  67.     index_len = var_len;
  68.  
  69.     if (is_array) {
  70.         int nest_level = 0;
  71.         while (1) {
  72.             char *index_s;
  73.             int new_idx_len = 0;
  74.  
  75.             if(++nest_level > PG(max_input_nesting_level)) {
  76.                 HashTable *ht;
  77.                 /* too many levels of nesting */
  78.  
  79.                 if (track_vars_array) {
  80.                     ht = Z_ARRVAL_P(track_vars_array);
  81.                     zend_symtable_del(ht, var, var_len + 1);
  82.                 }
  83.  
  84.                 zval_dtor(val);
  85.  
  86.                 /* do not output the error message to the screen,
  87.                  this helps us to to avoid "information disclosure" */
  88.                 if (!PG(display_errors)) {
  89.                     php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variable nesting level exceeded %ld. To increase the limit change max_input_nesting_level in php.ini.", PG(max_input_nesting_level));
  90.                 }
  91.                 free_alloca(var_orig, use_heap);
  92.                 return;
  93.             }
  94.  
  95.             ip++;
  96.             index_s = ip;
  97.             if (isspace(*ip)) {
  98.                 ip++;
  99.             }
  100.             if (*ip==']') {
  101.                 index_s = NULL;
  102.             } else {
  103.                 ip = strchr(ip, ']');
  104.                 if (!ip) {
  105.                     /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
  106.                     *(index_s - 1) = '_';
  107.  
  108.                     index_len = 0;
  109.                     if (index) {
  110.                         index_len = strlen(index);
  111.                     }
  112.                     goto plain_var;
  113.                     return;
  114.                 }
  115.                 *ip = 0;
  116.                 new_idx_len = strlen(index_s); 
  117.             }
  118.  
  119.             if (!index) {
  120.                 MAKE_STD_ZVAL(gpc_element);
  121.                 array_init(gpc_element);
  122.                 if (zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p) == FAILURE) {
  123.                     zval_ptr_dtor(&gpc_element);
  124.                     zval_dtor(val);
  125.                     free_alloca(var_orig, use_heap);
  126.                     return;
  127.                 }
  128.             } else {
  129.                 if (zend_symtable_find(symtable1, index, index_len + 1, (void **) &gpc_element_p) == FAILURE
  130.                     || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
  131.                     MAKE_STD_ZVAL(gpc_element);
  132.                     array_init(gpc_element);
  133.                     zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
  134.                 }
  135.             }
  136.             symtable1 = Z_ARRVAL_PP(gpc_element_p);
  137.             /* ip pointed to the '[' character, now obtain the key */
  138.             index = index_s;
  139.             index_len = new_idx_len;
  140.  
  141.             ip++;
  142.             if (*ip == '[') {
  143.                 is_array = 1;
  144.                 *ip = 0;
  145.             } else {
  146.                 goto plain_var;
  147.             }
  148.         }
  149.     } else {
  150. plain_var:
  151.         MAKE_STD_ZVAL(gpc_element);
  152.         gpc_element->value = val->value;
  153.         Z_TYPE_P(gpc_element) = Z_TYPE_P(val);
  154.         if (!index) {
  155.             if (zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p) == FAILURE) {
  156.                 zval_ptr_dtor(&gpc_element);
  157.             }
  158.         } else {
  159.             /*
  160.              * According to rfc2965, more specific paths are listed above the less specific ones.
  161.              * If we encounter a duplicate cookie name, we should skip it, since it is not possible
  162.              * to have the same (plain text) cookie name for the same path and we should not overwrite
  163.              * more specific cookies with the less specific ones.
  164.              */
  165.             if (PG(http_globals)[TRACK_VARS_COOKIE] &&
  166.                 symtable1 == Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]) &&
  167.                 zend_symtable_exists(symtable1, index, index_len + 1)) {
  168.                 zval_ptr_dtor(&gpc_element);
  169.             } else {
  170.                 zend_symtable_update(symtable1, index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
  171.             }
  172.         }
  173.     }
  174.     free_alloca(var_orig, use_heap);
  175. }
Crees que 1 variable más, simplemente son 4 bytes?
Sólo la estructura ZVAL que la contiene, en el caso muy simple de un entero (long) ocupa unos 20 bytes.Sin contar el nombre de la variable, y su posición en la tabla de símbolos.Un array es más grande.
La aritmética de la memoria **real** no es tan simple como "resto la longitud de los arrays".Si nos estamos molestando por esos bytes, *todo* cuenta.
En cualquier caso, dónde está el uso de memoria "disparatado"?

Bueno, todo esto es una discusión divertida (para variar), pero, por mi parte como conclusión, ni en este caso en particular, y, ni mucho menos en general, la fuerza bruta es la forma de hacer lo que el OP quería.

Última edición por dashtrash; 25/11/2013 a las 18:30