atsukanrockのブログ

Microsoft系技術を中心にぼちぼち更新します

.NETで、桁数と精度を指定してランダムな数値を生成する

はじめに

桁数と精度を指定してランダムな数値を生成するメソッドの、.NET(C#)での実装例を示す。

補足説明

「桁数」と「精度」というのは、OracleのNUMBER型で指定する、NUMBER(p, s)の

  • p:桁数
  • s:精度

のこと。NUnitなどを使ったユニットテストで、OracleのNUMBER型のフィールドに、ランダムな数値を設定したい、といった用途が*1想定される。

以下の実装例だと、戻り値が必ず0以上の数となる。戻り値に負の数も現れるようにするためには、もうひと工夫が必要。

コメント

以下の実装例、なんだかとっても重たそうですね…。でも、私にはこれしか思いつきませんでした。別のもっと良いアイデア、募集中です!!
※ビット演算とか使った、すげぇやつを見てみたい(。-_-。)

あと、以下の実装例が間違ってる可能性もあります。間違いのご指摘、歓迎です!!

実装例1 - ユーティリティメソッドとして…

/// <summary>
/// <c>0</c> 以上、かつ指定された桁数、および精度で表せる最大の数以下の、
/// ランダムな <see cref="Double"/> 値を返す。
/// </summary>
/// <param name="precision">戻り値の桁数。</param>
/// <param name="scale">戻り値の精度。</param>
/// <returns>ランダムな <see cref="Double"/> 値。</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="precision"/><c>0</c> 以下の数が指定された。
/// </exception>
/// <remarks>
/// <paramref name="scale"/><c>0</c> を指定することで、
/// 戻り値が整数となる。
/// </remarks>
public static double GetRandomDouble(int precision, int scale)
{
    if (precision <= 0)
    {
        throw new ArgumentOutOfRangeException("precision",
            precision, "0 より大きい数を指定してください。");
    }
    var value = Math.Pow(10, precision) * __random.NextDouble();
    value = Math.Truncate(value);
    value /= Math.Pow(10, scale);
    return value;
}

/// <summary>
/// <see cref="GetRandomDouble"/> メソッドが使用する乱数ジェネレータ。
/// </summary>
private static readonly Random __random = new Random();

実装例2 - C# 3.0から使える拡張メソッドを使って…

/// <summary>
/// <c>0</c> 以上、かつ指定された桁数、および精度で表せる最大の数以下の、
/// ランダムな <see cref="Double"/> 値を返す。
/// </summary>
/// <param name="random">疑似乱数ジェネレータ。</param>
/// <param name="precision">戻り値の桁数。</param>
/// <param name="scale">戻り値の精度。</param>
/// <returns>ランダムな <see cref="Double"/> 値。</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="random"/><c>null</c> が指定された。
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="precision"/><c>0</c> 以下の数が指定された。
/// </exception>
/// <remarks>
/// <paramref name="scale"/><c>0</c> を指定することで、
/// 戻り値が整数となる。
/// </remarks>
public static double NextDouble(this Random random, int precision, int scale)
{
    if (random == null)
    {
        throw new ArgumentNullException("random");
    }
    if (precision <= 0)
    {
        throw new ArgumentOutOfRangeException("precision",
            precision, "0 より大きい数を指定してください。");
    }
    var value = Math.Pow(10, precision) * random.NextDouble();
    value = Math.Truncate(value);
    value /= Math.Pow(10, scale);
    return value;
}

*1:ニッチですねー