2

I'm creating a RandomDecimal function that allows you to specify a max value and the precision of the decimal. However, if the last random digit that is chosen happens to be zero, it is dropped and the precision is off. Is it possible to not lose this zero? I tried converting it to a string then back to a decimal but it's still dropped.

    public static decimal RandomDecimal(int maxValue, int precision)
    {
        decimal result = new Random().Next(maxValue);

        if (maxValue == 0)
        {
            return result;
        }

        int i = 1;

        decimal digit = 0;

        while (i <= precision)
        {
            digit = new Random().Next(10);
            digit = (digit / (Convert.ToDecimal(Math.Pow(10, i))));
            result = result + digit;
            i++;
        }

    //    if (digit == 0)
    //    {
    //     string resultstring = Convert.ToString(result) + '0';
   //      result = Convert.ToDecimal(resultstring);
   //       } This code doesn't do anything because the zero is still dropped.

        return result;
    }
SetFreeByTruth
  • 819
  • 8
  • 23
  • 2
    This kind of 'precision' only exists when converting to string. – H H Jul 19 '12 at 17:40
  • @HenkHolterman Not true. That's true of the existing C# data types, but conceptually a number that's not a string can have "precision". – Servy Jul 19 '12 at 17:40
  • I was talking specifically about `decimal`. It does not record the number of fractional digits. – H H Jul 19 '12 at 17:41
  • @HenkHolterman: perhaps he means the "scale" of the 96-bit integer? – user7116 Jul 19 '12 at 17:43

3 Answers3

4

If you want a representation of a number that has not only a value, but knows how many significant digits it has you are better off using something other than double/float/decimal. You'll want to create your own type that has both a value and a SignificantDigits property.

You simply want information decimal wasn't designed to have users using. In certain situations (where you have no leading/trailing zeros) you coincidentally end up with the same result despite [decimal] not knowing the information, but that's irrelevant to you solving your problem.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    Not true, according to the MSDN description of Decimal. – MNGwinn Jul 19 '12 at 17:47
  • @MNGwinn From everything that I can see that's an implementation detail as the data isn't available or mutable by the public interface (beyond just getting/setting the bits of the structure directly). Because of this, even if it were *possible* to use a decimal, it would be quite hard and so it would still be best to create a new Type. Doing so would allow you to easily get or set the precision of a particular value, add/multiply or perform other operations on values and determine the precision of the result using your own rules (other than whatever `decimal` does), etc. – Servy Jul 19 '12 at 18:03
  • A new type is quite possibly a better solution. My objection's just to the statement that he wants data that's not stored in a decimal. – MNGwinn Jul 19 '12 at 18:12
  • I think my situation is just getting interpreted differently, I see the difference in what both of you are saying though. Both have been helpful. Thank you! –  Jul 19 '12 at 18:13
  • @MNGwinn Changed wording since you are right, it is technically possible to use a decimal, just difficult and unproductive. – Servy Jul 19 '12 at 18:14
  • @Servy: considering the decimal type does store a scale, which will preserve trailing zeros, I'm not sure what you mean by "information `decimal` wasn't designed to have users storing". – user7116 Jul 19 '12 at 18:49
  • @sixlettervariables The information is stored, but it can't be accessed by it's public interface, nor set explicitly, so clearly it's an implementation detail. It might exist, but I'm not supposed to used it. – Servy Jul 19 '12 at 19:03
  • @Servy: I would disagree that it is an "implementation detail". The fact that trailing zeros are stored is well defined as the scale of a decimal is significant. – user7116 Jul 19 '12 at 19:12
1

What you want can only be done (with built-in types) by returning a string instead of a decimal. You should also declare a Random object once, not creating new ones multiple times within a single method.

    static Random r = new Random();
    public static string RandomDecimal(int maxValue, int precision)
    {
        decimal result = r.Next(maxValue);

        if (maxValue != 0)
        {
            int i = 1;

            decimal digit = 0;

            while (i <= precision)
            {
                digit = r.Next(10);
                digit = (digit / (Convert.ToDecimal(Math.Pow(10, i))));
                result = result + digit;
                i++;
            }
        }
        var sb = new StringBuilder("0.");
        sb.Append('0', precision);
        return result.ToString(sb.ToString());
    }
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • Thanks for the tip about generating the random object over and over again. :) Something in the back of mind was telling me it probably wasn't the best practice. –  Jul 19 '12 at 18:04
1

The Decimal struct stores a scaling factor internally as a power of 10. According to MSDN,

The scaling factor also preserves any trailing zeroes in a Decimal number. Trailing zeroes do not affect the value of a Decimal number in arithmetic or comparison operations. However, trailing zeroes can be revealed by the ToString method if an appropriate format string is applied.

It's not obvious to me that there's any way to directly set the scaling factor, except by using the Decimal (Int32, Int32, Int32, Boolean, Byte) constructor, which takes the scaling factor as the last argument. So, in theory, you could create a decimal with significant trailing 0s by creating your Decimals with that constructor.

MNGwinn
  • 2,394
  • 17
  • 18
  • Just ran through my code and this is in fact correct...The decimal doesn't have the digits, but once I convert it to a string the digits reappear. Thanks for your help! I still wish there was a way to get them to display without converting to a string, but this should suffice for my purposes. –  Jul 19 '12 at 18:09
  • You can, to an extent. Nothing to stop you from upvoting multiple answers and then picking the best one. – MNGwinn Jul 19 '12 at 19:07