How can I get a random System.Decimal? System.Random
doesn't support it directly.

- 98,240
- 88
- 296
- 433

- 13,187
- 11
- 69
- 96
-
9would it not just be easier to generate a random integer between, say, 1 and 999, and divide the result by 100? ex. random number 1 would be 0.01 and 999 would be 9.99 – Stefan Z Camilleri Apr 19 '12 at 10:47
-
@StefanZCamilleri Depends on what you need the random decimal for. Have a read through some of the answers below. The complete range of possible Decimal values that can be represented is really large and some thought is required to get random ints to feed into the Decimal constructor. Then there is the problem of how uniform the random distribution of generated decimal values is. – Daniel Ballinger Apr 20 '12 at 01:05
-
Besides, if I am not mistaken, .01 is not between 1 and 999. It's less than 1 therefor would not be a valid response. – Gary O. Stenstrom Nov 17 '17 at 15:31
14 Answers
EDIT: Removed old version
This is similar to Daniel's version, but will give the complete range. It also introduces a new extension method to get a random "any integer" value, which I think is handy.
Note that the distribution of decimals here is not uniform.
/// <summary>
/// Returns an Int32 with a random value across the entire range of
/// possible values.
/// </summary>
public static int NextInt32(this Random rng)
{
int firstBits = rng.Next(0, 1 << 4) << 28;
int lastBits = rng.Next(0, 1 << 28);
return firstBits | lastBits;
}
public static decimal NextDecimal(this Random rng)
{
byte scale = (byte) rng.Next(29);
bool sign = rng.Next(2) == 1;
return new decimal(rng.NextInt32(),
rng.NextInt32(),
rng.NextInt32(),
sign,
scale);
}

