簡體   English   中英

Bignum除法與無符號8位整數。 C

[英]Bignum division with an unsigned 8 bit integer. C

我已經創建了一個算法,用於將整數最大為255字節的整數除以8位整數,並且它可以用於我已經完成的測試。 有沒有人對此有任何意見或任何改進建議? 有沒有更好的算法用於此目的? 我不希望bignum通過bignum除法算法,第二個整數是8位整數。

迄今為止的最佳解決方案(小端):

typedef struct{
    u_int8_t * data;
    u_int8_t length;
}CBBigInt;
void CBBigIntEqualsDivisionByUInt8(CBBigInt * a,u_int8_t b,u_int8_t * ans){
    // base-256 long division.
    u_int16_t temp = 0;
    for (u_int8_t x = a->length-1;; x--) {
        temp <<= 8;
        temp |= a->data[x];
        ans[x] = temp / b;
        temp -= ans[x] * b;
        if (!x)
            break;
    }
    a->length -= ans[a->length-1]? 0 : 1; // If last byte is zero, adjust length.
    memmove(a->data, ans, a->length); // Done calculation. Move ans to "a".
}

大端的舊解決方案:

它的工作原理是:

  1. 如果除數是2的冪,則向右移動一點。
  2. 否則,除數在大於被除數之前需要向左​​移動多少,並使16位整數成為除數,就好像它被移到左邊一樣。 這將用於減法。
  3. 設置與答案上的移位量對應的位。 所做的是股息可以適用於除數的數量,直到找到2的冪。
  4. 從被除數中取走移位的字節以創建余數。
  5. 對於余數重復步驟2,直到除數大於余數。 發生這種情況時,會找到答案。

typedef struct{
    u_int8_t * data;
    u_int8_t length;
}CBBigInt;
u_int8_t CBPowerOf2Log2(u_int8_t a){
    switch (a) {
        case 1:
            return 0;
        case 2:
            return 1;
        case 4:
            return 2;
        case 8:
            return 3;
        case 16:
            return 4;
        case 32:
            return 5;
        case 64:
            return 6;
    }
    return 7;
}
u_int8_t CBFloorLog2(u_int8_t a){
    if (a < 16){
        if (a < 4) {
            if (a == 1){
                return 0;
            }
            return 1;
        }
        if (a < 8){
            return 2;
        }
        return 3;
    }
    if (a < 64){
        if (a < 32) {
            return 4;
        }
        return 5;
    }
    if (a < 128){
        return 6;
    }
    return 7;
}
void CBBigIntEqualsRightShiftByUInt8(CBBigInt * a,u_int8_t b){
    u_int8_t deadBytes = b / 8; // These bytes fall off the side.
    a->length -= deadBytes; // Reduce length of bignum by the removed bytes
    u_int8_t remainderShift = b % 8;
    if (!remainderShift) { // No more work
        return;
    }
    u_int16_t splitter;
    u_int8_t toRight = 0; // Bits taken from the left to the next byte.
    for (u_int8_t x = 0; x < a->length; x++) {
        splitter = a->data[x] << 8 - remainderShift; // Splits data in splitters between first and second byte.
        a->data[x] = splitter >> 8; // First byte in splitter is the new data.
        a->data[x] |= toRight; // Take the bits from the left
        toRight = splitter; // Second byte is the data going to the right from this byte.
    }
}
void CBBigIntEqualsDivisionByUInt8(CBBigInt * a,u_int8_t b,u_int8_t * ans){
    if (!(b & (b - 1))){
        // For powers of two, division can be done through bit shifts.
        CBBigIntEqualsRightShiftByUInt8(a,CBPowerOf2Log2(b));
        return;
    }
    // Determine how many times b will fit into a as a power of two and repeat for the remainders
    u_int8_t begin = 0; // Begining of CBBigInt in calculations
    bool continuing = true;
    u_int8_t leftMost;
    bool first = true;
    while (continuing){
        // How much does b have to be shifted by before it becomes larger than a? Complete the shift into a shiftedByte
        int16_t shiftAmount;
        u_int16_t shiftedByte;
        if (a->data[begin] > b){
            shiftAmount = CBFloorLog2(a->data[begin]/b);
            shiftedByte = b << 8 + shiftAmount;
        }else if (a->data[begin] < b){
            shiftAmount = -CBFloorLog2(b/a->data[begin]);
            shiftedByte = b << 8 + shiftAmount;
            // Shift right once again if "shiftedByte > (a->data[begin] << 8) + a->data[begin+1]" as the shifted divisor should be smaller
            if (shiftedByte > ((a->data[begin] << 8) + a->data[begin+1])){
                shiftedByte >>= 1;
                shiftAmount--; // Do not forget about changing "shiftAmount" for calculations
            }
        }else{
            shiftAmount = 0;
            shiftedByte = b << 8;
        }
        // Set bit on "ans"
        if (shiftAmount < 0){ // If "shiftAmount" is negative then the byte moves right.
            ans[begin+1] |= 1 << (8 + shiftAmount);
            if (first) leftMost = 1;
        }else{
            ans[begin] |= 1 << shiftAmount; // No movement to right byte, jsut shift bit into place.
            if (first) leftMost = 0;
        }
        first = false; // Do not set "leftMost" from here on
        // Take away the shifted byte to give the remainder
        u_int16_t sub = (a->data[begin] << 8) + a->data[begin+1] - shiftedByte;
        a->data[begin] = sub >> 8;
        if (begin != a->length - 1) 
            a->data[begin + 1] = sub; // Move second byte into next data byte if exists.
        // Move along "begin" to byte with more data
        for (u_int8_t x = begin;; x++){
            if (a->data[x]){
                if (x == a->length - 1)
                    // Last byte
                    if (a->data[x] < b){
                        // b can fit no more
                        continuing = false;
                        break;
                    }
                begin = x;
                break;
            }
            if (x == a->length - 1){
                continuing = false; // No more data
                break;
            }
        }
    }
    a->length -= leftMost; // If the first bit was onto the 2nd byte then the length is less one
    memmove(a->data, ans + leftMost, a->length); // Done calculation. Move ans to "a".
}

謝謝!

我將其描述為“基地2長師”。 一個更好的選擇是“base 256 long division”。

這是一個(未經測試的,可能是錯誤的)示例:

typedef struct{
    u_int8_t * data;
    u_int8_t length;
} CBBigInt;


u_int8_t CBBigIntEqualsDivisionByUInt8(CBBigInt * a, u_int8_t b, u_int8_t * ans) {
    int i;
    unsigned int temp = 0;

    i = a.length;
    while(i > 0) {
       i--;
       temp <<= 8;
       temp |= a.data[i];
       ans.data[i] = temp / b;
       temp -= ans.data[i] * b;
    }
    return temp;   // Return remainder
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM