質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • JavaScript

    16903questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

ビット演算で桁数を合わせるために256を足しているのはなぜ?

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 1,675

re97

score 195

下記リンク先で、桁を合わせるため、(r << 8)を(256 + r << 8)へ変更しているのですが、
・256を足すと、どうして2進数『1000000000000000000000000』を足したことになるのでしょうか?

2進数で表すところの『1000000000000000000000000』、10進数で『16777216』、16進数で『1000000』を足すことによって一時的に桁を合わせ

function toColorCode_1a(r,g,b){
  return (((256 + r << 8) + g << 8) + b).toString(16).replace(/^1/,'#');
}


リンク

・1バイトが256だから?
・11111111?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+1

>・256を足すと、どうして2進数『1000000000000000000000000』を足したことになるのでしょうか?

256を足したから1000000000000000000000000を足したことになっているのではなく
この256はr<<8とg<<8の8bit左シフト2回によって0x100 が 0x1000000 になっています。
256 + r << 8 の部分で256(0x100)は0x10000になっていて(1回目の8bit左シフト)
次の「(その演算結果+g)<<8」によって最初の256だった物はさらに8bit左にシフトされるため
結果として最初の256(16進の0x100)は最終的に0x1000000になっているという事です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 10:30 編集

    回答ありがとうございました

    >256(0x100)は0x10000になっていて(1回目の8bit左シフト)
    ・ここが分からないのですが、これはどうやって導き出すのでしょうか?
    ・下記やり方で変換しているのでしょうか?
    ・それとも、何か簡単に導き出すことができるのでしょうか?

    ・256を2進数変換すると、100000000
    ・8bit左シフトすると、10000000000000000
    ・16bitへ再変換すると、10000
    ・だから、0x10000?

    ・それとも、16進数のまま8bit左シフトすることが出来るのでしょうか?

    キャンセル

  • 2016/05/03 12:09

    >>256(0x100)は0x10000になっていて(1回目の8bit左シフト)
    >・ここが分からないのですが、これはどうやって導き出すのでしょうか?
    (中略)
    >・それとも、16進数のまま8bit左シフトすることが出来るのでしょうか?

    16進数の値をそのまま8bit左シフトして結果を求める事はできますよ。
    …うまく説明できるかわかりませんが…
    256は16進数で0x100です。
    これを8bit左にシフトすれば0x10000です。
    「8bit左にシフトする」のは「16進数の右端に00を付加する」のと同じです。
    なので0x100の右に00を付加して0x10000とすれば0x100を左に8bitシフトした結果になります。
    16進数の1桁は10進数で言う所の0~15の16種類の値で1桁が構成されています。
    (ただし10~15の範囲は10進のそれのままだと見た目が2桁になってしまうのでそれをA~Fに割り当てて1桁表現しています)
    16種類の値で1桁が構成されそれを超えると桁があがる…から16進数です。
    同様に2進数は0~1の2種類の値で1桁が構成されそれを超えると桁が上がるから2進数。
    10進数は0~9の10種類の値で1桁(以下同様なので省略)。
    2進数で1桁あがる(桁上りする)状況ですが、1桁が0~1の2つの値の範囲で構成されているので
    1桁あがる(左にシフトする)という事は2倍されているというのと同じです。
    (10進数でも1桁あがるのは10倍ですよね?)
    2進数の0001は10進数の1
    2進数の0010は10進数の2(上の1を2倍したのと同じ)
    2進数の0100は10進数の4(上の2を2倍したのと同じ)
    2進数の1000は10進数の8(上の4を2倍したのと同じ)
    ちなみに多くのプログラマーはこの1,2,4,8,16,32,64,128,256,512,1024,2048,4096...と65536程度までは九九のように覚えていると思います。
    この理屈を16進数でも考えてみてください。
    16進数は1桁で0~Fの16種類の値で構成されていて、1桁あがるのは16倍です。
    2桁あがるのは16倍してさらに16倍ですから16x16=256ですね。
    「8bitシフトする」というのは「256倍する」という事と同じ事で、これはちょうど16進数で2桁の桁上りと同じです。
    8bitシフトするのが何故256倍と同じなのかは上の2進数の桁上り(左シフト1回)が2倍に相当するからです。
    1回の左シフトで2倍
    2回なら4倍
    3回なら8倍
    4回なら16倍
    5回なら32倍
    6回なら64倍
    7回なら128倍
    8回なら256倍
    になりますね?
    なので
    ・256を8bit左にシフトする
    ↓(同じ意味)
    ・256を256倍する
    であり
    ・10進数の256は16進数の0x100
    ・16進数で256倍するのは右に00を付加するのと同じ
    ・0x100を256倍した結果は0x10000
    となります。

    ついでなのでn進数についてもう少し。
    2進数の単位(桁)をビット(bit)と呼んでいますが1桁目をbit0,2桁目をbit1,3桁目はbit2...と呼びます。
    例えば 0001 という2進数は右端の1はbit0が1の状態、その左にある0はbit1が0の状態です。
    2進数は 2^n という式で値を表せます。(2のn乗)
    bit0 は 2^0 なので 1
    bit1 は 2^1 なので 2
    bit2 は 2^2 なので 4
    bit3 は 2^3 なので 8
    bit4 は 2^4 なので 16
    10進数でも同様に 10^n で考えられます。
    1桁目は 10^0 なので 1
    2桁目は 10^1 なので 10
    3桁目は 10^2 なので 100
    4桁目は 10^3 なので 1000
    5桁目は 10^4 なので 10000
    16進数では
    16^0 = 1 (0x0001)
    16^1 = 16 (0x0010)
    16^2 = 256 (0x0100)
    16^3 = 4096 (0x1000)
    16^4 = 8192 (0x10000)

    (覚えておくと計算思考の一部を省略できるよくありがちで今回のケースに当てはまる基準)
    ・左シフト1回は値を2倍する事に相当する
    ・8bit左シフトは16進数で右端に00を付加する事に相当する
    ・16進数の1桁は4ビット(0~15の値範囲)に相当し2桁で0~255の256範囲に相当する

    キャンセル

  • 2016/05/04 11:28

    コメント&長文解説いただき、ありがとうございました

    >16進数の値をそのまま8bit左シフトして結果を求める事はできますよ
    ・初めて知りました

    ・「左シフト」は2進数で行うものだと思っていたのですが、根本的に勘違いしていたことに気がつきました
    ・大変参考になりました

    キャンセル

