elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP)
| | | |-+  Programación Visual Basic (Moderadores: LeandroA, seba123neo)
| | | | |-+  [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] 2 Ir Abajo Respuesta Imprimir
Autor Tema: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )  (Leído 12,087 veces)
BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
[Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« en: 28 Mayo 2011, 10:47 am »

.

@Psyke1

Mas que una matriz quedaría precioso en una clase... al rato lo traslado a una clase para aumentar la velocidad de procesamiento, ya que de este modo se le aumenta el peformance ( en relación procesador/tiempo, pero no memoria ) con una clase.


Este código es una mera actualización directa de este otro, se puede decir que es la version 2.0

[source] Números Aleatorio desde X a Y con excepciones.

Vaya solo le falta una opción a mi punto de vista y es meterle una lista de números antes de generar alguno tal cual se le hace en la función solo que ahora seria una propiedad, y podría modificarse en cualquier instante, pero eso se los dejo a ustedes, yo ya hice mi labor.

* El ordenamiento QuickSort se sustituyo por una heuristica mas eficiente.

En un modulo de clase:

cRndNumbersNR.cls

Código
  1.  
  2. '
  3. ' ////////////////////////////////////////////////////////////////
  4. ' // Autor: BlackZeroX ( Ortega Avila Miguel Angel )            //
  5. ' //                                                            //
  6. ' // Web: http://InfrAngeluX.Sytes.Net/                         //
  7. ' //                                                            //
  8. ' // |-> Pueden Distribuir Este Codigo siempre y cuando         //
  9. ' // no se eliminen los creditos originales de este codigo      //
  10. ' // No importando que sea modificado/editado o engrandesido    //
  11. ' // o achicado, si es en base a este codigo                    //
  12. ' ////////////////////////////////////////////////////////////////
  13.  
  14. Option Explicit
  15.  
  16. Private Declare Function VarPtrA Lib "msvbvm60.dll" Alias "VarPtr" (ByRef Ptr() As Any) As Long
  17. Private Declare Sub lCopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal Destination As Long, ByVal Source As Long, ByVal Length As Long)
  18.  
  19. Private Type stRangos
  20.    lValIni         As Long
  21.    lValEnd         As Long
  22. End Type
  23.  
  24. Private lcvalmax    As Long
  25. Private lcvalmin    As Long
  26.  
  27. Private lvcsplit()  As stRangos
  28. Private lacexcep()  As Long
  29.  
  30. Private bChange     As Long
  31.  
  32. Private Sub Swapnumbers(ByRef lvalone As Long, ByRef lvaltwo As Long)
  33. '   //  Intercambia el contenido de las variables.
  34. Dim lvaltmp         As Long
  35.    lvaltmp = lvalone
  36.    lvalone = lvaltwo
  37.    lvaltwo = lvaltmp
  38. End Sub
  39.  
  40. Private Function Fixnumbers(ByRef lvalmin As Long, lvalmax As Long) As Boolean
  41. '   //  Corrige los valores dados.
  42.    If lvalmax < lvalmin Then
  43.        Call Swapnumbers(lvalmin, lvalmax)
  44.        Fixnumbers = True
  45.    End If
  46. End Function
  47.  
  48. Private Function NumRandom(lvalmin As Long, lvalmax As Long) As Long
  49. '   //  Genera un Numero aleatorio de acuerdo a un rango dado.
  50.    Call Fixnumbers(lvalmin, lvalmax)
  51.    Call Randomize
  52.    NumRandom = (lvalmin - lvalmax) * Rnd + lvalmax
  53. End Function
  54.  
  55. Public Sub Reset()
  56. '   //  Reinicia y permite nuevamente generar los números aleatorios desde el principio, si no aplica este al generar todos los numeros, entonces no generara mas números y devolverá únicamente 0..
  57.    Erase lvcsplit()
  58.    Erase lacexcep()
  59.    ReDim lvcsplit(0 To 0)
  60.    lvcsplit(0).lValIni = lcvalmin
  61.    lvcsplit(0).lValEnd = lcvalmax
  62.    bChange = False
  63. End Sub
  64.  
  65. Public Property Get GetMore() As Boolean
  66. '   //  Hay mas ocurrencias? cuando ya no hay se elimina el array de ocurrencias.
  67.    GetMore = Itsarrayini(VarPtrA(lvcsplit)) Or bChange = True
  68. End Property
  69.  
  70. Private Function Itsarrayini(ByVal lpszv As Long, Optional llen As Long = 4) As Boolean
  71. '   //  Obtiene el limite superior de los numeros a generar de manera aleatoria sin repetir.
  72. Dim lpsz                    As Long
  73.    If lpszv <> 0 And llen > 0 Then
  74.        Call lCopyMemory(ByVal VarPtr(lpsz), ByVal lpszv, llen)
  75.        Itsarrayini = Not lpsz = 0
  76.    End If
  77. End Function
  78.  
  79. Private Sub SeparateRange(ByVal lDivVal As Long, ByVal lindex As Long, ByRef vArray() As stRangos)
  80. '   //  Es un proceso para aplicar el dicho "Divide y Venceras", esto aumenta mucho la velocidad para no repetir numeros dentro de un rango dado y generados de manera aleatoria.
  81. '   //  Repeti un poco de codigo lo siento xP...
  82. Dim lu          As Long
  83. Dim lpsz        As Long
  84.  
  85.    If (vArray(lindex).lValIni <= lDivVal And lDivVal <= vArray(lindex).lValEnd) Then
  86.        lu = UBound(vArray)
  87.        lpsz = VarPtr(vArray(lindex))
  88.        If (vArray(lindex).lValIni = lDivVal) Then
  89.            vArray(lindex).lValIni = vArray(lindex).lValIni + 1
  90.            If (vArray(lindex).lValIni > vArray(lindex).lValEnd) Then
  91.                If (lu > 0) Then
  92.                    lCopyMemory lpsz, lpsz + &H8, ((lu - lindex) * &H8)
  93.                    lu = lu - 1
  94.                    ReDim Preserve vArray(0 To lu)
  95.                Else
  96.                    Erase vArray()
  97.                End If
  98.            End If
  99.        ElseIf (vArray(lindex).lValEnd = lDivVal) Then
  100.            vArray(lindex).lValEnd = vArray(lindex).lValEnd - 1
  101.            If (vArray(lindex).lValIni > vArray(lindex).lValEnd) Then
  102.                If (lu > 0) Then
  103.                    lCopyMemory lpsz, lpsz + &H8, ((lu - lindex) * &H8)
  104.                    lu = lu - 1
  105.                    ReDim Preserve vArray(0 To lu)
  106.                Else
  107.                    Erase vArray()
  108.                End If
  109.            End If
  110.        Else
  111.            lu = lu + 1
  112.            ReDim Preserve vArray(0 To lu)
  113.            lpsz = VarPtr(vArray(lindex))
  114.            lCopyMemory lpsz + &H10, (lpsz + &H8), (((lu - 1) - lindex) * &H8)
  115.            vArray(lindex + 1).lValEnd = vArray(lindex).lValEnd
  116.            vArray(lindex + 1).lValIni = (lDivVal + 1)
  117.            vArray(lindex).lValEnd = (lDivVal - 1)
  118.  
  119.        End If
  120.    End If
  121.  
  122. End Sub
  123.  
  124. Public Property Get GetNumRandom() As Long
  125. '   //  Genera un numero aleatorio sin repetir de acuerdo a un rango de valores dados.
  126. Dim lindex          As Long
  127. Dim lu              As Long
  128. Dim lret            As Long
  129.    If (bChange = True) Then
  130.        Call Fixnumbers(lcvalmin, lcvalmax)
  131.        Call Reset
  132.    End If
  133.    If (GetMore = True) Then
  134.        lindex = NumRandom(0, UBound(lvcsplit))
  135.        lret = NumRandom(lvcsplit(lindex).lValIni, lvcsplit(lindex).lValEnd)
  136.        SeparateRange lret, lindex, lvcsplit
  137.        If (Itsarrayini(VarPtrA(lacexcep)) = True) Then
  138.            lu = UBound(lacexcep) + 1
  139.        Else
  140.            lu = 0
  141.        End If
  142.        ReDim Preserve lacexcep(0 To lu)
  143.        lacexcep(lu) = lret
  144.        GetNumRandom = lret
  145.    End If
  146. End Property
  147.  
  148. Public Property Let minval(ByVal ldata As Long)
  149. '   //  Establece el limite inferior de los numeros a generar de manera aleatoria sin repetir.
  150.    lcvalmin = ldata
  151.    bChange = True
  152. End Property
  153.  
  154. Public Property Get minval() As Long
  155. '   //  Obtiene el limite inferior de los numeros a generar de manera aleatoria sin repetir.
  156.    minval = lcvalmin
  157. End Property
  158.  
  159. Public Property Let maxval(ByVal ldata As Long)
  160. '   //  Establece el limite superior de los numeros a generar de manera aleatoria sin repetir.
  161.    lcvalmax = ldata
  162.    bChange = True
  163. End Property
  164.  
  165. Public Property Get maxval() As Long
  166. '   //  Obtiene el limite superior de los numeros a generar de manera aleatoria sin repetir.
  167.    maxval = lcvalmax
  168. End Property
  169.  
  170. Public Property Get GetNumbers() As Long()
  171. '   //  Devueve una coleccion de los numeros generados.
  172.    GetNumbers() = lacexcep()
  173. End Property
  174.  
  175. Public Function RegenerateThis(ByVal lVal As Long) As Boolean
  176. Dim ii              As Long
  177. Dim lub             As Long
  178.    If (lcvalmin <= lVal) And (lcvalmax >= lVal) Then
  179.        If (breglist = True) Then
  180.            If (Itsarrayini(VarPtrA(lacexcep)) = True) Then
  181.                For ii = 0 To UBound(lacexcep)
  182.                    If (lacexcep(ii) = lVal) Then
  183.                        RemoveInArrayLong ii, lacexcep()
  184.                        Exit For
  185.                    End If
  186.                Next ii
  187.            End If
  188.        End If
  189.        If (Itsarrayini(VarPtrA(lvcsplit)) = True) Then
  190.            lub = UBound(lvcsplit)
  191.            For ii = 0 To (lub - 1)
  192.                If (lvcsplit(ii).lValEnd > lVal) And (lvcsplit(ii + 1).lValIni < lVal) Then
  193.                    If ((lvcsplit(ii).lValEnd + 1) = lVal) Then
  194.                        lvcsplit(ii).lValEnd = lVal
  195.                    ElseIf ((lvcsplit(ii + 1).lValIni) = lVal) Then
  196.                        lvcsplit(ii + 1).lValIni = lVal
  197.                    End If
  198.                    Select Case (lvcsplit(ii).lValEnd = lvcsplit(ii + 1).lValIni)
  199.                        Case 0, 1
  200.                            lub = (lub - 1)
  201.                            lvcsplit(ii).lValEnd = lvcsplit(ii + 1).lValEnd
  202.                            ReDim Preserve lvcsplit(0 To lub)
  203.                        Case Else
  204.                            If Not ((lvcsplit(ii).lValEnd + 1) = lvcsplit(ii + 1).lValIni) Then
  205.                                lub = (lub + 1)
  206.                                ReDim Preserve lvcsplit(0 To lub)
  207.                                SwapBlockMemoryInCicle VarPtr(lvcsplit(ii)), (VarPtr(lvcsplit(lub)) + LenB(lvcsplit(0))), LenB(lvcsplit(0))
  208.                                lvcsplit(ii + 1).lValIni = lVal
  209.                                lvcsplit(ii + 1).lValEnd = lVal
  210.                            End If
  211.                    End Select
  212.                    RegenerateThis = True
  213.                Else
  214.                    Exit For
  215.                End If
  216.            Next ii
  217.        Else
  218.            ReDim lvcsplit(0 To 0)
  219.            lvcsplit(0).lValIni = lVal
  220.            lvcsplit(0).lValEnd = lVal
  221.        End If
  222.    End If
  223. End Function
  224.  
  225. Private Sub Class_Initialize()
  226. '   //  Constructor de la clase, no tengo por que hacer lo siguiente pero como me estoy adaptando a un standart lo hare.
  227.    bChange = False
  228. End Sub
  229.  
  230.  

