Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Serapis

#1651
Bien... pero es pura suerte...

Por aquel entonces yo también estuve a punto de invertir 6.000 euros en bitcoins, pero me abstuve a última hora.

En cualquier caso, que el bitcoin subiera como la espuma los siguientes años, no es algo mérito del chico (ni de nadie en particular), luego peca (propio de la edad) de prepotencia sublime... pués a fin de cuentas su 'fortuna' es debida precisamente a 'la fortuna', y no a su esfuerzo, ni a su inteligencia, ni a ninguna otra cosa.
#1652
Algún defectillo, se podría tolerar... pero vamos que es un coladero de chapuza tras chapuza.

Me pregunto yo, si no debína remplazarnos gratis los procesadores, pués al final son defecto de diseño y a juicio mío debieran pagar lo mismo que cualquier otra empresa, que cualquier otro producto... porque las consecuencias son o bajada de renidimiento o intrusiones (y además irreconocibles).
#1653
Hay dos formas básicamente de hacerlo (con ficheros, si no recurres a una base de datos):
Considera la cosa como te enumero:
Ayer creaste 20 registros, hoy creas 10 registros, mañana creas 30 registros... total 60.
Ahora pongamos que llega el momento de borrar los de ayer... sucede que están al comienzo del fichero, luego eliminar los registros, básicamente se limita a copiar a un nuevo fichero los registros vigentes... y luego eliminar el viejo fichero, y renombrar el nuevo con el nombre del viejo...

Ahora bien, puede optimizarse?.  Si, claro...
Considera el log, como un array, una lista, donde siempre se borra del comienzo x (un número indeterminado de registros), lo que se hace de forma más eficiente, es 'subir' todos los registros por debajo, justamente 'x' registros hacia arriba... y casi está listo.
Tan solo resta saber que es preciso el mantenimiento de algunos datos para tener informada dichas condiciones...

Ahora pasemos a un punto más cercano al código que la propia prosa que lo describe:

// Cabecera de fichero...
Estructura LogFile
  int Ultima      //  Es la posición de escritura de la siguiente línea.
  int Entradas   // cantidad de entradas (días) que tiene actualmente el log.
fin estructura

Estructura LogData
  int MesYdia   // (mes * 100) + día , o de tipo fecha si prefieres...
  int LogsHoy      // cantidad de logs alojados para el mes y día x
  // Nota si todos los días se escriben registro posiblemente pueda omitirse el mes.
  array string LogTxt     // los datos a almacenar...
Fin Estructura

logData  Logs()   // un array de 'logdata'
logData Log   /// un log temporal


* La primera estructura sería la cabecera del fichero, simplemente se sobrescriben los datos 'ultima' y 'Entradas'.
--- Entradas: Contiene la cantidad de entradas (días) que contiene el fichero.
--- Ultima: Es el puntero de escritura, es importante, porque al borrar entradas, entradas viejas quedan en el fichero (no importa se sobrescribirán cuando proceda), pero es preciso saber donde escribir las nuevas entradas...

* La estructura logData contiene los datos del log de un día concreto... Hay tantas como señala 'Entradas'
--- MesYDía contiene la fecha relativa al día y mes de esa entrada.
--- Logshoy, señala cuantas líneas de log se han añadido, es decir el tamaño del campo LogTxt, que son almacenadas un día en concreto...

Al abrir el programa lo primero es leer la cabecera, verificar si tiene una o más entradas y en tal caso leer la primera, y verificar si su fecha ha sobrepasado el plazo previsto (30 días por ejemplo)...
sugiero transformar la fecha en un entero para hacer comparaciones sencillas, mediante la fórmula: f = (mes * 100) + dia
.... donde mes va del rango 1 al 12 y dia del 1 al 31, así tendrías guardadas como fechas valores de ejemplo:
 Enero 1= 101
 Enero 15 = 115
 Enero 22 = 122
 Abril 19= 419
  Mayo 19 = 519
 Diciembre 25= 1225