+1

演算子の優先順位を考慮してビットシフトよりも先に足し算が行われるので
(((256 + r << 8) + g << 8) + b)
の計算の順番は16進数で考えて以下の通りになると思います。(例えば、r=1,b=2,g=0x80とすると)
256+r==>0x100+0x01=0x101
(256+r)<<8==>0x101<<8=0x10100
((256+r)<<8)+g==>0x10100+0x02=0x10102
((256+r)<<8)+g<<8==>0x10102<<8=0x1010200
(((256+r)<<8)+g<<8)+b==>0x1010200+0x80=0x1010280
最上位ビットの'1'を#に置換して
"#010280"
になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/02 10:26

    ・回答ありがとうございました
    ・内容難しかったです

    >256+r==>0x100+0x01=0x101
    ・この式の意味が分かりませんでした

    キャンセル

  • 2016/05/02 10:42

    横から失礼。
    単純な足し算を16進数で表現しています。
    256は0x100(先頭の0xは、あとに続く数字が16進数であることを意味する)で、それにr、今回の場合は1を加算しています。

    キャンセル

  • 2016/05/03 03:30

    2進数だと桁数が大きくなりすぎて計算が面倒なので16進数で表現したのですが、わかりにくかったようですね。
    プログラム言語で扱う演算子は演算の優先順位が決まっていますのでそこらへんから勉強するのが良いかと思います。
    算数でも+やーよりも×や÷を先に計算するとか、かっこの中を先に計算するとか決まりがありましたよね?

    キャンセル

  • 2016/05/03 10:20

    ・コメントありがとうございました

    キャンセル

+1

 桁落ちの問題

単純に考えれば赤を16ビットシフト、緑を8ビットシフトすればいいですが、それでは赤が 0 の場合に桁落ちが発生してしまいます。

'use strict';
function toColorCode (r, g, b) {
  return '#' + ((r << 16) + (g << 8) + b).toString(16);
}

console.log(toColorCode(255, 255, 255));  // "ffffff"
console.log(toColorCode(0, 0, 128));      // "#80"

 桁落ちの回避策

桁落ちを回避するために 0x000080 を 0x1000080 のように変換している(一つ上の桁に 1 を置く)のでしょう。
256 を加算すると9bit目に1を置く事になります。
10進数で例えるなら「9 + 100 = 109」で2桁目をゼロパディングしているようなものですね。

var r = 15;
console.log(r.toString(16));             // "f"
console.log((256 + r).toString(16));    // "10f"
console.log((0x100 + r).toString(16));  // "10f"

 N進数

Nを基数とするN進数には各桁となる数字に明確な計算法があります。
10進数で例えるなら、148 は次のように分解する事が出来ます。

console.log(Math.pow(10, 0) * 8); // 8   … 1桁目は 10^0*8 (10の0乗の8倍)
console.log(Math.pow(10, 1) * 4); // 40  … 2桁目は 10^1*4 (10の1乗の4倍)
console.log(Math.pow(10, 2 * 1)); // 100 … 3桁目は 10^2*1 (10の2乗の1倍)
console.log(Math.pow(10, 2) * 1 + Math.pow(10, 1) * 4 + Math.pow(10, 0) * 8); // 148