- 1,421,763
- 867
- 9,128
- 9,194
-
I wondered about this and/or the ctor that takes a byte[] - but are all the byte[] permutations legal? – Marc Gravell Mar 04 '09 at 07:20
-
@Marc: My recollection is that they are, and the other bits are just ignored. I haven't checked though. – Jon Skeet Mar 04 '09 at 07:23
-
I did, it's just passed through a private ctor as if it was legal. You should try that and see if it makes sense. The implementation is hidden (InternalCall) and that junk data could corrupt calculations. – John Leidegren Mar 04 '09 at 07:31
-
@John: Right. Will check it out some time. I prefer my revised version anyway. I do like making it an extension method though... – Jon Skeet Mar 04 '09 at 07:35
-
@Jon - Yes, it's a lot nicer and with the extension, that's how I would do it to. But you could just as easily implement your NextInt32 in a similar fashion to mine. It's to bad that the Random class is this limited thing, it could do with some by ref and unsafe methods. – John Leidegren Mar 04 '09 at 07:40
-
I remember you said in one of your posts "... not all exponent combinations are valid. Only values 0-28 work..." (http://www.yoda.arachsys.com/csharp/decimal.html). Doesn't this mean that the old version here could produce invalid values? – Hosam Aly Mar 04 '09 at 09:00
-
@Hosam Aly: Well, the ReadDecimal method constructs the decimal by accessing a private constructor, this ctor does not test whether the exponent is valid or not. If the InternalCall methods don't check this then any calculation involving that number would be incorrect. – John Leidegren Mar 04 '09 at 09:08
-
I have been thinking about this, and I believe it will not produce a uniform distribution, but will rather favour larger numbers. I think we should give the second int a 33% probability of having a 0 value, and the third int a 67% probablity of 0. – Hosam Aly Mar 04 '09 at 19:13
-
And even the scale needs to be adjusted to favour lower values, as (I think) this would correspond better to the actual uniform distribution of values. – Hosam Aly Mar 04 '09 at 19:15
-
3@Hosam: It's absolutely non-uniform in terms of magnitude of decimal. It's uniform in terms of each bit pattern having the same probability of occurring. For a uniform pattern, we'd be better off generating a number between 0 and 1. – Jon Skeet Mar 04 '09 at 19:27
-
I marked this answer as accepted as it overcomes the issue I had with getting the full range of Int32 values (particularly int.MaxValue). I hadn't really thought about the distribution of random values I was expecting. If repetitions are an issue the Faber and Aly solution may be more appropriate. – Daniel Ballinger Mar 04 '09 at 23:55
-
@Daniel, for the record, I don't deserve any credit for that answer. I just fixed a typo. – Hosam Aly Mar 05 '09 at 04:20
-
@Jon: I see that you left a comment regarding the fact that this does not produce a uniform distribution, but I do think that should be lifted into the body of your answer. I think too many people rip code without understanding its behavior and that we have a responsibility to provide such warnings (lest we end up flying on a plane guided by poorly understood copied code). – jason Jan 04 '10 at 16:50
-
@JonSkeet, Why did you create NextInt32 instead of just using Next(0, Int.MaxValue)? – johnny 5 May 18 '16 at 15:09
-
@johnny5: Because `Next(0, int.MaxValue)` will never return `int.MaxValue`. – Jon Skeet May 18 '16 at 15:11
-
@JonSkeet so it's soley to include that value, so there is more even distribution? So If there's nothing that wrong with using next, I'd just be working with 1 less value? – johnny 5 May 18 '16 at 15:23
-
@johnny5: Well, it also includes all negative numbers as well. Basically it does what it says - it gives you an integer in the *entire* range of values. That's its purpose. It's not a matter of "a more even distribution" - unless you view "never, ever, ever hitting some values" as only a matter of distribution. – Jon Skeet May 18 '16 at 15:40
-
What is the idea behind the NextInt32? What does it solve that ordinary Next() does not? – LosManos Jul 08 '16 at 11:13
-
1@LosManos: `Next()` never returns a negative number. `NextInt32` can return *any* `int`. – Jon Skeet Jul 08 '16 at 11:14
-
-
1@D.R.: Yes, it is. I can't remember (8 1/2 years later) why I put it in, but it's possible there were some non-bitwise operations before. Removed now. – Jon Skeet Nov 19 '17 at 16:53
-
One year later ... did you choose 4 and 28 by fair dice roll or is there a reason why you chose 4 and 28 instead of the more obvious 16 and 16? – D.R. Sep 12 '18 at 19:24
-
@D.R.: One year after the previous comment, but nearly 10 years after the first answer. I'm afraid I can't remember why I picked those. – Jon Skeet Sep 13 '18 at 06:21
It is also, through the power of easy stuff, to do:
var rand = new Random();
var item = new decimal(rand.NextDouble());

- 545
- 1
- 5
- 15
-
2This might work for some use-cases, but it won't generate decimals with the precision that .NET decimal can support. – Michael Fry Dec 17 '19 at 19:07
You would normally expect from a random-number-generator that it not only generated random numbers, but that the numbers were uniformly randomly generated.
There are two definitions of uniformly random: discrete uniformly random and continuous uniformly random.
Discretely uniformly random makes sense for a random number generator that has a finite number of different possible outcomes. For example generating an integer between 1 and 10. You would then expect that the probability of getting 4 is the same as getting 7.
Continuously uniformly random makes sense when the random number generator generates numbers in a range. For example a generator that generates a real number between 0 and 1. You would then expect that the probability of getting a number between 0 and 0.5 is the same as getting a number between 0.5 and 1.
When a random number generator generates floating-point numbers (which is basically what a System.Decimal is - it is just floating-point with base 10), it is arguable what the proper definition of uniformly random is:
On one hand, since the floating-point number is being represented by a fixed number of bits in a computer, it is obvious that there are a finite number of possible outcomes. So one could argue that the proper distribution is a discrete continuous distribution with each representable number having the same probability. That is basically what Jon Skeet's and John Leidegren's implementation does.
On the other hand, one might argue that since a floating-point number is supposed to be an approximation to a real number, we would be better off by trying to approximate the behavior of a continuous random number generator - even though are actual RNG is actually discrete. This is the behavior you get from Random.NextDouble(), where - even though there are approximately as many representable numbers in the range 0.00001-0.00002 as there are in the range 0.8-0.9, you are a thousand times more likely to get a number in the second range - as you would expect.
So a proper implementation of a Random.NextDecimal() should probably be continuously uniformly distributed.
Here is a simple variation of Jon Skeet's answer that is uniformly distributed between 0 and 1 (I reuse his NextInt32() extension method):
public static decimal NextDecimal(this Random rng)
{
return new decimal(rng.NextInt32(),
rng.NextInt32(),
rng.Next(0x204FCE5E),
false,
0);
}
You could also discuss how to get an uniform distribution over the entire range of decimals. There is probably an easier way to do this, but this slight modification of John Leidegren's answer should produce a relatively uniform distribution:
private static int GetDecimalScale(Random r)
{
for(int i=0;i<=28;i++){
if(r.NextDouble() >= 0.1)
return i;
}
return 0;
}
public static decimal NextDecimal(this Random r)
{
var s = GetDecimalScale(r);
var a = (int)(uint.MaxValue * r.NextDouble());
var b = (int)(uint.MaxValue * r.NextDouble());
var c = (int)(uint.MaxValue * r.NextDouble());
var n = r.NextDouble() >= 0.5;
return new Decimal(a, b, c, n, s);
}
Basically, we make sure that values of scale are chosen proportionally to the size of the corresponding range.
That means that we should get a scale of 0 90% of the time - since that range contains 90% of the possible range - a scale of 1 9% of the time, etc.
There are still some problems with the implementation, since it does not take into account that some numbers have multiple representations - but it should be much closer to a uniform distribution than the other implementations.

- 48,631
- 24
- 141
- 189
-
Why is your scale ratio 0.1? It doesn't seem uniform to me. Perhaps 1.0/28 is more uniform. – Hosam Aly Mar 04 '09 at 12:41
-
-
That's quite interesting, because we're totally just putting in garbage. Supposedly you would wanna have a nice uniform distribution between 0 and 1 and then you would scale that with what ever range you require. Though I fail to see how this accomplish that? – John Leidegren Mar 04 '09 at 13:58
-
@Hosam Aly I have tried to explain in more depth what I am doing. Basically, you want to get scale=28 90% of the time, since that contains the largest range of numbers. 28*r.NextDouble() makes it as likely to get a number between 0.1 and 0.2 as it is to get a number between 100000000 and 200000000. – Rasmus Faber Mar 05 '09 at 08:18
-
@John Leidegren: Yes, it usually would be easier to start off with a uniform distribution between 0 and 1 and just scale that. I think I will make an answer that provides that. – Rasmus Faber Mar 05 '09 at 08:20
-
Sorry, it just occurred to me, that I had inverted the meaning of scale. So replace scale=x with scale=28-x in my comments. – Rasmus Faber Mar 05 '09 at 08:54
-
-
@RasmusFaber: I wonder if there is a way to speed up `GetDecimalScale` somehow, preferably with only a single call to `Random`. Any ideas or pointers? – D.R. Sep 12 '18 at 19:44
-
The code presented here is extremely useful and appreciated. It is unfortunate, however, that this answer misuses the word and concept of "continuous" throughout, when it seems to be talking about non-integral numbers. "Continuous" is a mathematical concept, but not a Computer Science term that is valid in the real-world. In programming *everything* is technically discrete, there is no "continuous", only discrete approximations of it, and your distinctions of "discrete" vs "continuous" would be better replaced with "integers" or "integral" vs "non-integral", "numerical" or "fractional", etc. – RBarryYoung Nov 19 '20 at 14:38
-
Upon further reflection, I think that if you just changed "continuous" to "continuous *distribution*", this would all be fine. By always including "distribution" it makes it clear that you are referring to the mathematical concept of random distributions. As currently written it appears that you are talking about the computer representation of values from those distributions, which are not at all continuous. – RBarryYoung Nov 19 '20 at 16:18
I know this is an old question, but the distribution issue Rasmus Faber described kept bothering me so I came up with the following. I have not looked in depth at the NextInt32 implementation provided by Jon Skeet and am assuming (hoping) it has the same distribution as Random.Next().
//Provides a random decimal value in the range [0.0000000000000000000000000000, 0.9999999999999999999999999999) with (theoretical) uniform and discrete distribution.
public static decimal NextDecimalSample(this Random random)
{
var sample = 1m;
//After ~200 million tries this never took more than one attempt but it is possible to generate combinations of a, b, and c with the approach below resulting in a sample >= 1.
while (sample >= 1)
{
var a = random.NextInt32();
var b = random.NextInt32();
//The high bits of 0.9999999999999999999999999999m are 542101086.
var c = random.Next(542101087);
sample = new Decimal(a, b, c, false, 28);
}
return sample;
}
public static decimal NextDecimal(this Random random)
{
return NextDecimal(random, decimal.MaxValue);
}
public static decimal NextDecimal(this Random random, decimal maxValue)
{
return NextDecimal(random, decimal.Zero, maxValue);
}
public static decimal NextDecimal(this Random random, decimal minValue, decimal maxValue)
{
var nextDecimalSample = NextDecimalSample(random);
return maxValue * nextDecimalSample + minValue * (1 - nextDecimalSample);
}

- 1
- 1

- 197
- 2
- 7
Here is Decimal random with Range implementation that works fine for me.
public static decimal NextDecimal(this Random rnd, decimal from, decimal to)
{
byte fromScale = new System.Data.SqlTypes.SqlDecimal(from).Scale;
byte toScale = new System.Data.SqlTypes.SqlDecimal(to).Scale;
byte scale = (byte)(fromScale + toScale);
if (scale > 28)
scale = 28;
decimal r = new decimal(rnd.Next(), rnd.Next(), rnd.Next(), false, scale);
if (Math.Sign(from) == Math.Sign(to) || from == 0 || to == 0)
return decimal.Remainder(r, to - from) + from;
bool getFromNegativeRange = (double)from + rnd.NextDouble() * ((double)to - (double)from) < 0;
return getFromNegativeRange ? decimal.Remainder(r, -from) + from : decimal.Remainder(r, to);
}

- 1,883
- 1
- 21
- 22
Since the OP question is very embracing and just want a random System.Decimal without any restriction, below is a very simple solution that worked for me.
I was not concerned with any type of uniformity or precision of the generated numbers, so others answers here are probably better if you have some restrictions, but this one works fine in simple cases.
Random rnd = new Random();
decimal val;
int decimal_places = 2;
val = Math.Round(new decimal(rnd.NextDouble()), decimal_places);
In my specific case, I was looking for a random decimal to use as a money string, so my complete solution was:
string value;
value = val = Math.Round(new decimal(rnd.NextDouble()) * 1000,2).ToString("0.00", System.Globalization.CultureInfo.InvariantCulture);

- 1,653
- 2
- 31
- 60
I puzzled with this for a bit. This is the best I could come up with:
public class DecimalRandom : Random
{
public override decimal NextDecimal()
{
//The low 32 bits of a 96-bit integer.
int lo = this.Next(int.MinValue, int.MaxValue);
//The middle 32 bits of a 96-bit integer.
int mid = this.Next(int.MinValue, int.MaxValue);
//The high 32 bits of a 96-bit integer.
int hi = this.Next(int.MinValue, int.MaxValue);
//The sign of the number; 1 is negative, 0 is positive.
bool isNegative = (this.Next(2) == 0);
//A power of 10 ranging from 0 to 28.
byte scale = Convert.ToByte(this.Next(29));
Decimal randomDecimal = new Decimal(lo, mid, hi, isNegative, scale);
return randomDecimal;
}
}
Edit: As noted in the comments lo, mid and hi can never contain int.MaxValue so the complete range of Decimals isn't possible.

- 13,187
- 11
- 69
- 96
-
Not quite... Random.Next(int.MinValue, int.MaxValue) will never return int.MaxValue. I've got an answer, but I think I can improve on it. – Jon Skeet Mar 04 '09 at 07:13
-
1Statistics is not my strong point, so I'm probably wrong, but I'd worry that the distribution might not be very uniform. – Michael Burr Mar 04 '09 at 07:14
here you go... uses the crypt library to generate a couple of random bytes, then convertes them to a decimal value... see MSDN for the decimal constructor
using System.Security.Cryptography;
public static decimal Next(decimal max)
{
// Create a int array to hold the random values.
Byte[] randomNumber = new Byte[] { 0,0 };
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
// Fill the array with a random value.
Gen.GetBytes(randomNumber);
// convert the bytes to a decimal
return new decimal(new int[]
{
0, // not used, must be 0
randomNumber[0] % 29,// must be between 0 and 28
0, // not used, must be 0
randomNumber[1] % 2 // sign --> 0 == positive, 1 == negative
} ) % (max+1);
}
revised to use a different decimal constructor to give a better range of numbers
public static decimal Next(decimal max)
{
// Create a int array to hold the random values.
Byte[] bytes= new Byte[] { 0,0,0,0 };
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
// Fill the array with a random value.
Gen.GetBytes(bytes);
bytes[3] %= 29; // this must be between 0 and 28 (inclusive)
decimal d = new decimal( (int)bytes[0], (int)bytes[1], (int)bytes[2], false, bytes[3]);
return d % (max+1);
}

- 28,542
- 5
- 55
- 68
-
That does mean we're limited to 65536 values out of the huge possible range though, doesn't it? – Jon Skeet Mar 04 '09 at 09:15
-
2Are we living in the days of 16-bit computing? What's the meaning of this? – John Leidegren Mar 04 '09 at 13:59
static decimal GetRandomDecimal()
{
int[] DataInts = new int[4];
byte[] DataBytes = new byte[DataInts.Length * 4];
// Use cryptographic random number generator to get 16 bytes random data
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
do
{
rng.GetBytes(DataBytes);
// Convert 16 bytes into 4 ints
for (int index = 0; index < DataInts.Length; index++)
{
DataInts[index] = BitConverter.ToInt32(DataBytes, index * 4);
}
// Mask out all bits except sign bit 31 and scale bits 16 to 20 (value 0-31)
DataInts[3] = DataInts[3] & (unchecked((int)2147483648u | 2031616));
// Start over if scale > 28 to avoid bias
} while (((DataInts[3] & 1835008) == 1835008) && ((DataInts[3] & 196608) != 0));
return new decimal(DataInts);
}
//end

- 1,265
- 2
- 18
- 35
Check out the following link for ready-made implementations that should help:
MathNet.Numerics, Random Numbers and Probability Distributions
The extensive distributions are especially of interest, built on top of the Random Number Generators (MersenneTwister, etc.) directly derived from System.Random, all providing handy extension methods (e.g. NextFullRangeInt32, NextFullRangeInt64, NextDecimal, etc.). You can, of course, just use the default SystemRandomSource, which is simply System.Random embellished with the extension methods.
Oh, and you can create your RNG instances as thread safe if you need it.
Very handy indeed!
This is an old question, but for those who are just reading it, why re-invent the wheel?

- 173
- 1
- 4
To be honest I don't believe the internal format of the C# decimal works the way many people think. For this reason at least some of the solutions presented here are possibly invalid or may not work consistently. Consider the following 2 numbers and how they are stored in the decimal format:
0.999999999999999m
Sign: 00
96-bit integer: 00 00 00 00 FF 7F C6 A4 7E 8D 03 00
Scale: 0F
and
0.9999999999999999999999999999m
Sign: 00
96-bit integer: 5E CE 4F 20 FF FF FF 0F 61 02 25 3E
Scale: 1C
Take special note of how the scale is different but both values are nearly the same, that is, they are both less than 1 by only a tiny fraction. It appears that it is the scale and the number of digits that have a direct relationship. Unless I'm missing something, this should throw a monkey wrench into most any code that tampers with the 96-bit integer part of a decimal but leaves the scale unchanged.
In experimenting I found that the number 0.9999999999999999999999999999m, which has 28 nines, has the maximum number of nines possible before the decimal will round up to 1.0m.
Further experimenting proved the following code sets the variable "Dec" to the value 0.9999999999999999999999999999m:
double DblH = 0.99999999999999d;
double DblL = 0.99999999999999d;
decimal Dec = (decimal)DblH + (decimal)DblL / 1E14m;
It is from this discovery that I came up with the extensions to the Random class that can be seen in the code below. I believe this code is fully functional and in good working order, but would be glad for other eyes to be checking it for mistakes. I'm not a statistician so I can't say if this code produces a truly uniform distribution of decimals, but if I had to guess I would say it fails perfection but comes extremely close (as in 1 call out of 51 trillion favoring a certain range of numbers).
The first NextDecimal() function should produce values equal to or greater than 0.0m and less than 1.0m. The do/while statement prevents RandH and RandL from exceeding the value 0.99999999999999d by looping until they are below that value. I believe the odds of this loop ever repeating are 1 in 51 trillion (emphasis on the word believe, I don't trust my math). This in turn should prevent the functions from ever rounding the return value up to 1.0m.
The second NextDecimal() function should work the same as the Random.Next() function, only with Decimal values instead of integers. I actually haven't been using this second NextDecimal() function and haven't tested it. Its fairly simple so I think I have it right, but again, I haven't tested it - so you will want to make sure it is working correctly before relying on it.
public static class ExtensionMethods {
public static decimal NextDecimal(this Random rng) {
double RandH, RandL;
do {
RandH = rng.NextDouble();
RandL = rng.NextDouble();
} while((RandH > 0.99999999999999d) || (RandL > 0.99999999999999d));
return (decimal)RandH + (decimal)RandL / 1E14m;
}
public static decimal NextDecimal(this Random rng, decimal minValue, decimal maxValue) {
return rng.NextDecimal() * (maxValue - minValue) + minValue;
}
}

- 1,423
- 1
- 10
- 12
I wanted to generate "random" decimals up to 9 decimal places. My approach was to just generate a double and divide it for the decimals.
int randomInt = rnd.Next(0, 100);
double randomDouble = rnd.Next(0, 999999999);
decimal randomDec = Convert.ToDecimal(randomint) + Convert.ToDecimal((randomDouble/1000000000));
the "randomInt" is the number before the decimal place, you could just put 0. To reduce decimal points simply remove "9"s in random and "0"s in dividing

- 699
- 1
- 7
- 13
public static decimal RandomDecimal()
{
int a = RandomNumber(2, 10);
int b = RandomNumber(0, 99);
string c = a + "." + b;
decimal d = decimal.Parse(c);
return d;
}
public static int RandomNumber(int min, int max)
{
return _random.Next(min, max);
}

- 29
- 3
-
Please don't post code-only answers. Future readers will be grateful to see explained *why* it answers the question instead of having to infer it from the code. And, since this is an old question, please explain how it compliments the other answers. If it doesn't, kindly remove the answer. – Gert Arnold Jan 29 '22 at 15:04
System.Random rnd = new System.Random();
System.Math.Round( Convert.ToDecimal(rnd.NextDouble() * (maxValue-minValue) + minValue) , decimalPlaces);
Oneliners are always the best full code and example bellow
using System;
public class Program
{
public static void Main()
{
var val = GetRandomDecimal(0, 100, 2);
Console.WriteLine(val.ToString());
}
static System.Random rnd = new System.Random();
public static decimal GetRandomDecimal(int minValue, int maxValue, int decimalPlaces)
{
return System.Math.Round( Convert.ToDecimal(rnd.NextDouble() * (maxValue-minValue) + minValue) , decimalPlaces);
}
}

- 997
- 2
- 12
- 25
-
The `Math.Round` is causing a bias for the upper and lower bounded numbers. So, for example, if I tried to generate numbers between 0 and 1 with 1 decimal place then 0.0 comes up one 20th of the time, as does 1.0. The other numbers, 01. to 0.9 come up one tenth of the time. This isn't uniform. – Enigmativity Jun 06 '22 at 08:22