uso simple:

Código
  1.  
  2. Option Explicit
  3.  
  4. Private Sub Form_Load()
  5. Dim cls     As cRndNumber
  6. Dim lc      As Long
  7.    Set cls = New cRndNumber
  8.    With cls
  9.    '   //  Este simple codigo probara la velocidad, que de hecho ya es rapido a consideracion de otros que conozco.
  10.        .minval = 0
  11.        .maxval = 99999
  12.        Do While (.GetMore = True)
  13.            DoEvents
  14.            lc = .GetNumRandom
  15.        Loop
  16.        MsgBox "Se recorrieron todos los numeros sin repetir alguno xD"
  17.    '   //  Si se cambian los valores menor y mayor entonces es como si se le aplicara call .Reset
  18.    '   //  Este codigo hara un test de repeticion
  19.        .minval = 0
  20.        .maxval = 99
  21.        Do While (.GetMore = True)
  22.            DoEvents
  23.            Debug.Print .GetNumRandom
  24.        Loop
  25.  
  26.        MsgBox "Se recorrieron todos los numeros sin repetir alguno xD"
  27.    End With
  28. End Sub
  29.  
  30.  

Temibles Lunas!¡.


« Última modificación: 8 Junio 2011, 02:02 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
Psyke1
Wiki

Desconectado Desconectado

