Seeded Random Analytics:The given key was not present in the dictionary - c#

I was following a tutorial on random number generation in Visual C# 2010 Express as a console app and ran into an issue.
The code matches the tutorial I was watching as far as I can tell with 5 overviews.
The idea is that it will take built in random seed function and generate 100 values with it. The program will be storing the random number (a double) as a KEY for a DICTIONARY and a int VALUE to show the number of duplicates. This system will print analytical data about the duplicates, the mean, and the distribution.
//PROGRAM SCOPE
private const int Count = 100;
// MAIN CLASS SCOPE
var standardRnd = new Random(20);
var list = new Dictionary<double,int>();
//In a for loop till Count-1
var rand = standardRnd.NextDouble();
if (!list.ContainsKey(rand))
list.Add(rand, 1);
else
{
list[rand]++;
duplicate++;
}
When I run the program the console will activate just fine but I wont print anything to the screen. After a second or so It will throw an exception and highlight this code snippet.
sum += rand * list[rand];
ERROR: The given key was not present in the dictionary.
Logically it makes sense to me. Do you guys see anything wonky?
Thank you for any help you can give.
FULL CODE:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Random_RnD
{
class Program
{
static void Main(string[] args)
{
var standardRnd = new Random(20);
var min = 1.0;
var max = 0.0;
var valueCounter = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
var list = new Dictionary<double,int>();
var duplicate = 0;
var iterations = 0;
var timeStart = DateTime.Now;
//Do Stuff
for (int x = 0; x < Count; x++)
{
var rand = standardRnd.NextDouble();
if (!list.ContainsKey(rand))
list.Add(rand, 1);
else
{
list[rand]++;
duplicate++;
}
iterations++;
}
var timeStop = DateTime.Now;
var elapseTime = TimeSpan.FromTicks((timeStop-timeStart).Ticks);
//Analytics
var sum = 0.0;
foreach (var kvp in list)
{
var rand = kvp.Key;
if (rand < min)
min = rand;
if(rand>max)
rand = max;
if (rand >= 0.0 && rand < 0.1)
valueCounter[0]++;
if (rand >= 0.1 && rand < 0.2)
valueCounter[1]++;
if (rand >= 0.2 && rand < 0.3)
valueCounter[2]++;
if (rand >= 0.3 && rand < 0.4)
valueCounter[3]++;
if (rand >= 0.4 && rand < 0.5)
valueCounter[4]++;
if (rand >= 0.5 && rand < 0.6)
valueCounter[5]++;
if (rand >= 0.6 && rand < 0.7)
valueCounter[6]++;
if (rand >= 0.7 && rand < 0.8)
valueCounter[7]++;
if (rand >= 0.8 && rand < 0.9)
valueCounter[8]++;
if (rand >= 0.9 && rand <= 1.0)
valueCounter[9]++;
sum += rand * list[rand];
}
Console.WriteLine("{0:###,###,###} Iteration took: {1:D2}min:{2:D2}sec:{3:D2}msec",
iterations, elapseTime.Minutes, elapseTime.Seconds, elapseTime.Milliseconds);
Console.WriteLine(" {0}\n {1}", min, max);
Console.WriteLine(" 0.0 to 0.1 = {0:###,###,###}", valueCounter[0]);
Console.WriteLine(" 0.1 to 0.2 = {0:###,###,###}", valueCounter[1]);
Console.WriteLine(" 0.2 to 0.3 = {0:###,###,###}", valueCounter[2]);
Console.WriteLine(" 0.3 to 0.4 = {0:###,###,###}", valueCounter[3]);
Console.WriteLine(" 0.4 to 0.5 = {0:###,###,###}", valueCounter[4]);
Console.WriteLine(" 0.5 to 0.6 = {0:###,###,###}", valueCounter[5]);
Console.WriteLine(" 0.6 to 0.7 = {0:###,###,###}", valueCounter[6]);
Console.WriteLine(" 0.7 to 0.8 = {0:###,###,###}", valueCounter[7]);
Console.WriteLine(" 0.8 to 0.9 = {0:###,###,###}", valueCounter[8]);
Console.WriteLine(" 0.9 to 1.0 = {0:###,###,###}", valueCounter[9]);
var avg = sum / (double)iterations;
Console.WriteLine("\nStatistics:");
Console.WriteLine(" Mean = {0}", avg);
Console.WriteLine(" Duplicates = {0}", duplicate);
Console.ReadKey();
}
}
}

The problem is here:
if (rand>max)
rand = max;
This assigns 0 to rand. But 0 isn't guaranteed to be in the dictionary.
You meant max = rand;.
There is also a much easier way to find the minimum and maximum values in a collection by using LINQ:
var keys = list.Keys;
double min = keys.Min();
double max = keys.Max();

Related

Solving modulo in c#

I'm having troubles solving modulo in c#. The example below
7^-1 modulo 26
when on Wolfram Alpha returns correct 15. In c# when I tried direct:
1/7 % 26
it returns unwanted 0.142857142857143 instead of desired 15.
But i'm not a master mathematician, so i'm probably missing something vital.
Your are looking for modular inversion: in case of
7**-1 modulo 26 = x
or
1 / 7 modulo 26 = x
you actually want to find out an x such that
(x * 7) modulo 26 = 1
In our case x == 15 since
15 * 7 == 105 == 26 * 4 + 1
For small modulo values (like 26) you can find the answer (15) with a help of naive for loop:
int modulo = 26;
int div = 7;
int result = 0;
for (int i = 1; i < modulo; ++i)
if ((i * div) % modulo == 1) {
result = i;
break;
}
Console.Write(result);
In general case, you can obtain the result with a help of Extended Euclid Algorithm. Often, when working with modulo arithmetics we face huge numbers, that's why let me show the code for BigInteger; if it's not your case you can turn BigInteger to good old int.
Code:
using System.Numerics;
...
private static (BigInteger LeftFactor,
BigInteger RightFactor,
BigInteger Gcd) Egcd(this BigInteger left, BigInteger right) {
BigInteger leftFactor = 0;
BigInteger rightFactor = 1;
BigInteger u = 1;
BigInteger v = 0;
BigInteger gcd = 0;
while (left != 0) {
BigInteger q = right / left;
BigInteger r = right % left;
BigInteger m = leftFactor - u * q;
BigInteger n = rightFactor - v * q;
right = left;
left = r;
leftFactor = u;
rightFactor = v;
u = m;
v = n;
gcd = right;
}
return (LeftFactor: leftFactor,
RightFactor: rightFactor,
Gcd: gcd);
}
The inversion itself will be
private static BigInteger ModInversion(BigInteger value, BigInteger modulo) {
var egcd = Egcd(value, modulo);
if (egcd.Gcd != 1)
throw new ArgumentException("Invalid modulo", nameof(modulo));
BigInteger result = egcd.LeftFactor;
if (result < 0)
result += modulo;
return result % modulo;
}
Demo:
using System.Numerics;
...
BigInteger result = ModInversion(7, 26);
Console.Write(result);
Outcome:
15

generate random integers with a specific sum

I have 5 fields, I want them all to have a generated number between 0 and 100. But, the sum of the 5 fields should be 100.
When I want to give a random number for one field I would do the following:
Random rnd = new Random();
int x= rnd.Next(1, 10);
But how should I do that for multiple fields that needs to have a sum of 100 together?
You can use the following approach:
generate 4 random integers in [0, 100]
sort them, let's denote the sorted values as 0 ≤ x1 ≤ x2 ≤ x3 ≤ x4 ≤ 100
use the following 5 values as the random numbers with sum 100:
N1 = x1
N2 = x2 - x1
N3 = x3 - x2
N4 = x4 - x3
N5 = 100 - x4
It basically corresponds to randomly choosing 4 sectioning points on the [0, 100] interval, and using the lengths of the 5 resulting intervals as the random numbers:
const int k = 5;
const int sum = 100;
Random rnd = new Random();
int[] x = new int[k + 1];
// the endpoints of the interval
x[0] = 0;
x[k] = sum;
// generate the k - 1 random sectioning points
for (int i = 1; i < k; i++) {
x[i] = rnd.Next(0, sum + 1);
}
// sort the sectioning points
Array.Sort(x);
// obtain the k numbers with sum s
int[] N = new int[k];
for (int i = 0; i < k; i++) {
N[i] = x[i + 1] - x[i];
}
In order to make your distribution uniform, you could try the following aproach:
Generate some random numbers.
Normalize them.
Correct the last field to get exactly the expected sum, if needed.
The code:
const int ExpectedSum = 100;
Random rnd = new Random();
int[] fields = new int[5];
// Generate 4 random values and get their sum
int sum = 0;
for (int i = 0; i < fields.Length - 1; i++)
{
fields[i] = rnd.Next(ExpectedSum);
sum += fields[i];
}
// Adjust the sum as if there were 5 random values
int actualSum = sum * fields.Length / (fields.Length - 1);
// Normalize 4 random values and get their sum
sum = 0;
for (int i = 0; i < fields.Length - 1; i++)
{
fields[i] = fields[i] * ExpectedSum / actualSum;
sum += fields[i];
}
// Set the last value
fields[fields.Length - 1] = ExpectedSum - sum;
Live example: https://dotnetfiddle.net/5yXwOP
To achieve a truly random distribution, with every element having the chance to be 100 with a total sum of 100, you can use the following solution:
public static int[] GetRandomDistribution(int sum, int amountOfNumbers)
{
int[] numbers = new int[amountOfNumbers];
var random = new Random();
for (int i = 0; i < sum; i++)
{
numbers[random.Next(0, amountOfNumbers)]++;
}
return numbers;
}
static void Main(string[] args)
{
var result = GetRandomDistribution(100, 5);
}
It increases a random number by one until the sum is reached. This should fulfill all your criterias.
After thinking about it, I prefer the following solution, because it's less likely to generate an equal distribution:
public static int[] GetRandomDistribution2(int sum, int amountOfNumbers)
{
int[] numbers = new int[amountOfNumbers];
var random = new Random();
for (int i = 0; i < amountOfNumbers; i++)
{
numbers[i] = random.Next(sum);
}
var compeleteSum = numbers.Sum();
// Scale the numbers down to 0 -> sum
for (int i = 0; i < amountOfNumbers; i++)
{
numbers[i] = (int)(((double)numbers[i] / compeleteSum) * sum);
}
// Due to rounding the number will most likely be below sum
var resultSum = numbers.Sum();
// Add +1 until we reach "sum"
for (int i = 0; i < sum - resultSum; i++)
{
numbers[random.Next(0, amountOfNumbers)]++;
}
return numbers;
}
For Example.
int sum=100;
int i = 5;
Random rnd = new Random();
while (true)
{
int cur;
--i;
if (i == 0) {
Console.WriteLine(sum + " ");
break;
} else
cur=rnd.Next(1, sum);
sum -= cur;
Console.WriteLine(cur + " ");
}
Live Example: https://dotnetfiddle.net/ltIK40
or
Random rnd = new Random();
int x= rnd.Next(1, 10);
int y= rnd.Next(x,x+10);
int y2=rnd.Next(y,y+10);
int y3=rnd.Next(y2,y2+10);
int y4=100-(x+y+y2+y3);
My approach is this:
var rnd = new Random();
var numbers = Enumerable.Range(0, 5).Select(x => rnd.Next(0, 101)).ToArray().OrderBy(x => x).ToArray();
numbers = numbers.Zip(numbers.Skip(1), (n0, n1) => n1 - n0).ToArray();
numbers = numbers.Concat(new[] { 100 - numbers.Sum() }).ToArray();
This is as uniform as I think is possible.
Create your first random number. After that you take the difference between the value of num1 and 100 as the max def of rnd. But to guarantee that their sum is 100, you have to check at the last num if the sum of all nums is 100. If not the value of your last num is the difference that their sum and 100.
And to simply your code and get a clean strcuture, put that code in a loop and instead of single numbers work with an int[5] array.
private int[] CreateRandomNumbersWithSum()
{
int[] nums = new int[5];
int difference = 100;
Random rnd = new Random();
for (int i = 0; i < nums.Length; i++)
{
nums[i] = rnd.Next(0, difference);
difference -= nums[i];
}
int sum = 0;
foreach (var num in nums)
sum += num;
if (sum != 100)
{
nums[4] = 100 - sum;
}
return nums;
}
I think this is a very simple solution:
public void GenerateRandNr(int total)
{
var rnd = new Random();
var nr1 = rnd.Next(0, total);
var nr2 = rnd.Next(0, total - nr1);
var nr3 = rnd.Next(0, total - nr1 - nr2);
var nr4 = rnd.Next(0, total - nr1 - nr2 - nr3);
var nr5 = total - nr1 - nr2 - nr3 - nr4;
}
EDIT:
Just tested it, works fine for me:
The solution is that it's not the numbers that need to be random so much as the distribution needs to be random. The randomness of the numbers will be a side effect of their random distribution.
So you would start with five random numbers in a given range. The exact range doesn't matter as long as the range is the same for all five, although a broader range allows for more variation. I'd use Random.NextDouble() which returns random numbers between 0 and 1.
Each of those individual numbers divided by the sum of those numbers represents a distribution.
For example, say your random numbers are .4, .7, .2, .5, .2. (Using fewer digits for simplicity.)
The total of those numbers is 2. So now the distributions are each of those numbers divided by the total.
.4 / 2 = .20
.7 / 2 = .35
.2 / 2 = .10
.5 / 2 = .25
.2 / 2 = .10
You'll notice that those distributions will equal 100% or really close to it if there are a lot more decimal places.
The output is going to be each of those distributions times the target number, in this case, 100. In other words, each of those numbers represents a piece of 100.
So multiplying each of those distributions times the target, we get 20, 35, 10, 25, and 100, which add up to 100.
The trouble is that because of rounding your numbers won't always perfectly add up to 100. To fix that you might add one to the smallest number if the sum is less than 100, or subtract one from the largest number of the the sum is greater than 100. Or you could choose to add or subtract on one of the numbers at random.
Here's a class to create the distributions. (I'm just playing around so I haven't exactly optimized this to death.)
public class RandomlyDistributesNumbersTotallingTarget
{
public IEnumerable<int> GetTheNumbers(int howManyNumbers, int targetTotal)
{
var random = new Random();
var distributions = new List<double>();
for (var addDistributions = 0; addDistributions < howManyNumbers; addDistributions++)
{
distributions.Add(random.NextDouble());
}
var sumOfDistributions = distributions.Sum();
var output = distributions.Select(
distribution =>
(int)Math.Round(distribution / sumOfDistributions * targetTotal, 0)).ToList();
RoundUpOutput(output, targetTotal);
return output;
}
private void RoundUpOutput(List<int> output, int targetTotal)
{
var difference = targetTotal - output.Sum();
if (difference !=0)
{
var indexToAdjust =
difference > 0 ? output.IndexOf(output.Min()) : output.IndexOf(output.Max());
output[indexToAdjust]+= difference;
}
}
}
And here's a not-perfectly-scientific unit test that tests it many times over and ensures that the results always total 100.
[TestMethod]
public void OutputTotalsTarget()
{
var subject = new RandomlyDistributesNumbersTotallingTarget();
for (var x = 0; x < 10000; x++)
{
var output = subject.GetTheNumbers(5, 100);
Assert.AreEqual(100, output.Sum());
}
}
Some sample outputs:
5, 30, 27, 7, 31
15, 7, 26, 27, 25
10, 11, 23, 2, 54
The numbers are always going to average to 20, so while 96, 1, 1, 1 is a hypothetical possibility they're going to tend to hover closer to 20.
Okay. Having been burned by my previous attempt at this seemingly trivial problem, I decided to have another go. Why not normalise all the numbers after generation? This guarantees randomness, and avoids O(n log n) performance from a sort. It also has the advantage that even with my basic maths, I can work out that the numbers are uniformly distributed.
public static int[] UniformNormalization(this Random r, int valueCount, int valueSum)
{
var ret = new int[valueCount];
long sum = 0;
for (int i = 0; i < valueCount; i++)
{
var next = r.Next(0, valueSum);
ret[i] = next;
sum += next;
}
var actualSum = 0;
for (int i = 0; i < valueCount; i++)
{
actualSum += ret[i] = (int)((ret[i] * valueSum) / sum);
}
//Fix integer rounding errors.
if (valueSum > actualSum)
{
for (int i = 0; i < valueSum - actualSum; i++)
{
ret[r.Next(0, valueCount)]++;
}
}
return ret;
}
This should also be one of the fastest solutions.

How to do the loop and solve the following

I'm supposed to code a program that writes out a division just like in school.
Example:
13:3=4.333333333333
13
1
10
10
10....
So my approach was:
Solve the division then get the solution in a List.
Then question if the first number (in this case 1) is divisible by 3.
If not put it down and add the second number and so on...
I managed to do this the first time. It's sloppy but works. The problem is that it only works with numbers that when divided get to have a decimal in it.
Exapmle:
123:13
This is the first code:
do
{
for (int number = 1; number <= divNum; number++)
if (number % divisor == 0) countH++;
for (int i = 0; i < count; i++)
Console.Write(" ");
if ((c = divNum % divisor ) < divisor )
{
Console.WriteLine(" " + ((divNum- (countH * divisor ))) * 10);
}
else Console.WriteLine(" " + (divNum- (countH * divisor )));
c = divNum % divisor ;
if (c < divisor )
{
divNum = c * 10;
}
count++; countH = 0;
} while ((divNum >= divisor ) && (count < x));
Any ideas or help? Sorry if this is a bad question.
************ added
Try of a better explanation:
1 cant be divided by 13, so it goes down, we get the 2 down and try 12 divided by 13, still nothing so we get the 3 down and try 123:13, 13 goes 9 times in 123 so we have 123-9*13 = 6 the six goes down we write 9 in the result. We try 6:13 not going so we drop a 0 next to 6. Next we try 60:13, 13 goes 4 times so 60-4*13 = 8, we get the 8 down. And so on..
123:13=9.46153....
123
60
80
20
70
50
....
Something like this should work. Not the fastest solution most likely, but should do the job.
var number = 123;
var b = 12;
int quotient;
double remainder = number;
var x = 10;
do
{
quotient = (int)Math.Floor(remainder / b);
remainder = remainder - (quotient * b);
for (int i = 0; i < count; i++)
Console.Write(" ");
remainder *= 10;
Console.WriteLine(" " + remainder);
count++;
} while ((remainder > 0) && (count < x));

