2017-09-05 3 views
4

私の入力がある:中位のビットがパターンに一致する次の整数。

  • ビット幅nmaskをマスクし、いくつかはk一部に1Sと> = 0
  • ビットパターンpattern(必ずしも全てではない)のビットマスクが有する位置をオフセット1s。
  • 私はresultような次の最大の整数を見つけたいval

整数:例えば

  • result > val
  • result & mask == pattern

mask = 0xFF00pattern = 0x0100を想定。その後、我々は次のような結果を期待する:

NextLargest(mask, pattern, 0x00000) => 0x00100 
NextLargest(mask, pattern, 0x000FF) => 0x00100 
NextLargest(mask, pattern, 0x010FE) => 0x001FF 
NextLargest(mask, pattern, 0x010FF) => 0x10100 

別の例は、 - mask = 0xFpattern = 0xFを言います。その後、我々は期待:

NextLargest(mask, pattern, 0x20) => 0x2F. 

私は「それをインクリメントについてmask心配、ビット、または背面pattern内を取り除くと返す」のようなものを試してみたが、私はエッジケースを打っておきます。問題は、ある整数の次に大きい倍数を見つける一般化のようなものです。ここで

は、これまでの私の試みです(実行可能リンク: https://ideone.com/AhXG5M):(擬似コード)

#include <iostream> 
using namespace std; 

using uint32 = unsigned long; 

uint32 NextLargest(int width, int offset, uint32 mask, uint32 pattern, uint32 val) { 
    unsigned long long ret = (val + 1) & ~mask; 
    if ((ret & ((1 << (offset + 1)) - 1)) == 0) { 
     // "carry" across the mask 
     ret += 1 << (offset + width); 
    } 
    return ret | pattern; 
} 

int main() { 
    // your code goes here 
    int width = 12; 
    int offset = 4; 

    uint32 significant_bits = (1 << (width + 1) - 1) << offset; 
    uint32 wanted_bits = 0xFFF << offset; 

    cout << hex; 
    // want 0xFFF1 -- correct 
    cout << NextLargest(width, offset, significant_bits, wanted_bits, 0) << endl; 
    // want 0xFFF2 -- correct 
    cout << NextLargest(width, offset, significant_bits, wanted_bits, 1) << endl; 
    // want 0x1FFFF0 -- incorrect, get 0xFFF0 
    cout << NextLargest(width, offset, significant_bits, wanted_bits, 0xF) << endl; 

    return 0; 
} 
+0

それは同様pattern' 'と等しくなるように'ヴァル&mask'ための本当ですか? –

+2

@RonおそらくこれはC++で行われているためですか?これは関連性があります。なぜなら、異なる言語がほとんど同じであっても、異なるビット操作関数を提供したり、有用なライブラリ関数などがある可能性があるからです。なぜ*それは関係ないでしょうか? –

+1

'NextLargest(マスク、パターン、0x010FF)=> 0x101FF'は' => 0x10100'ではありませんか? – user2079303

答えて

1

valueを3に分割して考えてください。 マスクの上、マスクの下、マスクの下のビット。 H(value),M(value),L(value)

われわれはM(result)==patternを知っています。 私たちは3人の候補者を持っています。

C1は、H(value)+pattern+0である。

C2は​​

C3はH(value)+pattern+X

X==(mask<<1)&~maskです。それはmaskの上の最下位ビットです。

pattern>M(value)の場合、C1を使用できます。 上位ビットを減らすと、数字は<valueになり、下位ビットを設定すると数字が大きくなります。

pattern==M(value)の場合、実際にはvalue+1であるC2を試すことができます。 パターンビットにオーバーフローが1つ追加されると失敗します。

これは、すべての下位ビットが設定され、次に下位に追加される場所がマスクの上にある最初のビットであることを意味します。

unsigned next_masked(unsigned mask,unsigned pattern,unsigned value){ 
    unsigned reduced_pattern=(mask&pattern);//May not be required... 
    unsigned over_add=(mask<<1)&~mask; 
    unsigned upper_mask=~(over_add-1); 
    unsigned cand=(value&upper_mask)|reduced_pattern; 
    if(cand>value){ 
     return cand; 
    } 
    if((value&mask)==reduced_pattern){ 
     unsigned scand=value+1; 
     if((scand&mask)==reduced_pattern){ 
      return scand; 
     } 
    } 
    return cand + over_add; 
} 

は、ここでは、いくつかのユニットテストで再びです:

#include <iostream> 

unsigned next_masked(unsigned mask,unsigned pattern,unsigned value){ 
    unsigned reduced_pattern=(mask&pattern);//May not be required... 
    unsigned over_add=(mask<<1)&~mask; 
    unsigned upper_mask=~(over_add-1); 
    unsigned cand=(value&upper_mask)|reduced_pattern; 
    if(cand>value){ 
     return cand; 
    } 
    if((value&mask)==reduced_pattern){ 
     unsigned scand=value+1; 
     if((scand&mask)==reduced_pattern){ 
      return scand; 
     } 
    } 
    return cand + over_add; 
} 

bool invariant_next_masked(unsigned mask,unsigned pattern,unsigned value,unsigned result){ 
    if((result&mask)!=(pattern&mask)){ 
     return false; 
    } 
    if(result<=value){ 
     return false; 
    } 
    for(unsigned test=result-1;test>value;--test){ 
     if((test&mask)==(pattern&mask)){ 
      return false; 
     } 
    } 
    return true; 
} 

int check_next_masked(unsigned mask,unsigned pattern,unsigned value,unsigned expect){ 
    unsigned result=next_masked(mask,pattern,value); 
    if(result!=expect){ 
     std::cout << std::hex << mask << ' ' << std::hex << pattern << ' ' << std::hex <<value << "==" << std::hex <<result << "!=" << std::hex <<expect <<'\n'; 
       return 1; 
    } 
    if(!invariant_next_masked(mask,pattern,value,result)){ 
     return 1; 
    } 
    return 0; 
} 

int main() { 
    int errors=0; 

    errors+=check_next_masked(0xFF00,0x0100,0x0000,0x00100); 
    errors+=check_next_masked(0xFF00,0x0100,0x00FF,0x00100); 
    errors+=check_next_masked(0xFF00,0x0100,0x10FE,0x10100);   
    errors+=check_next_masked(0xFF00,0x0100,0x1067,0x10100); 
    errors+=check_next_masked(0xFF00,0x0100,0x10123,0x10124); 
    errors+=check_next_masked(0xFF00,0x0100,0x110FF,0x20100); 
    errors+=check_next_masked(0xFF00,0x0100,0x102FF,0x20100); 
    errors+=check_next_masked(0xFF00,0x0100,0x101FF,0x20100); 
    errors+=check_next_masked(0x000F,0x0007,0x10123,0x10127); 
    errors+=check_next_masked(0x000F,0x0007,0x10128,0x10137); 
    errors+=check_next_masked(0x0FF0,0x0230,0x10128,0x10230); 
    errors+=check_next_masked(0x0FFF0,0x,0x,0x); 
    errors+=check_next_masked(0x0FFF0,0x,0x41237,0x41238); 
    errors+=check_next_masked(0x0FFF0,0x,0x4123F,0x51230); 


    if(errors>0){ 
     std::cout << "Errors "<< errors << '\n'; 
     return 1; 
    } 
    std::cout << "Success\n"; 
    return 0; 
} 
3

が、私はこれをテストしていないが、次のアルゴリズムが動作するはずです:

let mask, pattern, and val be inputs 
let fls be function that finds last bit set in word 
let ffs be function that finds first bit set in a word 

let applied be (val & ~mask) | pattern 
if applied is greater than val then 
    return applied 
let low_order_mask be (1 << ffs(mask)) - 1 
if applied == val then 
    let flipped_low be (~value & low_order_mask) 
    if not flipped_low then 
     return applied + 1 // no need to carry 
// need to carry 
let set_low_zero be applied & ~low_order_mask 
let carry be 1 << (fls(mask) + 1) 
return set_low_zero + carry 

flsffs POSIXによって提供されていますが、他のシステムはそうしないかもしれません。必要に応じてこれらを実装する方法については、SOの回答があります。

+0

素晴らしい、これは非常に合理的に見えます。私は私の実装を拡張し、完全なバージョンで答えを更新します。 'fls'と' ffs'はきちんとしていますが、私はこれまで見たことがありません。 'any_low_zero = value^low_order_maskについては、 '' value == low_order_mask'ならば単純化することができます。したがって、ブランチ全体が '== val == low_order_maskの場合、' 'apply applied + 1'になります。あるいは私は誤解していますか? –

+0

@PatrickCollinsあなたの結論は合理的ですが、私のコードがバグであるという事実を私に目覚めさせます。要点は、下位ビットのいずれかがゼロであるかどうかをテストし、残りを無視することです。マスク操作がありません。 – user2079303

+0

@PatrickCollinsは今より良くなるはずです。また、私のffs、flsの使用には不可欠なシフト操作が欠けていました。 – user2079303

0

最大又はSMALLEST次の値を計算する問題です?最大値は奇妙に見える。最小の値を計算する必要がある場合、このコードは動作するはずです:(gcc 7.1で、64ビットのターゲットを想定し、sizeof(void *)== sizeof(size_t)== sizeof(uint64_t))

size_t next_smallest_value (size_t mask, size_t pattern, size_t x) { 
    assert(pattern & mask == pattern); 
    // only change bits within mask range to meet the requirement 
    auto y = x & ~mask | pattern; 
    if (y > x) { 
     // if the operation increased the value 
     // mask off all the lower bits 
     auto lsb_mask = __builtin_ctzll(mask); 
     return y & ~ones(lsb_mask); 
    } else { 
     // otherwise, the operation decreased or didn't change the value 
     // need to increase the fraction higher than the mask 
     auto msb_mask = 63 - __builtin_clzll(mask); 
     // higher part cannot be empty if the masked part decrease 
     assert(msb_mask < 63); 
     auto higher = ((y >> msb_mask) + 1) << msb_mask; 
     // also higher part cannot overflow 
     assert(higher != 0); 
     return y & mask | higher; 
    } 
} 

考え方は非常に簡単です:ビットを3つの部分に分割します:上位部分、マスク部分、下部分。マスクされた部分はmaskpatternから直接導出でき、それ以外の値にはできません。

マスクされたビットを計算した後、値が増加すると、下部のすべてのビットがマスクされます。それ以外の場合は、上位部分を1だけ増やします(また、すべての下位ビットをマスクします)。

上記のコードは不正な入力を処理しませんが、アサーションをトリガーしますが、チェックは使い果たされません。

+0

残念ながら、私は、次の最小サイズではなく次の最大サイズを見つけるという要件を使用しています。あなたの仕事に感謝します。 –

+0

*次の最大値*とは何を意味するのですか?あなたの例は、 'mask = 0xff00'と' pattern = 0x0100'を与え、 'NextLargest(mask、pattern、0x00000)=> 0x00100'と書いた質問の最初の例のように私には分かりません。 (32ビット)*最大* '0xffff01ff'は* NOT *あなたが望むものですが、' 0x01ff'は '0x0100'よりも大きくなくても、この意味での要件を満たしていますか? 2番目の例と同じですが、 '0x0100'か' 0x01ff'でしょうか? 3番目の例は単純に入力より大きくはありません。それが私が混乱している理由です。または私は何かを逃している? –

0

ここではちょっと混乱しやすい質問の2つの関数 最初の関数は結果の要件を満たす次の最大の整数を返します。 2番目の値は、次のSMALLEST値を示します。


1:明らか

unsigned NextLargest (unsigned mask, unsigned pattern, unsigned val) { 

    // zero "mask" bits and set "pattern" bits in largest (unsigned) int 
    unsigned const x = ~mask | pattern; 

    // if result is not greater than val, we can't satisfy requirements 
    if (x <= val) { 
     ... report error, return error code or throw something 
    } 

    return x; 
} 

これは単なる要件result & mask == patternresult > valを満たす最高(符号なし)整数値を返す:result & mask == patternresult > valを満たす最大の整数を取得します。 if節は、結果がvalより大きくないかどうかをチェックし、関数は失敗します。


2:

unsigned NextSmallest (unsigned mask, unsigned pattern, unsigned val) { 

    unsigned const x = (val + mask + 1) & ~mask | pattern; 

    if (x <= val) { 
     ... increment wrapped, can't give greater value 
    } 

    return x; 
} 

編集:結果はまだvalより大きくなければなりませんのでval+mask(val|mask)を変更された要件を満たしているval後SMALLEST次の値を取得します。

この関数は、val + 1を計算し、オーバーフロービットをmaskのdビット以上に渡します。長い編集後

val  +mask +1  &~mask  |pattern == result 

0x00000 0x0ff00 0x0ff01 0x00001 0x00501 
0x00001 0x0ff01 0x0ff02 0x00002 0x00502 
0x000fe 0x0fffe 0x0ffff 0x000ff 0x005ff 
0x000ff 0x0ffff 0x10000 0x10000 0x10500 
0x00100 0x10000 0x10001 0x10001 0x10501 
0x0f000 0x1ef00 0x1ef01 0x10001 0x10501 
0x0ff00 0x1fe00 0x1fe01 0x10001 0x10501 
0x0ffff 0x1feff 0x1ff00 0x10000 0x10500 
0x10000 0x1ff00 0x1ff01 0x10001 0x10501 
0x10001 0x1ff01 0x1ff02 0x10002 0x10502 
0x100ff 0x1ffff 0x20000 0x20000 0x20500 

と私はまだ質問には十分に良い答えを与えることはできません書き換え:mask = 0x0ff00場合とpattern = 0x00500ここ は、関数が何をするか、いくつかの例です。その例には奇妙な結果があります。もし誰かがこれらの機能やその一部を役に立つと思ったら、私はまだここに残しておきます。また、私は実際にコンピュータ上の関数をテストしませんでした。

関連する問題