La comparación será fácil si el mes actual es mayor que el previo, pero hay que considerar también el caso opuesto, por ejemplo que la primera entrada sea de diciembre y hoy sea enero... En esos casos cuando el mes actual es menor que la primera entrada, basta sumar a hoy (12 * 100), antes de comparar las fechas...
buleano = Funcion Eliminable(int entrada, int hoy)
     Si (entrada > hoy)
         entrada + = 1200
     fin si
      // + 100 porque es la diferencia entre el día de un mes y el mismo día sel siguiente mes.
      // a propósito puse en el ejemplo 19 de abril y 19 de mayo, míralo otra vez...
     Si (entrada + 100 <= hoy) 
         devolver TRUE
     fin si
fin funcion


Si devuelve TRUE se invoca una función para 'EliminarLogDia' (que ya sabes que a pesar de su nombre no elimina nada, solo mueve datos... baja los logs de arriba, exactamente la cantidad que ocupa los datos de la entrada del log del día a eliminar...

Se puede optimizar más?. Posiblemente sí... Si resulta que el tamaño de los logs se hacen de tamaño fijo (todas iguales), entonces el fichero log se puede repartir en dos (es más fácil de amntener y calcular/procesar), uno sería el 'logcontrol.txt' y otro el 'logdata.txt'...
El de control tendría la cabecera y otra estructura simplificada a solo los datos indicativos del log de cada día:
estructura LogDia
    int MesYdia       // (mes * 100) + día , o de tipo fecha si prefieres...
    int LogsHoy      // número de entradas para el mes y día x
fin estructura


Ahora cuando haya que borrar la entrada de un día, directamente se puede sobrecribir las entradas en este fichero sin más complicaciones:

funcion EliminarPrimera
  logdia ld
  int k, n, sizeLogdia, ...
  int puntero

  puntero = size(estructura logfile)
  sizelogdia= size(estructura logdia)
 
  Bucle para k desde 1 hasta cabecera.Entradas -1
      ld = leerRegistro(puntero + sizelogdia)
       // aquí irá más código como señalaré más abajo..
       // ...
       //
      escribirRegistro(puntero, ld)
      puntero + = sizelogdia
  Siguiente

  cabecera.Entradas -=1
  cabecera.Ultima = n // 'n' se calcula después de hacer lo propio sobre el otro fichero...
fin funcion


Como se ve el mantenimiento de este fichero será extramadamente sencillo, eliminar el log de un día es un bucle para bajar todos los registros entrados un registro más abajo...

El fichero, que contiene el texto, al ser entradas de tamaño fijo (cada log), aunque varíe el número de líneas que tenga cada día, simplemente se trata de saber cuantas líneas contiene ese día, multiplicarlo por el largo fijo de cada log, y por tanto en un bucle (en realidad el mismo que se acaba de describir, porque puede ir en la misma función (aunque rerquiere un segundo bucle anidado), recorrer desde la primera línea de la segunda entrada hasta la última línea de la ultima entrada aceptada en el fichero.

El primer bucle recorre los días, el segundo las líneas que tenga cada día, y básicamente dentro de ese segundo bucle lo que se hace es leer la línea y voverla a escribir desplazado la cantidad precalculada hacia abajo. El bucle externo (que en realidad sirve el mismo puesto en la función previa, antes de moverlo-escribirlo, para utilizar sus datos), simplemente toma cuenta de cuantas líneas tiene que leer y escribir el segundo bucle...
Al final de ambos bucles la posición del siguiente registro que se fuera a escribir, será el valor a asignar en cabecera.Ultima


Solo restan dos cosas por aclarar:
- Cada nueva entrada se añade al final de las entradas (no del fichero). Con cada entrada se actualiza la cabecera el número de entradas y con cada línea de log a la entrada de un día, el número de líneas para ese día y la posición de escritura d ela siguiente (donde acaba la última escrita)
- El fichero así... puede ser más largo de lo requerido en un día preciso, pero no importa, se supone que pueda tener algunas líneas más de las precisas porque un día se borraron por ejemplo 120 líneas y luego ese día se escribieron 20, siguen quedando 100 al final (sin uso, sucias, pero no computadas), sigue sin importar, puede que dentro de unos días solo borrees 30 y luego escribas 90... considera que de forma absoluta el ficheor no ocupará (se supone) un tamaño mayor de cierto tolerable...
tamaño)... dicho de otro modo, ambos ficheros al tener una estructura fija se comportan como una pila, donde solo importan los x datos del comienzo, sin importar los datos que residan detrás...

Y con esto creo que debiera quedarte todo bastante claro. Naturalmente se entiende que tu pregunta odbedece a que no usar una base de datos si no que lo manejas tu mismo... La copción de escribir un nuevo fichero copiando lo que proceda, eliminar el viejo y renombrar el nuevo, es si cabe más sencilla de 'entender' y quizás de abordar, pero esta otra solución es más óptima a considerar sobretodo si el tamaño de los logs es fijo, tu decides cual usar...
#1654
A ver... de entrada un byte y un carácter (ANSI), son lo mismo una representación con 8 bits...
Ahora bien, los caracteres tienen asociado una representación gráfica, pero sucede que no todos los caracteres son imprimibles, de hecho incluso uno tiene una asociación sonora, y varios juegan un papel de control, por ejemplo el CR al tratar de imprimirlo, genera el salto de línea... el 34, que es las comillas, podría romper una comillas previas, etc...
Entonces no puedes tomar un fichero binario, pasarlo a string, y al ir a imprimirlo, esperar (sin más) ver cada byte ahí con una representación gráfica para cada uno...

Lo que tampoco implica que no puedas hacer lo que persigues... pero dando un pequeño rodeo.
Lee el array de bytes del exe, y lo conviertes a (por ejemplo) Base64 (o Base32, Base16, etc...), que como sabes (o debieras saber, si te dedicas a esto), codifica los bytes a caracteres legibles...

En realidad, lo que hace es tomar (al leer para representarlos) 3bytes de 8 en 8bits y luego leerse 4bytes de 6 en 6bits (pués (3x8) = (4x6) ). Esos 4bytes de 6 bits (6 bits direccionan 64 posiciones), son el índice en una tabla de 64 caracteres, que normalmente son A-Z, a-z, 0-9 más otros dos caracteres que suelen variar según la codificación (esto es a veces se le llama de otra manera).

Luego con el string, haces lo que te dé la gana (por ejemplo guardarlo como un fichero de texto)... más tarde, si lo quieres convertir a un array de bytes, lees el string (o el array de bytes y convertido a string) y finalmente harás la operación inversa... es decir pasar cada 4 bytes de 6 bits a 3 bytes de 8 bits...

En NET puedes usar la codificación UUEncode...

Base32, es similar, pero usa un conjunto de 32 caracteres, igualmente podrías usar Base16 (esto es hexadecimal) para el conjunto de caracteres imprimibles: 0-9, A-F).
#1655
Claro que es un problema que China censure a sus ciudadanos el acceso a información.
Es primordial apra el lavado de cerebro, cortar toda conexión a información que no sea la que sirve para dicho lavado cerebral.

