2

指定された最大値に達するまで昇順のシーケンスを返し、その後再び降順を返す整数値の関数が必要です。私はそれをジッグラトと呼んでいます:

0 1 2 3 4 5 6 6 5 4 3 2 1 0

手順はすべて1つです。最大値(シーケンスの途中)は2回表示する必要があります。ゼロから最大2*の範囲外では、何が起こるかは気にしません。

関数を高速にしたい-分岐しない。私はビット演算が好きです。

動作しない例として、ピラミッド関数と絶対値の実装を次に示します。

private static readonly int LONG_ABS_MASK_SHIFT = sizeof(long) * 8 - 1;

/// <summary>
/// Compute the Absolute value of a long without branching.
/// 
/// Note: This will deviate from Math.Abs for Int64.MinValue, where the .NET library would throw an exception.
/// The most negative number cannot be made positive.
/// </summary>
/// <param name="v">Number to transform.</param>
/// <returns>Absolute value of v.</returns>
public static long Abs(this long v)
{
    long mask = v >> LONG_ABS_MASK_SHIFT;
    return (v ^ mask) - mask;
}

public static long Pyramid(this long N, long max)
{
    return max - (max - N).Abs();
}

このピラミッド関数は、0 1 2 3 4 5 6 5 4 3 210のようなシーケンスを作成します

真ん中の数字は1回だけ発生することに注意してください。

ルックアップテーブルをlongまたはBigInteger内のビットの連続ブロックとして格納し、それらをシフトしてマスクすることを考えましたが、長いシリーズではメモリを大量に消費します。ただし、使用する命令はごくわずかです。

4

3 に答える 3

3

これを試して:

public static long Pyramid2(this long N, long max)
{
    return N.Pyramid(max + 1) + ((max - N) >> -1);
}

結果:

0 1 2 3 4 5 6 6 5 4 3 2 1 0


結果は次のように得られます。

                  \ N=0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
  N.Pyramid(6 + 1)    0  1  2  3  4  5  6  7  6  5  4  3  2  1  0 -1 -2 -3 -4
+ ((max - N) >> -1)   0  0  0  0  0  0  0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
=                     0  1  2  3  4  5  6  6  5  4  3  2  1  0 -1 -2 -3 -4 -5

Pyramidは、質問で定義され た元のPyramidメソッドです。

于 2012-04-11T02:23:37.360 に答える
2
于 2012-04-11T05:28:39.520 に答える
1
public static IEnumerable<long> getPyramid(long maxValue)
{
    for(long i = 0; i <= maxValue; i++)
    {
        yield return i;
    }

    for(long i = maxValue; i >=0; i--)
    {
        yield return i;
    }
}

おそらく、select / reverseなどですべてを処理することもできConcat Enumerable.Rangeますが、カウントダウンする簡単な方法がわからないため、効率が少し低下する可能性があります。リバースは、forループを生成するよりも「作業」が多く、select(maxvalueから現在の反復を引いたものEnumerable.Range)は、数行のコードを回避するために、一連の追加の演算を実行します。

すなわち:

public static IEnumerable<long getPyramid(long maxValue)
{
  return Enumerable.Range(0, maxValue)
  .Concat(Enumerable.Range(0, maxValue).Select(num => maxValue - num));
}
于 2012-04-11T02:11:12.510 に答える