Using RNGCryptoServiceProvider to "simulate" throwing a dice - c#

I've been trying to simulate rolling a 6-faces dice in C#. I thought using RNGCSP was better than Random because it is more secure.
I tried using MSDN's example code to achieve this, but there are a few things that I didn't understand from the code:
How do you generate 5 digit long numbers with RNGCSP?
How do you generate numbers from 1 to 6 (excluding zeroes)?

1. How do you generate 5 digit long numbers with RNGCSP?
For the numbers, you can use a range. You'll have to think of the lower bound yourself though. Ranges for number are treated in RNGCryptoServiceProvider.
So for a 5 digit number min would be 0 or 10000 and max would be 100000, because max is exclusive.
2. How do you generate numbers from 1 to 6 (excluding zeroes)?
Basically the same way, you generate a range [1, 7) where 7 - the max value - is exclusive.
If you just want a dice result you can just do something like this (untested!):
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] singleByteBuf = new byte[1];
int max = Byte.MaxValue - Byte.MaxValue % 6;
while (true) {
rng.GetBytes(singleByteBuf);
int b = singleByteBuf[0];
if (b < max) {
return b % 6 + 1;
}
}
Basically the same idea, but is only requests 1 byte at a time from the RNGCryptoServiceProvider, so it doesn't waste 3 additional bytes.

Related

C# - What's the fastest way to convert a number to the smallest BitArray

I would like to convert a number to a BitArray, with the resulting BitArray only being as big as it needs to be.
For instance:
BitArray tooBig = new BitArray(new int[] { 9 });
results in a BitArray with a length of 32 bit, however for the value 9 only 4 bits are required. How can I create BitArrays which are only as long as they need to be? So in this example, 4 bits. Or for the number 260 I expected the BitArray to be 9 bits long
You can figure out all the bits first and then create the array by checking if the least significant bit is 1 or 0 and then right shifting until the number is 0. Note this will not work for negative numbers where the 32nd bit would be 1 to indicate the sign.
public BitArray ToShortestBitArray(int x)
{
var bits = new List<bool>();
while(x > 0)
{
bits.Add((x & 1) == 1);
x >>= 1;
}
return new BitArray(bits.ToArray());
}
Assuming you are working with exclusively unsigned integers, the number of bits you need is equal to the base 2 logarithm of the (number+1), rounded up.
Counting the bits is probably the easiest solution.
In JavaScript for example...
// count bits needed to store a positive number
const bits = (x, b = 0) => x > 0 ? bits(x >> 1, b + 1) : b;

C# formula to determine index

I have a maths issue within my program. I think the problem is simple but I'm not sure what terms to use, hence my own searches returned nothing useful.
I receive some values in a method, the only thing I know (in terms of logic) is the numbers will be something which can be duplicated.
In other words, the numbers I could receive are predictable and would be one of the following
1
2
4
16
256
65536
etc
I need to know at what index they appear at. In othewords, 1 is always at index 0, 2 at index 1, 4 at index 3, 16 is at index 4 etc.
I know I could write a big switch statement but I was hoping a formula would be tidier. Do you know if one exists or any clues as the names of the math forumula's I'm using.
The numbers you listed are powers of two. The inverse function of raising a number to a power is the logarithm, so that's what you use to go backwards from (using your terminology here) a number to an index.
var num = 256;
var ind = Math.Log(num, 2);
Above, ind is the base-2 logarithm of num. This code will work for any base; just substitute that base for 2. If you are only going to be working with powers of 2 then you can use a special-case solution that is faster based on the bitwise representation of your input; see What's the quickest way to compute log2 of an integer in C#?
Try
Math.Log(num, base)
where base is 2
MSDN: http://msdn.microsoft.com/en-us/library/hd50b6h5.aspx
Logarithm will return to You power of base from you number.
But it's in case if your number really are power of 2,
otherwise you have to understand exactly what you have, what you need
It also look like numbers was powered to 2 twice, so that try this:
private static int getIndexOfSeries(UInt64 aNum)
{
if (aNum == 1)
return 0;
else if (aNum == 2)
return 1;
else
{
int lNum = (int)Math.Log(aNum, 2);
return 1+(int)Math.Log(lNum, 2);
}
}
Result for UInt64[] Arr = new UInt64[] { 1, 2, 4, 16, 256, 65536, 4294967296 } is:
Num[0] = 1
Num[1] = 2
Num[2] = 4
Num[3] = 16
Num[4] = 256
Num[5] = 65536
Num[6] = 4294967296 //65536*65536
where [i] - index
You should calculate the base 2 logarithm of the number
Hint: For the results:
0 2
1 4
2 16
3 256
4 65536
5 4294967296
etc.
The formula is, for a give integer x:
Math.Pow(2, Math.Pow(2, x));
that is
2 to the power (2 to the power (x) )
Once the formula is known, one could solve it for x (I won't go through that since you already got an answer).

How can you separate a string of numbers to single digits using division and the modulo operator?

Lets say someone enter a four digit number 1234 in the console. How can you separate this number in to 1 2 3 4 using only division and the modulo operator?
public static void MathProblem()
{
Console.WriteLine("Type a four digit number:");
//Ex input: 1234
string inputNumber = Console.ReadLine();
// I'm guessing you first need to parse the
// string as an int in some way?
// And then assign it to some variable
// Now, for seperating the digits to be: 1 2 3 4,
// you can (and must) use both division (/), and the remainder (%).
// The first one will be simple, just dividing value with 1000, but
// how about the others? (Remember, % also need to be used at least
// once)
Console.Write("{0},{1},{2},{3}", value/1000, ?, ?, ?;
}
Any guidelines for making this possible for any given four digit input?
Since this seems like a homework problem, I'll simply explain the method in a few steps rather than giving you the code. Having parsed the input as an integer,
A number modulo 10 allows you to obtain its last digit.
Dividing (integer division) the number by 10 removes the last digit.
Repeat while the number is greater than 0.
int num = int.Parse(inputNumber);
Console.Write(string.Format("{0},{1},{2},{3}", (num/1000) % 100, (num/100) % 10, (num/10) % 10, num % 10));
OR
List<int> listOfInts = new List<int>();
while(num > 0)
{
listOfInts.Add(num % 10);
num = num / 10;
}
Console.Write("{0},{1},{2},{3}", listOfInts[3], listOfInts[2], listOfInts[1], listOfInts[0]);
No need to do this by division or modulo operators. Use LINQ. You can get an integer array using LINQ as below:
string inputNumber= "1234"
var intList = inputNumber.Select(digit => int.Parse(digit.ToString()));
Then, you can simply use it as you want like this:
Console.Write("{0},{1},{2},{3}", intList[0]/1000, intList[1], intList[2], intList[3]);
Or simply the way you wanted it using Division and Modulo Operator:
public int[] ParseIntString(int number)
{
List<int> digits= new List<int>();
while(number> 0)
{
digits.Add(number% 10);
number= number/ 10;
}
digits.Reverse();
return digits.ToArray();
}
I hope this helps you
int[] values;
Seperate(inputNumber, out values);
Console.Write("{0},{1},{2},{3}", values[0] / 1000, values[1], values[2], values[3]);
Console.ReadKey();
}
public static void Seperate(string numbers, out int[] values)
{
values = new int[numbers.Length];
for (int x = 0; x <= numbers.Length - 1; x++)
{
values[x] = int.Parse(numbers[x].ToString());
}
}
I just started a course in coding and had this as homework as well. I did it in excel first because I thought it was easier than running code over and over and it's more a math problem than a coding one.
Say the number is 4352.
The first digit is easy, it's the integer of the number / 1000 = 4.
Then you simply multilpy by 1000 to get 4000. Remove that and you get 352. The integer of that / 100 is 3.
Then you times that by 100 to get 300 and remove that and you get 52, the integer of that / 10 is 5. Multiply that by 10 and remove that and you're left with 2.
Just read that you must use % so I suggest getting the last number as a modular of 10

Random.Next returns always the same values [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
I use the method to generate unique number but I always get the same number -2147483648. Even if I stop the program, recompile it and run again I still see the same number.
public static int GetRandomInt(int length)
{
var min = Math.Pow(10, length - 1);
var max = Math.Pow(10, length) - 1;
var random = new Random();
return random.Next((int)min, (int)max);
}
Try externalizing the random instance:
private readonly Random _random = new Random();
public static int GetRandomInt(int length)
{
var min = Math.Pow(10, length - 1);
var max = Math.Pow(10, length) - 1;
return _random.Next((int)min, (int)max);
}
This is not an issue of not reusing Random instance, the results he gets should be random on multiple starts, not always being -(2^32)
This is the issue with length being too big, and casting powers of length to int. If you break the code into following lines:
var min = Math.Pow(10, length - 1);
var max = Math.Pow(10, length) - 1;
var random = new Random();
var a = (int)min;
var b = (int)max;
return random.Next(a, b);
You'll see that a and b are -2147483648, making that the only possible result of Next(min, max) (the doc specifies if min==max, return min).
The largest length you can safely use with this method is 9. For a length of 10 you'll get System.ArgumentOutOfRangeException, for length > 10 you'll get the -2147483648 result.
You have three problems with your code.
You should externalize your random variable.
You have a problem with truncation error.
The range between min and max is way to large.
The first problem is because you may not have enough time to advance the seed when reinitializing your random variable. The second error comes from truncating your (what would b very large) numbers down to ints. Finally, your biggest problem is your range between your min and your max. Consider finding the range between min and max (as defined in your code) with inputs 1->20:
length max-min
1 8
2 89
3 899
4 8999
5 89999
6 899999
7 8999999
8 89999999
9 899999999
10 8,999,999,999
11 89999999999
12 899999999999
13 8999999999999
14 89999999999999
15 899999999999999
16 9E+15
17 9E+16
18 9E+17
19 9E+18
And keep in mind that the maximum integer is 2,147,483,647, which is passed on any number greater than 9.
You should keep an instance of Random and not new() it up all the time, that should give you better results.
Also check for what length actually is. It may be giving you funny results as to the limits.
I think the problem is the calculation of min and max. They will be greater than Int32.MaxValue pretty fast...
In your class, have one instance of Random, e.g.:
public class MyClass
{
private readonly Random random = new Random();
public static int GetRandomInt(int length)
{
var min = Math.Pow(10, length - 1);
var max = Math.Pow(10, length) - 1;
return random.Next((int)min, (int)max);
}
}
The fact that random always returns the same values only exists for testing purposes.
Random classes usually use a seed to initialize themselves, and will usually return the same sequence provided the seed is the same one :
Always reuse the same Random() instance instead of recreating one over and over again
if you want unpredictable results, use a time-dependent seed rather than an hard-coded one
It's very difficult to code a truly random number generator. Most methods use external entropy generators (such as mouse movement, cpu temperature, or even complex physical mechanisms such as helium balloons colliding one another...).
The Random instance should be created only once and then reused. The reason for this is that the RNG is by default seeded with the current system time. If you rapidly create new Random instances (and pull one value from it) then many of them will be seeded with the same timestamp, because the loop probably executes faster than the system clock advances.
Remember, a RNG initialized by seed A will always return sequence B. So if you create three Random instances all seeded with for example 123, these three instances will always return the same number on the same iteration.

How to generate a cryptographically secure Double between 0 and 1?

I know how to generate a random number between 0 and 1 using the NextDouble method of the pseudo-random number generator.
var rng1 = new System.Random();
var random1 = rng1.NextDouble(); // generates a random double between 0 and 1.0
And I know how to fill a random byte array using the cryptographically secure random number generator.
Byte[] bytes = new Byte[8];
var rng2 = new System.Security.Cryptography.RNGCryptoServiceProvider();
rng2.GetBytes(bytes); // generates 8 random bytes
But how can I convert the byte-array output of RNGCryptoServiceProvider into a random number uniformly distributed between 0 (inclusive) and 1 (exclusive)?
It appears to me that the solutions so far will have uneven distribution due to taking the inverse. For an even distribution I'd think you want something like this.
// Step 1: fill an array with 8 random bytes
var rng = new RNGCryptoServiceProvider();
var bytes = new Byte[8];
rng.GetBytes(bytes);
// Step 2: bit-shift 11 and 53 based on double's mantissa bits
var ul = BitConverter.ToUInt64(bytes, 0) / (1 << 11);
Double d = ul / (Double)(1UL << 53);
Note that you can't just divide the UInt64 into UInt64.MaxValue, because a double doesn't have enough bits, and there's no way to get unique outputs for all your inputs. So you can/must throw some bits away.
Well, I would not call a 64-bit random number "cryptographically secure" - you'd want a lot more bits than that to be "cryptographically secure". But anyway, you could do something like this:
var bytes = // assume this contains 8 bytes of random numbers
long l = BitConverter.ToInt64(bytes);
double d = Math.Abs(1 / (double)l);
Since RNGCryptoServiceProvider is obsolete in .NET 6
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=net-6.0
if you want "real" NextDouble you can use RandomNumberGenerator like this
How to get NextDouble from cryptogaphy random RandomNumberGenerator

Categories

Resources