문제

일련의 옵션, 일부 직교 (모든 조합으로 결합 될 수 있음), 일부 독점 (세트에서 하나만 허용)이 있으며 세트를 선택해야합니다. enum 비트 와이즈와 결합 할 수 있도록 값 or 비트와 함께 추출되었습니다 and. 나는 그것을 선호한다 or-유효하지 않은 조합은 감지 할 수 있습니다.

거기 아무도 없나요 도구 생성을 위해 enums 이와 같이?

명확성을 위해 편집하십시오

나는 일부 깃발이 사용 된 비트 수를 줄이기 위해 결합되어 유효하지 않다는 사실을 활용할 수있는 것을 찾고 있습니다. 오류를 감지 할 수 있어야한다는 요구 사항은 부드럽습니다. 나 ~하지 않다 일이 끝나면 사용 된 내용을 알 수 있어야합니다.

C#을 사용하고 있지만 모든 솔루션이 도움이되어야합니다.

예제 패턴은 다음과 같습니다.

0011 00
0101 00
1001 00
0110 00
1010 00
1100 00

0000 01
0000 10

6 개의 독점 플래그와 2 ~ 6 비트의 직교 쌍을 얻습니다.

빠른 테스트는 5 비트가 9 값을 제공하고 6 비트가 20을 제공한다는 것을 보여줍니다.

도움이 되었습니까?

해결책

"독점적인"세트 n 옵션 (예 : 정확히 하나를 선택해야합니다), 적어도 우리는 필요합니다. ceil(log2(n)) 비트. 예를 들어 옵션 k 숫자로 표시 될 수 있습니다 k 기본에서2.

"직교"세트 n 옵션 (즉, 크기의 조합 0, 1, ..., n 선택할 수 있습니다.) 적어도 우리는 필요합니다 n 비트. 예를 들어 옵션 k0, k1, k2 비트를 제외하고 비트가 0 인 이진수로 표시 될 수 있습니다. 0, 1, 2.

따라서 여러 옵션 세트를 동시에 표현하기 위해 필요한 비트 수를 얻기 위해 각 옵션 세트에 필요한 비트 수를 추가합니다 ( "독점"또는 "직교"에 따라 다릅니다.

요컨대, 열거 값을 선택하려면

  • "독점"옵션 k 용도 k << r
  • "직교"옵션 k0, k1, ..., k{n-1} 용도 0x1 << r, 0x1 << (r+1), ..., 0x1 << (r+n-1)

어디에서 오프셋 r 이전 옵션 세트에서 사용하는 비트 수입니다.


이 구성을 자동화하는 방법의 예, Java :

/**
 * Construct a set of enum values, for the given sizes and types 
 * (exclusive vs orthogonal) of options sets.
 *
 * @param optionSetSizes
 *     number of elements in each option set
 * @param isOptionSetExclusive
 *     true if corresponding option set is exclusive, false if
 *     orthogonal
 * @returns
 *     array of m elements representing the enum values, where 
 *     m is the sum of option set sizes. The enum values are 
 *     given in the order of the option sets in optionSetSizes 
 *     and isOptionSetExclusive.
 */ 
int[] constructEnumValues(
        int[] optionSetSizes, 
        boolean[] isOptionSetExclusive)
{
    assert optionSetSizes.length == isOptionSetExclusive.length;

    // determine length of the return value
    int m = 0; 
    for (int i = 0; i < optionSetSizes.length; i++) m += optionSetSizes[i];
    int[] vals = new int[m];

    int r = 0; // number of bits used by the preceding options sets
    int c = 0; // counter for enum values used 

    for (int i = 0; i < optionSetSizes.length; i++)
    {
        // size of this option set
        int n = optionSetSizes[i];                   

        // is this option set exclusive?
        boolean exclusive = isOptionSetExclusive[i]; 

        for (int k = 0; k < n; k++)
        {
            vals[c] = (exclusive) ? (k << r) : (0x1 << (r + k));
            c++;
        }

        r += (exclusive) ? (int) Math.ceil(Math.log(n)/Math.log(2)) : n; 
    } 

    return vals;
}

다른 팁

이 작업을 수행하는 가장 좋은 일반적인 방법은 컨벤션만큼 도구가 아닙니다. 이와 같은 비트 플래그 목록을 정의합니다.

FLAG_1                    0x00000001
FLAG_2                    0x00000002
FLAG_3                    0x00000004
FLAG_4                    0x00000008
FLAG_5                    0x00000010
FLAG_6                    0x00000020

숫자가 1, 2, 4, 8 패턴으로 왼쪽으로 이동하기 때문에 작업하기 쉽습니다.

편집 : 댓글에 응답합니다. 글쎄, 당신이 비트 플래그를 독점 열거와 함께 조합하고 싶다면, 기본적으로해야 할 일은 숫자 공간으로 취급 될 비트 목록의 부분을 분할하는 것입니다. 따라서 두 비트 0x1과 0x2를 가져갈 수 있으며 이제 두 비트를 사용하여 0-3을 나타낼 수 있습니다. 같은 것 :

OPT_1_VAL_1               0x00000000
OPT_1_VAL_2               0x00000001
OPT_1_VAL_3               0x00000002
OPT_1_VAL_4               0x00000003
FLAG_1                    0x00000004
FLAG_2                    0x00000008
FLAG_3                    0x00000010
FLAG_4                    0x00000020

당신이 사용하는 마스킹 로직은 더 복잡해야합니다. 플래그를 찾으려면 (settings & flag_1) if (settings & opt_1_val_3) == opt_1_val_3)를 수행해야합니다.