Mensajes: 1.089



Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #1 en: 28 Mayo 2011, 13:24 pm »


 :laugh:
Wow, impresionante, y rapidísimo también. :D
La única cosa que hecho en falta es la posibilidad de excluir números. :)
Ya pensaré algo... :rolleyes:

PD: ¿Algún año de estos seguiremos con nuestro proyecto secreto? :silbar: :xD

DoEvents! :P


« Última modificación: 28 Mayo 2011, 14:10 pm por Psyke1 » En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #2 en: 29 Mayo 2011, 04:11 am »


La única cosa que hecho en falta es la posibilidad de excluir números. :)
Ya pensaré algo... :rolleyes:


PISTA:
Debes buscar el indice del array donde se encuentre el valor a excluir y pasarlo por la función:

Private Sub SeparateRange(ByVal lDivVal As Long, ByVal lindex As Long, ByRef vArray() As stRangos)

Reformando la funcion ItsInArray se puede hacer, no me gustaría ver un For Next que recorra todos elementos del array ya que es algo muy feo y no entra en la relación Tiempo-Procesador ya que alentaria mucho el proceso.

Dulces Lunas!¡.
En línea

The Dark Shadow is my passion.
Psyke1
Wiki

Desconectado Desconectado

Mensajes: 1.089



Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #3 en: 29 Mayo 2011, 10:15 am »