Fastest way to get remaining count to next ceiling ten in C#

I'm doing a operation in a very large set of numbers (13 digit length each).
I need to validate each number with checksum. Checksum digit will tell how far number is it to next ten, so i.e.:
checksum checksum digit
20 0
21 9
22 8
33 7
34 6
35 5
36 4
37 3
208 2
9 1
The numbers are EAN-13 format. So, the maximum digits sum = 217 (999999999999: no checksum validation).
By far, the fastest way I have think is preloading data into a int array and retrieving it by index.
Is this the fastest way possible?
Or at this point this does not matter anymore, since it will be executed fast enough even to a lot of numbers?
UPDATE:
preloading values of checksum digit for cheksum into an array as I mentioned:
for (int i = 0; i < 220; i += 10)
{
matchValues[i] = 0;
matchValues[i + 1] = 9;
matchValues[i + 2] = 8;
matchValues[i + 3] = 7;
matchValues[i + 4] = 6;
matchValues[i + 5] = 5;
matchValues[i + 6] = 4;
matchValues[i + 7] = 3;
matchValues[i + 8] = 2;
matchValues[i + 9] = 1;
}
With this I can cover all checksums with matching checksum digit matchValues[sum];
So:
matchValues[208] = 2;
matchValues[9] = 1;
etc.
You can use the modulo to get the distance from the ceiling ten. You still would need to iterate over each number obviously.
int modulo = i % 10;
int distanceFromTen = modulo == 0 ? 0 : 10 - modulus;
Another solution would be int distanceFromTen = (int)(Math.Ceiling(i / 10d) * 10 - i);.
I've run benchmarks for both approaches:
private static void Main(string[] args)
{
//Console.WriteLine("Checking {0}", i);
int loops = 10;
long averageModulo = 0;
long averageCeiling = 0;
for (int l = 0; l < loops; l++)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000000; i++)
{
int modulus = i % 10;
int distanceFromTen = modulus == 0 ? 0 : 10 - modulus;
}
sw.Stop();
Stopwatch swTwo = new Stopwatch();
swTwo.Start();
for (int i = 0; i < 10000000; i++)
{
int distanceFromTenTwo = (int)(Math.Ceiling(i / 10d) * 10 - i);
}
swTwo.Stop();
Console.WriteLine("Modulo: {0} ({1}ms)", sw.ElapsedTicks, sw.ElapsedMilliseconds);
averageModulo += sw.ElapsedTicks;
Console.WriteLine("Math.Ceiling: {0} ({1}ms)", swTwo.ElapsedTicks, swTwo.ElapsedMilliseconds);
averageCeiling += swTwo.ElapsedTicks;
Console.WriteLine("");
}
Console.WriteLine("Average modulo: {0}", averageModulo / loops);
Console.WriteLine("Average ceiling: {0}", averageCeiling / loops);
Console.ReadLine();
}
The modulo operation is always faster than the ceiling (might be because of the boxing). This being said, both operations are very fast.
With the new edit I think this is now aimed at generating valid EANs in as little time as possible. Here is some code that will generate 100000000 EAN-13 checksums (as documented on the Wikipedia page) in toughly 3.5 seconds.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("");
long start = 0;
long end = 99999999;
long count = end - start + 1;
long[] eans = new long[count];
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(start, end + 1, i => {
eans[i] = GenerateEAN13(i);
});
sw.Stop();
Console.WriteLine("Generation of {0} EAN-13s took {1} ticks ({2} ms)", count, sw.ElapsedTicks, sw.ElapsedMilliseconds);
Console.ReadLine();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long GenerateEAN13(long number)
{
long checksum = 0;
long digit = 0;
long tmp = number;
for (int i = 13; i >= 0; i--)
{
digit = tmp % 10;
tmp = tmp / 10;
checksum += i % 2 == 0 ? digit * 3 : digit;
if (tmp < 10)
break;
}
long modulus = checksum % 10;
checksum = modulus == 0 ? 0 : 10 - modulus;
return number * 10 + checksum;
}
}
Definitely use modulus for this. Your "cache" of values won't help much because the cost saved in the subtraction will be incurred in the lookup of the dictionary value by key, which in turn will call GetHashCode() and have some overhead:
int distanceFromNextTen = (10 - input % 10) % 10;