도구를 모르지만 여기에는 고유 한 비트 열거를 약간 쉽게 생산할 수있는 트릭이 있습니다.

public enum Critters
{
   Amorphous = 0,
   Sloth =     1 << 0,
   Armadillo = 1 << 1,
   Weasel =    1 << 2,
   Crab =      1 << 3,
   Partridge = 1 << 4,
   Parakeet =  1 << 5,
   Rhino =     1 << 6
};

... 결합 할 수 있도록 열거 값 세트를 선택해야합니다 ...

당신은 ~ 진짜 수동으로 선택해야합니까? 예를 들어 Java는 가지고 있습니다 EnumSet 더러운 일이 당신을 위해 일하고 당신을 제시합니다. Set 이 플래그를 조작하기위한 인터페이스.

각 플래그가 단일 비트 위치에 해당하도록 두 개의 힘을 사용하십시오.

그 목적으로 표준 열거 (C#)를 사용할 수 있습니다. 이를 달성하려면 설정해야합니다 깃발 보호, 그런 다음 구체적으로 값을 숫자로 번호를 매 깁니다. 코드는 다음과 같이 보입니다.

[Flags]
public enum AvailableColours {
    black = 1,
    red = 2,
    green = 4,
    blue = 8,
    white = 16,
}

그런 다음 표준 비트 타이어 운영자는 예상대로 작동합니다.

편집] 음, 알았어, 가능한 조합을 생성하고 싶습니까? 귀하의 요구 사항은 매우 구체적이므로 원하는 것에 가까운 도구가 있으면 매우 놀랄 것입니다. 나는 당신이 당신 자신을 굴려야한다고 생각합니다. 나는 당신이 이것들을 끈으로 원한다고 가정합니다. 맞습니까? 다음은 최소한 시작하기위한 유틸리티 코드입니다.

public const int BITS_IN_BYTE = 8;
public const int BYTES_IN_INT = sizeof(int);
public const int BITS_IN_INT = BYTES_IN_INT * BITS_IN_BYTE;

/// <summary>
/// Display the bits in an integer
/// </summary>
/// <param name="intToDisplay">The integer to display</param>
/// <returns>A string representation of the bits</returns>
public string IntToBitString(int intToDisplay) {
    StringBuilder sb = new StringBuilder();
    AppendBitString(intToDisplay, sb);
    return sb.ToString();
}

/// <summary>
/// Displays the bits in an integer array
/// </summary>
/// <param name="intsToDisplay">Arrau to display</param>
/// <returns>String representation of the bits</returns>
public string IntArrayToBitString(int[] intsToDisplay) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < intsToDisplay.Length -1; i++) {
        AppendBitString(intsToDisplay[i], sb);
        sb.Append(' ');
    }
    if (intsToDisplay.Length - 1 > 0)
        AppendBitString(intsToDisplay[intsToDisplay.Length - 1], sb);
    return sb.ToString();
}

private void AppendBitString(int intToAppend, StringBuilder sb) {
    for (int j = BITS_IN_INT - 1; j >= 0; j--) {
        sb.Append((intToAppend >> j) & 1);
        if (j % 4 == 0 && j > 1)
            sb.Append(' ');
    }
}

/// <summary>
/// Creates an integer from a bit string. This method can be used
/// to explicitly set bits in an integer during testing.
/// </summary>
/// <example>
/// int i = bitUtil.IntFromBitString("0000 0000 0000 0100");
/// </example>
/// <param name="bitString">String representing the individual bits</param>
/// <returns></returns>
public int IntFromBitString(String bitString) {
    int returnInt = 0;
    int currentBitPos = bitString.Length;
    for (int i = bitString.Length - 1; i >= 0; i--) {
        char c = bitString[i];
        if (Char.IsWhiteSpace(c)) continue;

        if (c == '1') {
            returnInt |= 1 << (bitString.Length - currentBitPos);
        }
        currentBitPos--;
    }
    return returnInt;
}

/// <summary>
/// Tests the status of an individual bit in and integer. It is 0 based starting from the most
/// significant bit. 
/// </summary>
/// <param name="bits">The integer to test</param>
/// <param name="pos">The position we're interested in</param>
/// <returns>True if the bit is set, false otherwise</returns>
public bool IsBitOn(int bits, int pos) {
    int shiftAmnt = (BITS_IN_INT - 1) - pos;
    return ((bits >> shiftAmnt) & 1) == 1;
}

/// <summary>
/// Calculates the number of integers (as in an array of ints) required to
/// store a given number of bits
/// </summary>
/// <param name="bitsNeeded">The total count of required bits</param>
/// <returns>The number of integers required to represent a given bit count</returns>
public int RequiredSizeOfIntArray(int bitsNeeded) {
    return (bitsNeeded / BITS_IN_INT) + (((bitsNeeded % BITS_IN_INT) == 0) ? 0 : 1);
}

/// <summary>
/// Calculates which array element would hold the individual bit for a given bit position
/// </summary>
/// <param name="bitPos">The position of the interesting bit</param>
/// <returns>An index into an array of integers</returns>
public int ArrayPositionForBit(int bitPos) {
    return bitPos / BITS_IN_INT;
}

/// <summary>
/// Sets an individual bit to a given value
/// </summary>
/// <param name="bits">The integer containing the bits</param>
/// <param name="pos">The position in the integer to set</param>
/// <param name="isSet">True for on, False for off</param>
public void SetBit(ref int bits, int pos, bool isSet) {
    int posToSet = (BITS_IN_INT - 1) - pos;
    if (isSet)
        bits |= 1 << posToSet;
    else
        bits &= ~(1 << posToSet);
}

/// <summary>
/// Converts an array of integers into a comma seperated list
/// of hexidecimal values.
/// </summary>
/// <param name="bits">The array of integers</param>
/// <returns>String format</returns>
public String IntArrayToHexString(int[] bits) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bits.Length - 1; i++) {
        sb.Append(bits[i].ToString("X"));
        sb.Append(',');
    }
    if (bits.Length > 0) {
        sb.Append(bits[bits.Length - 1].ToString("X"));
    }
    return sb.ToString();
}

/// <summary>
/// Parses a comma seperated list of hexidecimal values and
/// returns an array of integers for those values
/// </summary>
/// <param name="hexString">Comma seperated hex values</param>
/// <returns>integer array</returns>
public int[] HexStringToIntArray(String hexString) {
    string[] hexVals = hexString.Split(new char[] {','});
    int[] retInts = new int[hexVals.Length];
    for (int i = 0; i < hexVals.Length; i++) {
        retInts[i] = Int32.Parse(hexVals[i], System.Globalization.NumberStyles.HexNumber);
    }
    return retInts;
}

비트 필드를 사용해야합니까?

내 경험상, 부울 데이터 멤버 세트가있는 수업이 거의 항상 최선의 선택입니다.

더 큰 부울 (종종 바이트) 대신 비트 필드를 사용하는 것에 대해 내가 들었던 유일한 주장은 그것이 더 빠르다는 것입니다. 모든 최적화와 마찬가지로 성능을 측정하지 않고 수행하는 것은 나쁜 생각입니다.

클래스에 캡슐화되면 최적화를 위해 표현을 변경하기로 결정하면 다른 코드를 많이 칠하지 않고도 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top