No sería un problema si la población de China fueran unos pocos millones, pero siendo los que son, básicamente es asumir que el 15% de la población mundial está censurada...

Que otros países sigan pasos similares, no es ra´zon para librar de culpas... es como decir que si alguien malo muy malo, mata a 150 personas no es un problema, porque alguien tenido por bueno, haya matado a 2... razonamiento gregario y absurdo.
#1656
Citar¿Pero cuanto dinero les cuesta tener eso alli parado???
Haber si se arruinan en mantenimiento y costes de alimentación y demás, no se.
En alguna parte debe estar, y sea donde sea que esté el coste viene a ser prácticamente el mismo...
Es decir, no cuesta más porque estén tal o cual sitio o en 'casa'... básicamente los portaviones se pasan la 'vida' fuera de casa.

Los portaviones nucleares, tiene una autonomía muy elevada (más de 1 año), y más ahora que se aprovecha mejor la energía, con subsistemas de almacenamiento adicionales. Por ejemplo de la frenada de un avión al 'portarrizar', la energía es almacenada en baterías. el cable que se engancha a una baliza en la cola (del avión), tira de un enrrollamiento sobre una rueda, sumergida parcialmente en un fluído denso (como la noria de un molino de agua), el giro de esa rueda genera una fuerza electromotriz, que se aprovecha para almacenarla en baterías. La densidad del fluído, actúa como un sistema neumático, pero a la inversa (decelerando por tanto el avión en muy poco espacio).
Por su lado, los viejos portaviones diesel, en cambio tenían una autonomía de alrededor de 15 días, lo cual los hacía muy dependientes del suministro y a la vez, vulnerables.

