2016-06-30 4 views
3

符号付き整数空間を符号なし整数空間にマップする関数を書いています。しかし、正の数の前に負の数のマップが必要です。2^63を符号付き64ビット整数に加算し、中間の128ビット整数を使わずに符号なし64ビット整数にキャストする方法

私がこのような仕事を考えている方法 は、符号付き64ビット整数を持っているとします。符号なしの64ビット

にキャストa

  • に2 を追加し、128ビット
  • aキャスト

    1. しかし、問題は、私が働いていますCの実装ですwithは128ビットの整数を持ちません。

      効率的な方法はありますか?

  • 答えて

    6

    符号なしの型での算術は、2のnのモジュロです(つまり、ラップアラウンドします)。

    だから、すべてを行う必要がある:

    1. は、符号なしの64ビット
    2. aキャストだけMSBを切り替えるa
    +1

    だから、実際には符号なしで明示的にキャストする必要はありません。 'a +(1ULL << 63)'は動作します –

    +0

    その魔法は何ですか((1ULL << 63)) – Alvar

    +0

    @AlvarMa '<<'は左シフト演算子です。この場合は 'unsigned long long'型の' 1'という数字をとり、そのビットを '63'で左にシフトします。例えば、「1 << 1」は「2」(ビットは「0 ... 10」)であり、「1 << 3」は「0 ... 001000」であるため「8」であり、バイナリで8。基本的に「1 << n」は「n」のべき乗に「2」である。 – Bakuriu

    2

    に2 を追加ビット:
    1. aを符号なし64ビットにキャスト
    2. xorを2 と置き換えてください(または、2 を追加することもできます)。

    あなたは(XOR)を変更する必要があることを意味し、単に1つのビット(ビット63) サンプル出力:

    a     hex(a)    map(a) 
    -9223372036854775808 0x8000000000000000 0x0000000000000000 
    -9223372036854775807 0x8000000000000001 0x0000000000000001 
    -9223372036854775806 0x8000000000000002 0x0000000000000002 
    -9223372036854775805 0x8000000000000003 0x0000000000000003 
           -1000 0xfffffffffffffc18 0x7ffffffffffffc18 
           -10 0xfffffffffffffff6 0x7ffffffffffffff6 
            -1 0xffffffffffffffff 0x7fffffffffffffff 
            0 0x0000000000000000 0x8000000000000000 
            1 0x0000000000000001 0x8000000000000001 
            10 0x000000000000000a 0x800000000000000a 
           100 0x0000000000000064 0x8000000000000064 
           1000 0x00000000000003e8 0x80000000000003e8 
    9223372036854775805 0x7ffffffffffffffd 0xfffffffffffffffd 
    9223372036854775806 0x7ffffffffffffffe 0xfffffffffffffffe 
    9223372036854775807 0x7fffffffffffffff 0xffffffffffffffff 
    

    // xorを追加使用して)サンプルコード:

    #include <stdio.h> 
    #include <stdint.h> 
    #include <inttypes.h> 
    uint64_t show(int64_t n){ 
        uint64_t u = (uint64_t)n; 
        u += (uint64_t)1 << 63; // u ^= (uint64_t)1 << 63; 
        printf("%21"PRId64" %21"PRIu64" 0x%016"PRIx64"\n", n, u, u); 
        return u; 
    } 
    int main() 
    { 
        show(-1000); 
        show(-10); 
        show(-1); 
        show(0); 
        show(1); 
        show(10); 
        show(100); 
        show(1000); 
        return 0; 
    } 
    

    試験サンプルコードユニオンを使用してビットxorをデモする(リトルエンディアンのみ):

    #include <stdio.h> 
    #include <stdint.h> 
    #include <inttypes.h> 
    
    typedef union { 
        uint8_t b[8]; 
        int64_t i; 
        uint64_t u; 
    }T64bit; 
    
    uint64_t show(int64_t n){ 
        T64bit t; 
        t.i = n; 
        t.b[7] ^= 0x80; // t.b[7] += 0x80; 
        printf("%21"PRId64" %21"PRIu64" 0x%016"PRIx64"\n", n, t.u, t.u); 
        return t.u; 
    } 
    int main() 
    { 
        show(-1000); 
        show(-10); 
        show(-1); 
        show(0); 
        show(1); 
        show(10); 
        show(100); 
        show(1000); 
        return 0; 
    } 
    

    出力:

     -1000 9223372036854774808 0x7ffffffffffffc18 
          -10 9223372036854775798 0x7ffffffffffffff6 
          -1 9223372036854775807 0x7fffffffffffffff 
          0 9223372036854775808 0x8000000000000000 
          1 9223372036854775809 0x8000000000000001 
          10 9223372036854775818 0x800000000000000a 
          100 9223372036854775908 0x8000000000000064 
         1000 9223372036854776808 0x80000000000003e8 
    
    +0

    なぜあなたはxorで置き換えることによって追加を不明瞭にしていますか? –

    +1

    この質問はハードウェアの実装ではなく、 'c'でタグ付けされています。'x^= 1ULL << 63'と' x + = 1ULL << 63'のために異なるコードが生成されるとは信じる理由はありませんが、あなたが意味するときxorを書いて、コードの意味を無益に覆い隠します。ハードウェアでさえ、現代のHDLはこの種の難読化を奨励するのではなく、代わりに高水準の変換を可能にします。 –

    +0

    なぜ 'u^=(uint64_t)0x8000000000000000;'にキャストするのですか? '' llx ''よりも 'PRIx64'を使う方が良い – chux

    関連する問題