同じ事を16進数で考えればこうなります。

console.log((Math.pow(16, 2) * 1).toString(16)); // 100   … 3桁目は 16^2*1 (16の2乗の1倍)
console.log((Math.pow(16, 2) * 1));              // 256   … 10進数なら 256

従って、256 を加算するという事は16進数でいうところの「0x100 (16進数表記)」を加算する事と同義です。
0x100 (16進数表記)」は2進数に換算すると「0b100000000 (2進数表記)」になります。
0b100000000 (2進数表記)」は9bit目に1がある数字です。
2進数についてはご自身で計算(検証)してみてください。

 別解コード

私なら次のようにコードを書きます。

'use strict';
function toColorCode (r, g, b) {
  return '#' + (0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

console.log(toColorCode(255, 255, 255));  // "ffffff"
console.log(toColorCode(0, 0, 128));      // "#000080"

ゼロパディングについては文字列処理をしてもいいので他の方法もあるとは思います。

 更新履歴

  • 2016/05/02 11:24 256加算のロジックの説明追加
  • 2016/05/02 11:59 256加算のロジックの説明が誤っていたので修正
  • 2016/05/03 11:55 N進数の説明追加

Re: re97 さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/03 10:26

    回答ありがとうございました

    >256 を加算すると9bit目に1を置く事になります
    ・ここが分からないのですが、これはどうやって導き出すのでしょうか?
    ・下記やり方で変換しているのでしょうか?
    ・それとも、何か簡単に導き出すことができるのでしょうか?

    ・256を2進数変換すると、100000000
    ・だから「256 を加算すると9bit目に1を置く事になる」ということ?

    キャンセル

  • 2016/05/03 11:58

    N進数の各桁がどのような計算で導き出されるものなのか、の理解が必要な印象を持ちました。
    親記事を修正しました(N進数の説明追加)。
    基礎的なところで躓いている事が多い印象ですので「自分が何を知っているのか」「何を知らないのか」を踏まえ、未知と既知の境界を導き出して質問するとより理解が進むと思います。
    疑問を持つのはプログラマに必要な素晴らしい素質だと思いますので、是非頑張って下さい。

    キャンセル

  • 2016/05/04 11:34

    ・コメント&親記事修正、ありがとうございました

    ・ロジックを理解した後は、JavaScriptコードで試していく予定なので、提示いただいた内容を参考にさせていただきます

    キャンセル

0

256 は16進で 100 です。
式で8ビット左シフトを2回していますので、
1000000 になります。
これがリンク先の説明 の
「16進数で『1000000』を足すことによって」
になります。

補足
(256 + r << 8) は演算子の優先度から
256 + r の結果を 8 ビット左シフトです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/02 10:24

    ・回答ありがとうございました
    ・内容難しかったです

    >式で8ビット左シフトを2回していますので、1000000 になります
    ・(256 + r << 8)で8ビット左シフトを2回?
    ・8ビット左シフト1回で「00000000」を右に入れるということではないのでしょうか?

    キャンセル

  • 2016/05/02 10:30

    式というのは
    (256 + r << 8) + g << 8)
    のことで (256 + r << 8) の部分で1回目の 8 ビットシフト、
    (256 + r << 8) + g に対する 8 ビットシフトで2回目のシフトをしています。

    キャンセル

  • 2016/05/03 10:19

    ・コメントありがとうございました

    キャンセル

0

ビット演算とか2進数とか16進数とかあまり関係ありません。ただ単に桁数を合わせたいだけです。
10進数で考えてもいいです。

9999以下の数値がいろいろあったとします。
1
12
888
2345

これを4ケタ未満だった場合に4ケタになるように0を付けたい。そういう話です。つまり
0001
0012
0888
2345
にしたいと。

そのために1万を足して
10001
10012
10888
12345
にして、先頭の1をとれば目的に文字列になるよねという話です。

初心者の方には逆にわかりにくくなっているかもしれませんが、こちらの方がシンプルですよね。

あと念のため

 (((256 + r << 8) + g << 8) + b)

256 << 16
r << 16
g << 8
b
の4つの値を足したのと同じです。もしかするとこっちが分からなかった?

ちなみに
(256 << 16).toString(16)
は1000000です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/04 11:44

    ・回答ありがとうございました

    >ビット演算とか2進数とか16進数とかあまり関係ありません。ただ単に桁数を合わせたいだけです。
    >10進数で考えてもいいです
    ・参考になりました
    ・何となくそうなのかな、と思っていたのですが、文で明示していただいたので分かりやすかったです
    ・考えがすっきりしました

    >もしかするとこっちが分からなかった?
    ・はい
    ・256 + の意味が分かりませんでした
    ※左シフト(2進数でしか出来ないと思っていました)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    16903questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。