.
mmmmmmmmmmmm
Ook, pensaré algo... :rolleyes:

DoEvents! :P
En línea

Psyke1
Wiki

Desconectado Desconectado

Mensajes: 1.089



Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #4 en: 29 Mayo 2011, 20:34 pm »

Quizás puedas ahorrarte los RedimPreserve() que gastan mucho tiempo y redimensionarlo cada 1024 elementos.
¿Y para devolverlos en la propiedad GetNumbers() sería más rápido copiando el array CopyMemory()? :huh:

DoEvents! :P
En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #5 en: 29 Mayo 2011, 22:02 pm »

'
1024*4 = 4096  = 4kb's ---> Cache eso me estas sugiriendo?, aun así la probabilidad de que se ocupe la clase en un bucle tal cual lo hago es baja.

GetNumbers() se puede usar Set también no tengo idea si se aumenta la velocidad...

P.D.: Psyke1 -> Estoy saturado de tarea... lo bueno que ya entro para el ciclo vacacional en 5 días.

Dulces Lunas!¡.
En línea

The Dark Shadow is my passion.
Psyke1
Wiki

Desconectado Desconectado

Mensajes: 1.089



Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #6 en: 30 Mayo 2011, 00:35 am »

Algo así, por ejemplo:

Código
  1. '...
  2.  
  3. Public Property Get GetNumRandom() As Long
  4. '   //  Genera un numero aleatorio sin repetir de acuerdo a un rango de valores dados.
  5. Dim lindex          As Long
  6. Dim lu              As Long
  7. Dim lret            As Long
  8.    If (bChange = True) Then
  9.        Call Fixnumbers(lcvalmin, lcvalmax)
  10.        Call Reset
  11.    End If
  12.    If (GetMore = True) Then
  13.        lindex = NumRandom(0, UBound(lvcsplit))
  14.        lret = NumRandom(lvcsplit(lindex).lValIni, lvcsplit(lindex).lValEnd)
  15.        SeparateRange lret, lindex, lvcsplit
  16.        If (Itsarrayini(VarPtrA(lacexcep)) = True) Then
  17.            lu = UBound(lacexcep) + 1
  18.            If (lu Mod &H3FF) = 0 Then '# si la matriz tiene 1024 elementos (lo puedes hacer con And también)
  19.                ReDim Preserve lacexcep(0 to (lu + &H400)) '# le añadimos 1024 más...
  20.            End If
  21.        Else
  22.            lu = 0
  23.            Redim lacexcep(0)
  24.        End If
  25.        lacexcep(lu) = lret
  26.        GetNumRandom = lret
  27.    End If
  28. End Property
  29.  
  30. '...
  31.  
  32. Private Sub Class_Initialize()
  33. '   //  Constructor de la clase, no tengo por que hacer lo siguiente pero como me estoy adaptando a un standart lo hare.
  34.    ReDim lacexcep(&H3FF) '# iniciamos la matriz con 1024
  35.    bChange = False
  36. End Sub


En cuanto a lo de copiar la matriz... :rolleyes:
Hice este test y... :o ¡sorpresa!
Gana RtlMoveMemory() ;-)

Código
  1. Option Explicit
  2. Private Declare Sub RtlMoveMemory Lib "kernel32.dll" (ByVal Destination&, ByVal Source&, ByVal Length&)
  3.  
  4. Private Sub Form_Load()
  5. Const Max& = 999990
  6. Dim q&, a&(Max), b&(), t As New CTiming
  7.    Me.AutoRedraw = True
  8.  
  9.    ReDim b&(Max)
  10.  
  11.    For q = 0 To Max
  12.        a(q) = q
  13.    Next q
  14.  
  15.    t.Reset
  16.    RtlMoveMemory VarPtr(b(0)), VarPtr(a(0)), (Max + Max + Max + Max + 4) '// Procuro evitar multiplicaciones...
  17.    Me.Print "RtlMoveMemory", t.sElapsed
  18.  
  19.    ReDim b&(Max)
  20.  
  21.    t.Reset
  22.    b = a
  23.    Me.Print "Igualación", , t.sElapsed
  24.  
  25.   '// Con Set me tiraba error... xP
  26. End Sub

Resultado:


DoEvents! :P
« Última modificación: 30 Mayo 2011, 12:16 pm por Psyke1 » En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #7 en: 30 Mayo 2011, 01:40 am »

.
OK, yo pensaba que decias por el array de stRangos (lvcsplit) .

No hagas el test de esa manera,:

estas aplicando la relación:

Variable -> a -> Variable

la debes aplicar

(Miembro de clase)Propiedad -> a -> Variable

La diferencia radica en que en una no hay PILA de datos y en otra si.

Dulces Lunas!¡.
« Última modificación: 30 Mayo 2011, 01:43 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
Psyke1
Wiki

Desconectado Desconectado

Mensajes: 1.089



Ver Perfil WWW
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #8 en: 30 Mayo 2011, 12:12 pm »

.
OK, yo pensaba que decias por el array de stRangos (lvcsplit) .

No hagas el test de esa manera,:

estas aplicando la relación:

Variable -> a -> Variable

la debes aplicar

(Miembro de clase)Propiedad -> a -> Variable

La diferencia radica en que en una no hay PILA de datos y en otra si.

Dulces Lunas!¡.
Sería genial que la técnica esa la emplearas también con vArray(), puesto que las estructuras pesan 8 Bytes.
Es cierto lo que dices, en el test no conté con eso... :silbar:
Está bien como está. :)

Pd1:
Código
  1. Public Property Get maxval() As Long
  2. '   //  Obtiene el limite superior de los numeros a generar de manera aleatoria sin repetir.
  3.    minval = lcvalmax '// Sería maxval
  4. End Property


Pd2: Estaría genial que pusieras más ejemplos usando todas las propiedades para que a la gente le quedara más claro. :rolleyes:

Pd3:
Citar
P.D.: Psyke1 -> Estoy saturado de tarea... lo bueno que ya entro para el ciclo vacacional en 5 días.
Ook, comienza la cuanta atrás... :xD

DoEvents! :P
« Última modificación: 30 Mayo 2011, 12:32 pm por Psyke1 » En línea

Karcrack


Desconectado Desconectado

Mensajes: 2.416


Se siente observado ¬¬'


Ver Perfil
Re: [Src] cRndNumbersNR ( Generar números aleatorios sin repetir [Very-Fast] )
« Respuesta #9 en: 30 Mayo 2011, 16:36 pm »

Mi granito de arena; Una forma más rápida de hacer el Swapnumbers() sin usar variable temporal:
Código
  1. Private Sub Swapnumbers(ByRef l1 As Long, ByRef l2 As Long)
  2.    l1 = l1 Xor l2
  3.    l2 = l2 Xor l1
  4.    l1 = l1 Xor l2
  5. End Sub

También acelerararias un poco si enlazases RtlMoveMemory() directamente desde NTDLL y no desde KERNEL32 ;)
« Última modificación: 30 Mayo 2011, 16:39 pm por Karcrack » En línea

Páginas: [1] 2 Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines