Integer mit spezifischem Bitset generieren

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    praktisch halte ich das für die beste lösung, vorallem da man so die probleme umgeht die man sonst mit zb fisher yates lösen muss, wenn man den input validiert halte ich es für realistisch unmöglich das es nicht terminiert
    Und .. was haltet ihr von dieser Lösung?

    C#-Quellcode

    1. public static uint GenerateUInt32(int n)
    2. {
    3. if (n == 0)
    4. return 0;
    5. if (n < 0 || n > 32)
    6. throw new ArgumentOutOfRangeException("n");
    7. return Enumerable.Range(0, 32).Select(i => i < n ? true : false).Shuffle().Select((b, i) => new { Index = i, Value = b }).Aggregate(0u, (last, current) => unchecked(last + (uint)((current.Value ? 1 : 0) << current.Index)));
    8. }

    Zusatz

    C#-Quellcode

    1. public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
    2. {
    3. var rng = new Random();
    4. return source.Shuffle(rng);
    5. }
    6. public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
    7. {
    8. if (source == null) throw new ArgumentNullException("source");
    9. if (rng == null) throw new ArgumentNullException("rng");
    10. return source.ShuffleIterator(rng);
    11. }
    12. private static IEnumerable<T> ShuffleIterator<T>(
    13. this IEnumerable<T> source, Random rng)
    14. {
    15. var buffer = source.ToList();
    16. for (int i = 0; i < buffer.Count; i++)
    17. {
    18. int j = rng.Next(i, buffer.Count);
    19. yield return buffer[j];
    20. buffer[j] = buffer[i];
    21. }
    22. }

    Ist eigentlich lustig, das noch keiner auf die Idee gekommt ist, LINQ zu nutzen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „AliveDevil“ ()

    @AliveDevil
    Ich dachte erst an Enumerable.Concat(Enumerable.Repeat(True, HighBitCount), Enumerable.Repeat(False, 32 - HighBitCount)).OrderBy(Function(i) Rnd.NextDouble) aber das war mir erstens zu lang und zweitens zu LINQ-lastig.
    Und doch, LINQ wurde schon gezeigt: Post #4
    Edit: Und auch, dass der TE LINQ nicht verwenden kann, weil Framework-Einschränkungen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    also ich finde so Bandwürmer iwann nicht mehr sonderlich lesbar.
    sowas nicht:

    C#-Quellcode

    1. result = (result & ~((1u << i) | (1u << j))) | (((result >> i) & 1u) << j) | (((result >> j) & 1u) << j);

    Und sowas noch weniger:

    C#-Quellcode

    1. return Enumerable.Range(0, 32).Select(i => i < n ? true : false).Shuffle().Select((b, i) => new { Index = i, Value = b }).Aggregate(0u, (last, current) => unchecked(last + (uint)((current.Value ? 1 : 0) << current.Index)));

    ich steige am leichtesten durch die Codes von post#13 und post#15 durch.
    Was ist das Problem dabei? Ein Kommentar dazu, ausreichend testen und man hat eine performante, elegante, logische Lösung. Ich wüsste nicht, was dagegen spricht solch einfache Sachen direkt einzubauen, egal ob sie übersichtlich sind oder nicht. In einer in sich geschlossenen Funktion interessiert das eh keine Sau mehr, solange sie das tut, was man will.

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    Habe beim zweiten mal j statt i geschrieben. Ist aber symmetrisch zum ersten (((result >> j) & 1u) << i) statt ((result >> j) & 1u) << j.

    Viele Grüße
    ~blaze~


    Hey :)
    Deine Lösung scheint aber immer noch nicht richtig zu funktionieren, - oder ich verwechsle irgendwas:



    (Die sollten eigentliche alle 6 gesetzte Bits haben, da ich das in der Main() function so angegeben habe)
    C# Developer
    Learning C++

    ErfinderDesRades schrieb:

    ~blaze~ schrieb:

    Ein Kommentar dazu
    jepp - ich glaub, ich habs geschnackelt:

    C#-Quellcode

    1. // tausche die bits an den Positionen i, j
    2. result = (result & ~((1u << i) | (1u << j))) | (((result >> i) & 1u) << j) | (((result >> j) & 1u) << j);
    richtich? ;)

    Ich glaube, immer noch nicht :D
    Probier das mal aus:

    C#-Quellcode

    1. public static uint GenerateUInt32(int n)
    2. {
    3. if (n == 0)
    4. return 0;
    5. if (n < 0 || n > 32)
    6. throw new ArgumentOutOfRangeException("n");
    7. uint result = 0xffffffffu >> (32 - n);
    8. for (int i = 1; i < 32; i++)
    9. {
    10. int j = rnd.Next(0, 32);
    11. result = (result & ~((1u << i) | (1u << j))) | (((result >> i) & 1u) << j) | (((result >> j) & 1u) << j);
    12. }
    13. return result;
    14. }


    Du wirst sehen das die Zahlen nicht alle 6 gesetzte Bits haben.
    C# Developer
    Learning C++

    ErfinderDesRades schrieb:

    ja, ich probiers grade, und stelle fest, zumindest die Bits 0, 30 tauscht das nicht :(

    also verstehe ich den Sinn falsch, oder der Code ist falsch.

    Warten wir mal, vllt hat @~blaze~ ja ne Idee was an seiner funktion falsch ist :P
    C# Developer
    Learning C++

    C#-Quellcode

    1. public static uint GenerateUInt32(this Random random, int n)
    2. {
    3. if (random == null)
    4. throw new ArgumentNullException("random");
    5. if (n < 0 || n > 32)
    6. throw new ArgumentOutOfRangeException("n");
    7. if (n == 0)
    8. return 0;
    9. if (n == 32)
    10. return ~0u;
    11. uint result = ~(~0u >> n);
    12. for (int i = 1; i < 32; i++)
    13. {
    14. int j = random.Next(0, 32);
    15. result = (result & ~((1u << i) | (1u << j))) | (((result >> j) & 1u) << i) | (((result >> i) & 1u) << j);
    16. }
    17. return result;
    18. }


    By the way: Die Vollzitate weglassen, bitte. ;)

    Hier der Testcode:

    C#-Quellcode

    1. Random rnd = new Random();
    2. while (true)
    3. {
    4. int n;
    5. string line = Console.ReadLine();
    6. if (line == string.Empty)
    7. break;
    8. else if (!int.TryParse(line, out n) || n < 0 || n > 32)
    9. {
    10. Console.WriteLine("Enter number in range 0-32.");
    11. continue;
    12. }
    13. for (int i = 0; i < 9; i++)
    14. {
    15. line = System.Convert.ToString(rnd.GenerateUInt32(n), 2);
    16. Console.WriteLine(line.PadLeft(32, '0') + " - " + line.Count((c) => c == '1').ToString());
    17. }
    18. }


    Viele Grüße
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()