Zufallswert mit Maximum aus 8-Bit Zufallswert ohne Bias

  • Allgemein

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    @petaod
    Ist deine Ziel-Plattform so unperformant, dass das ein Problem ist?

    In Post #7, Niko Ortner schrieb:

    Die Hardware ist stark limitiert. [...] Und es gibt keinen Hardware-Multiplizierer, das heißt ich muss einen Faktor so oft mit sich selbst addieren, wie vom zweiten Faktor angegeben. Ähnlich beim Dividieren und Modulo. *hust* Relay Computer *hust*


    @3daycliff
    berechnet einfach das Größte Vielfache von 126, was kleiner als 256 ist.

    Ahaaa! Jetzt hat's klick gemacht. Und das geht auch relativ einfach zu berechnen.
    Ok, ich bin dann mal am Basteln.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    <p>Es l&auml;sst sich keine Aussage treffen, wurde lange eine derartige Operation effektiv dauern wird, im schlimmsten Fall... Sehr sehr lange.</p>

    <p>Bei meinem Algorithmus ist das Problem, dass ich nicht beachtet habe, dass Additionen die Wahrscheinlichkeit nat&uuml;rlich gen Mitte verschiebt. Vielleicht setze ich mich echt nachher nochmal ran.</p>

    <p>Viele Gr&uuml;&szlig;e</p>

    <p>~blaze~</p>

    Niko Ortner schrieb:

    es gibt keinen Hardware-Multiplizierer
    Ist schon eine komische Prozessor-Architkektur.
    Random liegt in einem Register, aber Multiplikation ist nicht unterstützt.
    Wenn dem so ist, würde ich behaupten, dass Random einfach aus dem Tick-Counter entsteht und das ist bei kurz nacheinander abgesetzten Calls kein echter Zufall mehr.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Ggf., aber es kann auch sein, dass weitere Faktoren einfließen.
    Ich schaffe es ehrlich gesagt im Moment auch nicht auf eine günstigere Verteilung, mit Xor stelle ich mich auch zu blöd an, der Wertebereich bleibt bei 0..63 statt 0..100, weil ich irgendeinen Blödsinn übersehe und gerade nicht wirklich Lust auf Programmierung habe. Du kannst ja mal schauen, dass du den Algorithmus, den du mit Addition geliefert hast, auf eine homogene Verteilung umschreibst. Sollte durch geschickte Operationen möglich sein. Wahrscheinlich müsste man einfach nur eine Abhängigkeit des (i+1). Bits vom i. Bit einführen.

    Viele Grüße
    ~blaze~
    So, jetzt grab ich hier nochmal rum.
    Da ich Multiplikation, Division und Modulo jetzt in Hardware implementiert habe (siehe hier) hab ich mich jetzt nochmal an die Zufallszahlen rangesetzt.
    Im Simulator werden die Zufallszahlen von 0 bis 255 von System.Random generiert. Also die haben kein Bias (das hab ich auch nochmal sicherheitshalber getestet).
    Division und Modulo funktionieren auch.
    Ich hab mich für die Methode von 3daycliff entschieden und die mal testweise implementiert. Den Code hab ich mal angehängt. Ist etwas vereinfacht und ich habe mich bemüht, grob mit Kommentaren zu erklären, was passiert.
    Spoiler anzeigen

    Die Calling Convention ist wie folgt:
    1. Platz für Return-Wert(e) auf dem Stack reservieren (einfach irgendwas pushen)
    2. Argumente auf den Stack legen
    3. Call an Methode
    4. In der Methode kann man dann beginnend bei Frame[0] lokale Variablen auf dem Stack reservieren.
    5. Auf Argumente und Return-Werte kann bei Frame[-5] und abwärts zugegriffen werden, also bei 1 Byte Return-Wert und 4 Bytes an Argumenten liegt der Return-Wert bei Frame[-9] und die Argumente in der Reihenfolgen, in der sie auf den Stack gelegt wurden, bei Frame[-8] bis Frame[-5]. Hinweis: negative Offsets werden ins Zweierkompliment überführt und in 2 Bytes aufgeteilt (das höherwertige zuerst). Also mit Frame[Const] = C; 255; 251 ist Frame[-5] gemeint. @Label fügt die Adresse des Labels in den Code ein. Also nach Call Const folgt die Adresse der Methode, zu der gesprungen wird.
    6. Return
    7. Argumente vom Stack entfernen
    8. Return-Wert(e) vom Stack entfernen und verwenden

    VB.NET-Quellcode

    1. Lab Main
    2. 'Eingang 0 ist MaxExclusive
    3. Push C 'Platz für Return-Wert
    4. C = I0
    5. Push C '1.Argument
    6. Call Const
    7. @System_Random_Byte__Byte
    8. Pop C '1. Argument entfernen
    9. Pop C 'Return-Wert entfernen ...
    10. O0 = C 'und verwenden
    11. Goto Absolute Const
    12. @Main
    13. 'Äquivalent in ~VB
    14. Public Function Random(MaxExclusive As Byte) As Byte
    15. Dim BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 As UInt16 = 256 - (256 Mod MaxExclusive)
    16. Dim RandomNumber As Byte
    17. Do
    18. RandomNumber = Rnd
    19. Loop Until RandomNumber < BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256
    20. Return RandomNumber Mod MaxExclusive
    21. End Function
    22. ' -5 -6
    23. 'Public Function Random(MaxExclusive As Byte) As Byte
    24. Lab System_Random_Byte__Byte
    25. 'Dim BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 As UInt16
    26. '2 Bytes @ 0
    27. 'Dim RandomNumber As Byte
    28. '1 Byte @ 2
    29. SP += Const
    30. 3
    31. 'BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 = 256 - (256 Mod MaxExclusive))
    32. '256 Mod MaxExclusive
    33. 'G-Register sind für Multiplikation, Division und Modulo zuständig.
    34. '256 = (1 << 8) | 0
    35. C = Const
    36. 1
    37. GA1 = C
    38. C = Const
    39. 0
    40. GA0 = C
    41. C = Frame[Const] 'MaxExclusive
    42. 255
    43. 251
    44. GB = C
    45. GD = GA Mod GB
    46. '256 - ...
    47. C = Const
    48. 1
    49. F1 = C
    50. C = Const
    51. 0
    52. F0 = C
    53. '1-er Kompliment von (256 Mod MaxExclusive)
    54. C = GD
    55. A = C
    56. C = Not A
    57. E0 = C
    58. C = Const
    59. 255
    60. E1 = C
    61. 'A - B = A + !B + 1
    62. F += E
    63. F += Const
    64. 0
    65. 1
    66. C = F1
    67. Frame[Const] = C
    68. 0
    69. 0
    70. C = F0
    71. Frame[Const] = C
    72. 0
    73. 1
    74. 'Do
    75. Lab System_Random_Byte__Byte_Do1_Head
    76. 'RandomNumber = Rnd
    77. C = Rnd
    78. Frame[Const] = C
    79. 0
    80. 2
    81. 'Loop Until RandomNumber < BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256
    82. 'Kleiner-Als-Operator ist ein Aufruf, da in Hardware nur 8-Bit Vergleiche implementiert sind.
    83. Push C
    84. C = Const 'RandomNumber mit 0-en auf 16 Bits erweitern.
    85. 0
    86. Push C
    87. C = Frame[Const]
    88. 0
    89. 2
    90. Push C
    91. C = Frame[Const]
    92. 0
    93. 0
    94. Push C
    95. C = Frame[Const]
    96. 0
    97. 1
    98. Push C
    99. Call Const
    100. @System_Word_LessThan_Word_Word__Boolean
    101. SP += Const
    102. 255
    103. 252
    104. Pop C
    105. If C = 0 Then Goto 'Wenn C = 0, dann hat der Operator False zurückgegeben, dann muss wiederholt werden.
    106. @System_Random_Byte__Byte_Do1_Head
    107. 'Return Result Mod MaxExclusive
    108. C = Const
    109. 0
    110. GA1 = C
    111. C = Frame[Const]
    112. 0
    113. 2
    114. GA0 = C
    115. C = Frame[Const] 'MaxExclusive
    116. 255
    117. 251
    118. GB = C
    119. GD = GA Mod GB
    120. C = GD
    121. Frame[Const] = C 'Return-Wert
    122. 255
    123. 250
    124. Return
    125. 'End Function
    126. ' -8 -7 -6 -5 -9
    127. 'Public Operator <(Left As UInt16, Right As UInt16) As Boolean
    128. Lab System_Word_LessThan_Word_Word__Boolean
    129. 'If Left.HighByte < Right.HighByte Then
    130. C = Frame[Const]
    131. 255
    132. 248
    133. A = C
    134. C = Frame[Const]
    135. 255
    136. 250
    137. B = C
    138. C = A < B
    139. If C = 0 Then Goto
    140. @System_Word_LessThan_Word_Word__Boolean_If1_End
    141. 'Return True
    142. C = Const
    143. 255
    144. Frame[Const] = C 'Return-Wert
    145. 255
    146. 247
    147. Return
    148. 'End If
    149. Lab System_Word_LessThan_Word_Word__Boolean_If1_End
    150. 'If Left.HighByte > Right.HighByte Then
    151. C = A > B
    152. If C = 0 Then Goto
    153. @System_Word_LessThan_Word_Word__Boolean_If2_End
    154. 'Return False
    155. C = Const
    156. 0
    157. Frame[Const] = C 'Return-Wert
    158. 255
    159. 247
    160. Return
    161. 'End If
    162. Lab System_Word_LessThan_Word_Word__Boolean_If2_End
    163. 'Return Left.LowByte < Right.LowByte
    164. C = Frame[Const]
    165. 255
    166. 249
    167. A = C
    168. C = Frame[Const]
    169. 255
    170. 251
    171. B = C
    172. C = A < B
    173. Frame[Const] = C ''Return-Wert
    174. 255
    175. 247
    176. Return
    177. 'End Operator
    178. Lab EndOfCode

    Das Problem ist, dass trotzdem ein Bias vorhanden ist:
    MaxExclusive = 192

    MaxExclusive = 165

    MaxExclusive = 96

    Und ich komme einfach nicht drauf, wo das Problem liegt.


    Edit: Ach verdammt, ich hab den Fehler (bzw. einen, aber ich bin mir ziemlich sicher, dass das das Problem lösen wird) gefunden.
    Es war ein blöder Tippfehler. In der Random-Methode ganz am Anfang werden 3 Bytes auf dem Stack reserviert. Dazu wird der StackPointer einfach um 3 erhöht:

    VB.NET-Quellcode

    1. ' -5 -6
    2. 'Public Function Random(MaxExclusive As Byte) As Byte
    3. Lab System_Random_Byte__Byte
    4. 'Dim BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 As UInt16
    5. '2 Bytes @ 0
    6. 'Dim RandomNumber As Byte
    7. '1 Byte @ 2
    8. SP += Const
    9. 3
    10. 'BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 = 256 - (256 Mod MaxExclusive))
    11. '256 Mod MaxExclusive
    12. 'G-Register sind für Multiplikation, Division und Modulo zuständig.
    13. '256 = (1 << 8) | 0
    14. C = Const
    15. 1
    16. GA1 = C
    17. '...

    Da der StackPointer ein 16-Bit Wert ist, erwartet SP += Const auch 2 Bytes. Ich hab aber nur eines hingeschrieben. Korrekt müsste es so lauten:

    VB.NET-Quellcode

    1. ' -5 -6
    2. 'Public Function Random(MaxExclusive As Byte) As Byte
    3. Lab System_Random_Byte__Byte
    4. 'Dim BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 As UInt16
    5. '2 Bytes @ 0
    6. 'Dim RandomNumber As Byte
    7. '1 Byte @ 2
    8. SP += Const
    9. 0 ' <--------------Hier!
    10. 3
    11. 'BiggestMultipleOfMaxExclusiveLessThanOrEqualTo256 = 256 - (256 Mod MaxExclusive))
    12. '256 Mod MaxExclusive
    13. 'G-Register sind für Multiplikation, Division und Modulo zuständig.
    14. '256 = (1 << 8) | 0
    15. C = Const
    16. 1
    17. GA1 = C
    18. '...

    Der StackPointer wurde um (3 << 8) | 36 = 804 statt um (0 << 8) | 3 = 3 erhöht (36 ist der C = Const-OpCode). Und der 1-er wurde ausgeführt (Nop).
    Das Testprogramm läuft noch aber soweit sieht's gut aus.


    Edit 2:
    Jup, läuft:

    Damit hat sich das erledigt.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Niko Ortner“ ()