How to select random number

I need to get a random number in C#, within (-15, 15) but without generate values between (-10, 10) as float numbers. Like the random should come with in (-15,-10) and (10,15).
Is it possible to get?
This can be done in one line, but I separated it out for clarity.
public double GetRandomNumber()
{
//Between 0 and 1
Random random = new Random();
double randomNumber = random.NextDouble();
//Between -0.5 and 0.5;
randomNumber -= 0.5;
//Between -5.0 and 5.0;
randomNumber *= 10.0;
//Between [-15.0, -10.0] or [10.0, 15.0]
randomNumber += Math.Sign(randomNumber) * 10.0;
return randomNumber;
}
One way would be to use this:
var random = new Random();
var result = random.NextDouble();
if(result < 0.5)
result = -15 + result * 10;
else
result = 5 + result * 10;
Random.NextDouble generates a number between 0.0 and 1.0.
If it is less than 0.5 we treat this as the indicator to create a negative number.
Another approach, assuming that you do want a decimal place in your result (since it isn't entirely clear).
Random rand = new Random();
var intValue = rand.Next(10,15);
var decimalValue = rand.NextDouble();
var sign = rand.Next(0,1);
if (sign == 0) sign = -1;
return (intValue + decimalValue) * sign;
Generate two random numbers. The first random number will choose whether you're in the -15 to -10 range, or the 10 to 15 range, the second - how far along in that range you want to be.
Try:
Random random = new Random();
float value = (float) (Math.Sign((random.NextDouble() - 1)) * (10 + 5 * random.NextDouble()));
static Random r = new Random(2);
static void Main(string[] args)
{
int d = r.Next(-15, 15);
while ((d >= -15 && d <= -10) || (d >= 10 && d <= 15))
Console.WriteLine(d);
Console.ReadLine();
}
If you want integers and you want it to be performant, I would use:
var rand = new Random();
int value = rand.Next(-5, 7);
return value > 0 ? value + 9 : value - 10;
I am assuming you want numbers from the ranges: [-15, -10] and [10, -15]. Adjust hard-coded values above appropriately. To make it more performant, there may be a way to do some bit arithmetic and avoid the comparison but I'll leave that for the comments.
Here is a static method to accomplish that:
public static int RandomRange(int min, int max, bool includeNegatives = false)
{
if( min >= max) throw new Exception("min can't be greater than max");
Random rdm = new Random();
int num = 0;
while (num < min) num = rdm.Next(max + 1);
return num * (rdm.Next() % 2 == 0 ? -1 : 1);
}
To call it:
var TenToFifteenNegatives = RandomRange(10, 15, true);
var TenToFifteenNoNegatives = RandomRange(10, 15);

Categories

Resources