気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答5件
0
質問の絵に描いてあるシフトは循環シフトというものです。CおよびC++の<<
と>>
は算術シフトであり、そのような動作になりません。
算術シフトは2の補数ビット列で整数が表現されていれば、ビットをシフトすることで演算されますが、C/C++では2の補数ビット列であるという保証はありません。そのため、<<
や>>
が本当にビット列をシフトする処理になるのかはわかりません。また、符号あり・なし、正・負、越える越えないによって、動作が異なります。
演算 | aの符号 | aの値 | 結果 |
---|---|---|---|
a << b | unsigned | 非負 | a*2^b |
a << b | signed | 非負 | 整数の最大値を超えない場合はa*2^b、越える場合は未定義 |
a << b | signed | 負 | 未定義 |
a >> b | unsigned | 非負 | a/2^b |
a >> b | signed | 非負 | a/2^b |
a >> b | signed | 負 | 実装依存(ほとんどの実装では最上位ビットを保持したままずらす) |
※ ^
は冪乗を表します。
※ 未定義の動作は何が起こるかは規格上決められていないものです。エラーで強制的に終了する場合もあれば、何も起きない場合もありえます。
※ 実装依存の動作は、実装(コンパイラや環境)によって異なる動作です。コンパイラや環境によってどうなるかが定まっています。
ほとんどの実装においては、整数は2の補数ビット列で表現されるため、<<
は0
を右から埋めていく、>>
はunsignedの場合は0
を左から埋めていき、signedの場合は最上位ビットの同じ値(非負なら0
、負なら1
)を左から埋めていくという動作をします。しかし、上の表にある未定義や実装依存の動作について、全ての環境で同じようになるとは限りません。
なお、C/C++以外の言語は上の限りではありません。Javaなど>>>
という演算子を別途用意している言語もあります。
投稿2017/07/03 15:14
総合スコア21751
0
###追記2
raccyさん他の方が丁寧に回答くださっているので蛇足的ではありますが、C/C++についての自分の回答は間違いであることを改めて強調しておきたいと思います。
特定のC/C++コンパイラーの仕様にはシフト演算子の振る舞いが「他のコンパイラーでは違うかもしれない」との警告とともに明記されていたりしますが、それに依存したコードはもちろん可搬性を損なう結果になります。
Javaなど他の言語の中には「言語仕様でシフトの振る舞いが一意に決められていて可搬性のあるプログラムでそれを前提にできる」ものもあるのですが、C/C++ではそうではないわけです。
自分が言うのも間抜けですが、「仕様書で正確な意味を把握していないといつか痛い目にあう」ことの実例として教訓にしていただければと思います。
- 自分のプログラムにバグを混入させてしまう
- 間違った知識を他者へ広めてしまう(そして罪なきプログラマーを迷宮へいざなう・・・)
前者もそうですが後者が特に罪深いと思います。改めてお詫びいたします。
以下元の回答
ローテートとシフトを混同されているように思えます。図にかかれた演算はシフトではなくローテートと呼ばれます。
シフトおよびローテートの詳しい説明はwikipediaのご覧のページにあるとおりなので再度注意深く確認してみてください。
右シフトは単純にいうと符号付きの数を2で整数除算するのが算術右シフトで、負号なしの数を2で整数除算するのが論理右シフトということをまず覚えておくとよいと思います。
算術右シフトについて、それが二進数でなぜそうなるのかは、2の補数表現についてよく理解した上で考えるとわかると思います。(逆に2の補数表現を把握していないとピンとこないはずです)
訂正・補足1:Wikipediaのシフトの説明として算術シフト、論理シフトと2の補数表現を結び付けて説明したのですが、raccyさんの回答をご覧いただければわかるように自分の説明は適切とは言えませんでした。失礼しました!
投稿2017/07/03 14:36
編集2017/07/03 23:16総合スコア18404
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
どういう風に理解しているかが甚だ疑問ですが(書いた図からすると、微妙に勘違いしているようにみえる)、シフト演算はその名の通り、ビット位置をずらす演算です。
まず左シフトから説明しますか。左シフトはその名の通り、各ビットの値を上位ビット方向に移す演算です。移した結果、空いた最下位ビットには必ず「0」が入ります(質問者さんが書いた図だと、最上位ビットの値をここに移すかのように書いていますが、そんなことはしません。最下位ビットは「0」固定です)。
次に右シフト。こちらは各ビットを下位ビット方向にずらしますが、結果的に空いた最上位ビットには、最上位ビットの扱いによって埋められる値が変わってきます(まあ、早い話がsigned
かunsigned
かで変わります)。signed
つまり、符号として扱う場合、符号と同じ値が埋められます。つまり、「0」(=正数)であれば「0」が、「1」(=負数)であれば「1」が埋められます。一方、unsigned
つまり、符号として扱わない場合は固定で「0」が埋められます(質問者さんが書かれた図だと最下位ビットの値を最上位に移すかのように書かれていますが、決して最下位ビットの値を最上位ビットに移すということはしません)。
投稿2017/07/03 14:38
総合スコア1575
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
シフトして空いたところはゼロ埋めです。
逆に溢れたところは切り捨てられます。
赤の四角は間違いです。
投稿2017/07/03 14:25
総合スコア1392
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
ええっとまぁ、現実的なお話をしましょう。
C/C++ Shift演算原則1(でっち上げ)
Signedな整数型に対しShift演算原則を行ってはいけない。
理由: 未定義動作などに遭遇するから
まとめ
C/C++においてはUnsignedな整数型に対するShift演算のみ理解すればよい。使わないものは知らなくて良い。え?それでも知りたい?理解したい?それはコードが書きたいんじゃなくて規格書を読みたいんだな。よろしい、
C++er は“合法”だとか“違法”だとか言いたくて仕方がないけれど、結局どういう意味? それより適合・適格・○○動作・○○規則・診断不要いろいろの関係が謎
を読んでくるが良い。C++ 警察との戦いの始まりだ。
質問への回答
論理シフト は理解できました。
算術シフト の符号ビットが入るというのがまだ難しいです。
0111 LEFT-SHIFT
= 1110
これは、0が切り捨てられたから、新たに0を入れたわけではないという事ですか?
もし、
1000 LEFT-SHIFT
だったら、
=0001
という事ですか?
そもそも算術Shift、つまりはSignedな整数型に対しShift演算をしてはいけないので、知る必要がない。
質問文では4bitのSignedな整数型を仮定しているようだが(1byte = 4bitな処理系か?)、raccyさんが書いているとおりその場合未定義動作なので鼻から悪魔をだしても良い
あらためてshift演算子の覚えるべき挙動
raccyさんが書いているとおりでいいんだけどもう一度書いておく。
operator <<
cpp
1template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr> 2T lshift1(T a, T b) 3{ 4 return a << b; 5} 6 7template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr> 8T lshift2(T a, T b) 9{ 10 for(T i = 0; i < b; ++i) a *= 2; 11 return a; 12}
この2つの関数lshift1
/lshift2
は同じ結果を示します。
operator >>
cpp
1template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr> 2T rshift1(T a, T b) 3{ 4 return a >> b; 5} 6 7template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr> 8T rshift2(T a, T b) 9{ 10 for(T i = 0; i < b; ++i) a /= 2; 11 return a; 12}
この2つの関数rshift1
/rshift2
は同じ結果を示します。
C/C++以外の言語ではどうか
C/C++はもう何回も言ったとおり、算術シフトを使う機会はありませんがC#などでは使えます。
その場合の挙動ですが、上記のfor文で代替実装しているものと同じ挙動だと考えてください。
投稿2017/07/03 16:54
編集2017/07/03 16:55総合スコア5852
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。