고대 수학 지식을 활용한 비트 연산 최적화

결합 법칙의 중요성은 컴퓨팅에서 매우 크며, 특히 고성능 계산 및 암호학 분야에서 중요한 역할을 합니다. 이 글에서는 결합 법칙을 이용하여 비트 조작을 최적화하는 방법과 이를 C++에서 구현하는 예제를 다룹니다.

유한체 지수 연산 (모듈로 지수 연산)

공개 키 암호화 알고리즘인 RSA와 Diffie-Hellman에서 핵심적인 연산입니다. 모듈로 곱셈을 반복 적용하여 큰 수를 효율적으로 처리할 수 있습니다.

template<typename T>
constexpr T modularExponentiation(T base, T exponent, T modulus) {
    T result = 1;
    while (exponent > 0) {
        if (exponent & 1)
            result = (result * base) % modulus;
        base = (base * base) % modulus;
        exponent >>= 1;
    }
    return result;
}

SWAR를 사용한 병렬 곱셈

결합 법칙을 활용하여 SWAR(SIMD Within A Register) 기술을 통해 가속화된 성능을 얻을 수 있습니다.

template<int BitsPerLane, typename DataType>
class SWAR {
public:
    using LaneType = std::array;
    LaneType lanes;

    void add(const SWAR& other) {
        for (int i = 0; i < BitsPerLane; ++i) {
            lanes[i] += other.lanes[i];
        }
    }
};

CUDA 코어를 사용한 병렬 지수 연산

CUDA는 정수 지수 연산에 직접적인 지원이 없지만, CUDA 코어를 사용하여 자체 구현한 정수 지수 연산을 통해 뛰어난 성능을 얻을 수 있습니다.

고대 이집트 곱셈법

고대 이집트 곱셈법은 결합 법칙을 활용하여 곱셈을 최적화하는 좋은 예시입니다.

template<typename T>
T egyptianMultiplication(T a, T b) {
    T result = 0;
    while (b != 0) {
        if (b & 1)
            result += a;
        a <<= 1;
        b >>= 1;
    }
    return result;
}

예제 설명

b의 값 b가 홀수? result 업데이트 a 두 배 (a <<= 1) b 갱신 (b >>= 1)
11 0 + 13 = 13 13 * 2 = 26 11 / 2 = 5
5 13 + 26 = 39 26 * 2 = 52 5 / 2 = 2
2 아니요 39 52 * 2 = 104 2 / 2 = 1
1 39 + 104 = 143 104 * 2 = 208 1 / 2 = 0

점진적 고대 이집트 곱셈

이 알고리즘은 최하위 유효 비트(LSB)부터 시작하여 결과를 누적합니다.

template<typename T>
T progressiveEgyptianMultiply(T a, T multiplier) {
    T result = 0;
    while (true) {
        if (multiplier & 1)
            result += a;
        if (multiplier == 0)
            break;
        a <<= 1;
        multiplier >>= 1;
    }
    return result;
}

역방향 고대 이집트 곱셈

이 알고리즘은 최상위 유효 비트(MSB)부터 시작하여 각 단계에서 결합 법칙을 사용하여 결과를 누적합니다.

template<typename T>
T regressiveEgyptianMultiply(T a, T multiplier) {
    T result = 0;
    int iterationCount = sizeof(T) * 8;
    while (iterationCount > 0) {
        if (multiplier & (1 << (sizeof(T) * 8 - 1)))
            result += a;
        iterationCount--;
        if (iterationCount == 0)
            break;
        result <<= 1;
        multiplier <<= 1;
    }
    return result;
}

결합 법칙 반복을 통한 일반화

결합 법칙을 이용한 반복 연산을 통해 다양한 연산을 추상화할 수 있습니다.

template<typename Base, typename IterationCount, typename Operator, typename CountHalver>
constexpr auto associativeIteration(Base base, Base neutral, IterationCount count, IterationCount forSquaring, Operator op, unsigned iterationCount, CountHalver ch) {
    auto result = neutral;
    if (!iterationCount) return result;
    for (; iterationCount > 0; iterationCount--) {
        result = op(result, base, count);
        result = op(result, result, forSquaring);
        count = ch(count);
    }
    return result;
}

SWAR와 결합 법칙 반복을 통한 곱셈

SWAR와 결합 법칙 반복을 결합하여 각 lane에서 병렬 곱셈을 수행할 수 있습니다.

template<int ActualBits, int NB, typename T>
constexpr auto swarMultiplication(SWAR multiplicand, SWAR multiplier) {
    auto iterationCount = ActualBits;
    auto neutral = SWAR{0};
    auto forSquaring = SWAR{1 << (NB - 1)};
    auto shifted = SWAR{multiplier.value() >> (NB - ActualBits)};

    auto operation = [](auto left, auto right, auto counts) {
        return left + ((counts & (1 << (NB - 1))) ? right : 0);
    };

    auto halver = [](auto counts) {
        return counts << 1;
    };

    return associativeIteration(multiplicand, neutral, shifted, forSquaring, operation, iterationCount, halver);
}

태그: cpp swar simd associative-iteration modular-exponentiation

6월 12일 17:02에 게시됨