En cuanto a la fragata española de vuelta a puerto, se supone que había firmado un acuerdo de acompañar al portaviones para determinadas misiones, el gobierno de Sánchez, estima que el nuevo destino de Irán, se sale de los acuerdos firmados.
Por otro lado, no hay que olvidar que España tiene 'intereses estratégicos en Irán, ya que gran parte del petróleo que llega a España, pasa por el estrecho de Ormuz, etc, etc... por lo que de una manera u otra, ir contra Irán se entiende como tirar piedras a tu tejado y si no hay una razón sólida (los antojos y amenzasa de Trump, (comparto) no son nada sólidos), parece razonable dejar de hacer de satñélite para el portaviones... aunque reconozco que queda feo, hacerlo después de 'acompañarlo' bastante tiempo, a juicio mío debió decidirse al instante y no esperar a más, porque así se queda mal ante un socio de la OTAN.
#1657
Cita de: digimikeh en 14 Mayo 2019, 01:41 AM
...Pero no me imagino como pueda organizarse todo esto, aun no entiendo como se separa.. por ejemplo, un botón es una mezcla de V y C, porque no solo es algo visual sino que ejecuta una función...
En efecto, así es.

La separación clara solo es de cara a la teoría, en la práctica rara vez suele resultar así, por lo que simplemente hay que sacrificar alguna parte. En general para atenerse de algún modo, estricto, al patrón fuerza casi siempre a dar rodeos en ciertas partes, para lograr lo mismo (A llama a B, B llama a C, y luego C, representa algo en A... cuando directamente ese A, en vez de hacer la pertinente llamada, podría hacer la labor él mismo).

No obstante, al margen de la ineficiencia en la ejecución, suele buscarse la eficiencia en la implementación, al separarlo en partes distintas entre sí, si decides (por ejemplo) cambiar la vista (V), solo cambias esa parte, no necesitas tocar el resto, luego teóricamente resulta menos complejo y por ello más eficiente de abordar... también alejas problemas, si algo falla en la nueva implementación casi que queda claro, que será la implementación de la vista, luego no hay que repasar otras partes...

Es toda esa parte que 'no se ve' a simple vista, la que realmente le da sentido al patrón...
#1658
Trato de explicarte por encima...

La razón por la que un par de primos funciona mejor es bastante obvia (no, antes de que lo explique, claro)...
Un primo distribuye un hash en una de las 'cajas' (o líneas) del array... el otro primo, lo distribuye el hash, dentro de dicha caja... usar un solo primo es como tener un única caja... en la que lo distribuye.
Visto de otra manera: Considera como si fuera un array bidimensional, donde el primer primo selecciona el índice de la primera dimensión y el otro el indice en dicha dimensión, entonces dos hashes que un solo primo fueren a ser contiguos, ahora estarán bastante distantes, incluso en otra caja y ni siquier aocupando la misma posición 'contigua' en la otra caja, lo que logra que 'cadenas' casi iguales queden alejadas...
Un ejemplo: imaginemos (2 hashes obtenidos con un solo primo) cuyos índice absoluto 345678 y 345679, contíguos entre sí usando un solo primo, y supongamos los primos 787 y 797 (que he usado en el ejemplo de la imagen de más abajo), tendremos pués:
h1 = ((345678 modulo 787) * 797) + (345678 modulo 797) = 147445 + 577 = 148022
h2 = ((345679 modulo 787) * 797) + (345679 modulo 797) = 148242 + 578 = 148820
Como se ve, donde antes dos hashes estaban contíguos, ahora están distanciados 802.

En cuanto al porqué es preferible que los primos sean consecutivos, es porque es lo que hace que el 'area' sea lo más cerca posible de un cuadrado... digamos que cuanto más cuadrado más 'bidimensional' y cuanto más alargado resulte el rectángulo más se acerca a la 'unidimensionalidad'...

Considera que se podrían usar por ejemplo 3 primos con las mismas consideraciones, (lo más cercanos entre sí, así tendríamos un volumen (un array de tres dimensiones), e igualmente más primos para más dimensiones, el límite práctico, es el costo asociado al cálculo y también la ocupación de memoria dado que la multiplicación de más de dos primos hace que si un tamaño de array es pequeño para un conjunto dado, el siguiente 'cubículo', quizás sea excesivamente grande, por ejemplo para usar 3 primos: 5*7*11 = 385... supngamos que nuestro array estuviera bien conforme a 400 elementos, al ser 385, resulta insuficiente, pensmaos pués en tomar el siguiente conjunto de primos: 7*11*13 = 1001. Ahora ya, quizás se aleje en exceso y por tanto desperdicie más memoria de la aceptable. Claro que cuando los primos sean muy elevados , la cantidad no sea tan apreciable, pero es algo que claramente va 'a peor', cuantos más primos se utilicen... En tales sitauciones (utilizar varios primos), puede elegirse primos, no necesariamente contiguos que ronden su multiplicación un valor aproximado del tamaño del array adecuado... (en un ejemplo de abajo hago eso mismo, elegir dos primos distantes entre sí, que ofrecen un área más rectangular, pero cuyo producto arroja un array de tamaño muy similar al previo.

Lo normal, cuando desarrollas un algoritmo y necesitas verificar la eficiencia del mismo en diferentes aspectos, es que acabes por construir otros programas que lo pongan a prueba (al menos los aspectos que más interesan que sean verificados como óptimos).

La siguiente imagen procede de una de esas pruebas, se carga un fichero de texto de unas 90.000 líneas, se hashea cada línea (de cada línea se toman unos 44, d elos cuales los 32 últimos son números y letras A-E, para pronunciar la similaridad entre tales cadenas de texto), al caso la tabla tiene un tamaño para distribución de 627.239 elementos, resultado de aplicar los primos 787 * 797.
627.239 / 90.000 = arroja una ocupación de aproximadamente 1/7 de la tabla.

Los píxeles negros, son los huecos sin hash, los de colores los que tienen hash...
A la derecha el color azul simula la ocupación de cada línea, es decir se hace al final un barrido por cada línea, se cuentan los píxeles que no son negros y en la misma proporción del ancho del área azul (que refleja la línea entera) se dibuja en amarillo (que representa la ocupación en esa línea)...
Como se ve, no solo en la distribución de la imagen, si no también en la zona d ela derecha, en cada línea existe una cierta igualdad de prorcion en cuanto a la ocupación.
(hay que hacer scroll horizontal abajo del mensaje, para verlas, también incluyo nota  allí debajo).



Y en la siguiente imagen se ha rehaseado todo de nuevo pero ahora con primos: 607 * 1033, el array ahora (he buscado un par de primos que den un array de tamaño similar) es: 627031, una diferencia poco significativa con la anterior...
Como se ve sobre la imagen la distribución sigue siendo buena, la zona azul (a la derecha), ahora debiera ser más ancha (pués 1033 actúa como el ancho de línea), pero la he recortado al mismo ancho que el resto, para que no distorione la visualización de todas sobre el foro (después de todo es solo contenido azul, yla ocupación es similar 1/7, ya que el tamaño del array ha cambiado el tamaño sin relevancia).
Es importante notar que incluso en un área rectangular el comportamiento sigue siendo mejor que usando un solo primo como módulo.


En esta tercera imagen es lo mismo que la primera, simplemente se ha omitido dibujar las posiciones ocupadas pero sin colisión (puntitos grises), es decir se muestran solo los píxeles donde existen colisiones  (los de 1 colisión es decir 2 hashes chocaron en la misma posición, son los puntitos rojos, los más numerosos ahora).
El propósito de esta imagen es verificar que aún las mismas colisiones también tienen una buena dispersión y que tampoco aparecen amontonadas en una zona específica...


En esta última, solo se dibujan las casillas que tienen colisión, se omiten las casillas no ocupadas, así como las que están ocupadas pero sin o con solo una colisión). El objetivo es ver cuantas posiciones se ven afectadas por más de una colisión... solo añadir que ninguna posición llega a tener más de 6 colisiones, y como se ve, la suma de todas éstas, tampoco son muy numerosas...


NOTA: No ajusto las imágenes para verlas a tamaño real, pués están sin comprimir, para no alterar el contenido, y que al achicarlas para hacerlas tangibles al foro, obviamente la interpolación falsearía, el contenido...
#1659
Yo he realizado algoritmos rápidos y eficientes en cuanto a colisiones con precisamente cadenas (arrays) de pocos caracteres...

Básicamente lo que contará y bastante es el tamaño del array... así conviene dimensionarlo a un tamaño tal que se prevea que no será llenado más de x%... Cuanto más baja sea la ocupación tanta menos probabilidad de colisiones, lógicamente...

Por ejemplo supongamos que pretendes generar 32 hashes, tu array podría ser de no más de 256 elementos... lo cual supone una ocupación de 1/8 del array. Por cuestiones de evitar colisiones conviene que el valor de módulo sea un primo (como bien tienes), luego el primer primo mayor que 256 es 257... ese podría ser el módulo.

Nota que el array si no vas almacenar los hashes en memoria, no lo precisas, pero igualmente el tamaño será el módulo de la función Hash. Es decir si solo vas a calcular hashes y no vas a recuperar valores guardados...

Resolví tanto el problema de colisiones excesivas como su distribución, usando 2 primos en vez de 1, cuyo producto sean no menor que el array (el primo antes usado). Además encontré que lo más óptimo se daba cuando ambos primos eran consecutivos, así  para el array previo del ejemplo de 255 valores, el par de primos 'p' y 'q' son muy válidos '17' y '19' ; 17*19=323, el par previo (13*17= 221) que no contiene la suficiente cantidad de valores...
También encontré que 2 valores (no necesariamente primos), que multiplicados entre sí arrojen un valor equivalente al módulo, eran más eficientes, que usar un solo primo, (y por supuesto que usar el valor límite del array) así por ejemplo para el mismo array de ejemplo 'p' y 'q' podrían ser '15' y '17' (15*17=255), como mejor que usar el módulo 257 (o el límite del array 255).

Aquí uno de los algoritmo que utilizo, para pequeñas cadenas de texto o arrays (nota que los valores primos dependerán pués de la cantidad máxima de valores que consideres y la ocupación máxima que uno estuviere dispuesto a utilizar, en función siempre de la memoria del equipo, etc... es decir que hay que afinar dichos parámetros a valores consecuentes):

El algoritmo está pensado también para eficiencia en velocidad, por lo cual de entrada recibe un array de bytes...

// id es el array de bytes (los caracteres de una 'key', por ejemplo)
//  'p' y 'q' son los primos, que hacne de módulo...
int = Funcion Hashing(array bytes Id() , int P , int Q )
   int k As Long, j, t, h, max,n
   int grupos, resto, ultimos
   Constante T15 = 15
   Constante T03 = 3
   Constante SIZE_2_30 = ((2 ^ 30) - 1)   // pensado para no superar un entero de 32 bits con signo, ni pelearse con errores de desbordamiento...
       
   max = sizearray(Id)  //tamaño del array
   ultimos = (max Modulo T03)
   max = (max - ultimos - 1)
   
   // Si de seguro tus hashes no van a tener más de 15 bytes, este bloque puede ser omitido.
   // Se hacen iteraciones sobre grupos de hasta 15 bytes
   grupos = (max \ T15)   //división entera...
   Si (grupos > 0) luego
       bucle para k = 0 To (max - 1 - T15) enIncrementosDe T15
           // en cada ciclo se procesan 3 bytes, el bucle entero serían pués 5 iteraciones.
           Hacer
               t = ((Id(k + n) - n) * (Id(k + n + 1)) * (Id(k + n + 2) + (n + 2)))
               h = (h + t)
               n = (n + T03)
           Repetir mientras (n < T15)
           h = (h Modulo SIZE_2_30)  // para evitar desbordamientos... el array podría ser hasta de MB. de largo...
           n = 0
       Siguiente
   Fin si
   
   
   // Cantidad de bytes que no caben en un 'grupo', es decir que no llegan a 15 bytes... pero todavía tiene más de 2 bytes...
   resto = (max Modulo T15)
   Si (resto > 0) luego
       Hacer  // el bucle 'do loop' es idéntico al previo... excepto el valor límite del bucle
           t = ((Id(k + n) - n) * (Id(k + n + 1)) * (Id(k + n + 2) + (n + 2)))
           h = (h + t)
            n = (n + T03)
       Repetir mientras (n < resto)
   Fin si
   
   // 1 ó 2 Ultimos bytes (o los únicos cuando solo haya 1 ó 2 bytes).
   Si (ultimos > 0) luego
       Si (ultimos = 1) luego
           h = ((SIZE_2_30 - h) + Id(max-1))  // el último para evitar desbordamiento en tabla.
       Sino
           h = ((SIZE_2_30 - h) + (Id(max - 2) * (Id(max-1))))
       Fin si
   Fin si
   
   Hashing = (((h Modulo P) * Q) + (h Modulo Q))
Fin Funcion


Nota que la constante 'size_2_30' arroja un valor de 1.073 millones... aunque manejases tipos de datos de 64 bits, deja que ese valor permita ir devolviendo siempre el resto cuando lo sobrepase....


Debes crearte una función para obtener los dos primos:
Si vas a usarlos en muchas partes (como me pasa a mi), donde se dan distintas circunstancias, mejor un pequeño puñado de funciones, para resolver distintas situaciones...


int p_SizeArray, p_PrimoP, p_PrimoQ    
buleano Inicializado

// ========================================================================
// ========= Establecer el par de Primos y el tamaño de la tabla: =========
// ========================================================================

// Es decir sin el par de primos... (caso de querer usar 1 solo valor como módulo, que resulta ser el tamaño del array)
Funcion PorSizeFijo(int Size )
   Si (Inicializado = False) luego
       p_SizeArray = Size
       Inicializado = True      
   Fin si
Fin funcion

//Una función delega en otra, así puede usarse cualquiera para generar el par de 'primos' según interese...

// Por un tamaño, de cuya raíz cuadrada se busca el primo anterior y siguiente a dichos valores.
Funcion PorSizeArray(buleano AseguraMinimo, ref int Size)
   LlamarA  PorPrimoMenor ( (SQR(Size)).ToInt)

   Si AseguraMinimo luego
       Si (p_SizeArray < Size) Luego
           Inicializado = False
           LlamarA PorPrimoMenor (p_PrimoQ)
       Fin si
   Fin si
Fin funcion

// Por el primo menor (que se trunca al primo menor que el valor si no lo es), y el primo siguiente a éste.
Funcion PorPrimoMenor(ref int V)
   LlamadaA PorPrimos(0, V)
Fin Funcion

// Por los primos recibidos (Se truncan al primo menor y mayor que los respectivos valores recibidos, si no son primos).
Funcion PorPrimos(ref int Q, ref  int V)
   LlamadaA BuscaPrimos(V, Q)
   LlamadaA PorValores(Q, V)
Fin Funcion

// Los valores designados (sean primos o no)
//     Al caso: si se llama desde fuera pueden no ser primos,
//                  pero si es reinvocado desde otras funciones internas, ambos serán primos.
// Notar que en todas las funciones previas, los parámetros son devuelto modificados por referencia.
//     aquí en cambio son por valor, y se asignan ya internamente...
Funcion PorValores(int Q, int V)
   Si (Inicializado = False) Luego
       p_PrimoP = Size
       p_PrimoQ = Q
       p_SizeArray = (p_PrimoP * p_PrimoQ)
       Inicializado = True
   Fin si
Fin funcion



Faltan, ahora las funciones de cálculo de primos... obviamente el contenido de EsPrimo(int Valor) la dejo a tu esfuerzo...


function BuscaPrimos(ref int P, ref int Q )
   Si (EsPrimo(P) = False) Luego
       P = PrimoAnterior(P)
   Fin si
   
   Si (Q = 0) Luego
       Q = PrimoSiguiente(P)
   Sino
       Si (EsPrimo(Q) = False) Luego
           Q = PrimoSiguiente(Q)
       Fin si
   Fin si
Fin funcion

// haya el anterior número primo al valor recibido.
int = Funcion PrimoAnterior(int Valor)
   Si (Valor >= 4) Luego
       Si (Valor And 1) = 0 Luego
             Valor = (Valor + 1) // porque luego se restan 2.
       Fin si

       Hacer
           Valor = (Valor - 2)
       Repetir Mientras ((EsPrimo(Valor) = False) And (Valor > 2))  
   Sino
       Valor = (Valor - 1)
   Fin si
   
   Devolver Valor
Fin Funcion

// haya el siguiente número primo al valor recibido.
int = Funcion PrimoSiguiente(int Valor)
   Si (Valor And 1) = 0 Luego
       Valor = (Valor - 1)  // porque luego se suman 2.
   Fin si

   Hacer
       Valor = (Valor + 2)
   Repetir Mientras (EsPrimo(Valor) = False)
   
   Devolver Valor
Fin Funcion

// Debe devolver si el valor entrado es o no es primo.
buleano = Funcion EsPrimo(int Valor)
    // Esta función queda a tu esfuerzo...
Fin funcion


Un modo luego de obtener tales primos, es susurrar a la función específica partiendo del tamaño del array previsto (que será algo más grande, finalmente)...

Por ejemplo si el tamaño del array sería aprox. 255, se le pasa dicho valor a la función:
LlamadaA PorSizeArray(TRUE, 255)
Y nos devolverá para el par de primos los valores:
p_PrimoP = 17
p_PrimoQ = 19

Así como el tamaño final del array:
p_SizeArray = (p_PrimoP * p_PrimoQ) = 323

Si quieres forzar que sea 255 o lo más parecido posible, entonces usas la función:
LlamadaA PorValores(15, 17)
Y nos devolverá para el par de primos los valores:
p_PrimoP = 15
p_PrimoQ = 17
p_SizeArray = (p_PrimoP * p_PrimoQ) = 255



Ahora reserva memoria para tu array conforme a su tamaño y el tipo de datos que alojará... Si va de 0 a 255, el tipo de datos puede ser byte (por ejemplo)...
Finalmente tendrás tu hash...


int hash

hash =  Hashing(array bytes Key(), p_PrimoP, p_PrimoQ)


Si se crea una clase, lo idela es que ambos primos se crearan con el constructor de la instancia y que la propia función ya los usara sin necesidad de pasarlos como parámetros....
Por otro lado, la función hash podría ser estática en un  módulo, y cada instancia realmente invocar a esa estática, con los primos que dicha instancia tenga asignados. Es la situación ideal si tienes que generar hashes para diferentes campos y arrays de diferentes tamaños...


Tenía por ahí, un proyecto de prueba para modificar el tamaño del array (calcular los primos), la ocupación y mostrar gráficamente la distribución... pero no lo localizo, a ver si hay suerte y mañana doy con él... La distribución resulta increíblemente genial. No obstante por si no lo localizo o se me olvida, te describo brevemente en que consistía:

De momento céntrate en la función de hash, y pruébala con un array de pongamos 100.000 elementos, de la que ocupes pongamos un 20% para probar la distribución... usa ambos primos como si fueran sendos valores para el tamaño de filas y columnas, de un bitmap... deja en color negro cada 'píxel' (índice) que en el array está vacío, pinta de blanco el índice con cada casilla (hash) sin colisión y de otro color (por ejemplo rojo, para 1 colisión, verde para 2, azul para 3, amarillo para 4, violeta para más de 4), totaliza también cuántas colisiones tiene el hash que más haya colisionado, etc... tu mismo... Con un bittmap, creado así es fácil ver si la dispersión si es buena o mala, además ambos primos dan para un bitmap incluso de millones de píxeles (un array de varios millones, con lo que permite ver si además de comportarse bien con pequeños arrays lo hace bien también con otros más grandes)...
#1660
Programación General / Re: C++ y Python
12 Mayo 2019, 19:18 PM
Cita de: string Manolo en 12 Mayo 2019, 18:54 PM
La eleccion de lenguaje se hace pensando en la finalidad que se le va a dar a este. Supongo que si elegio C++ será por algo.
Efectivamente... ese algo suele ser muchas veces el 'consejo' de alguien, o la 'tendencia', el 'contínuo cacareo'... al principio no tiene importa.

Lo claro, es que con el tiempo, cada cual tiene que sentirse a gusto con el lenguaje que tiene entre manos, si no es así, no llegará muy lejos... y no digo que tome decisiones al cabo de 3 semanas, 1 año es tiempo más que suficiente para saber si amas u odias un lenguaje, conceder más tiempo entra en el rango de tonto resignado.