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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

Q&A

解決済

5回答

4680閲覧

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

re97

総合スコア208

JavaScript

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

0グッド

0クリップ

投稿2016/05/01 03:16

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

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

javascript

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

リンク

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

>・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/02 06:36

HiroshiWatanabe

総合スコア2160

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2016/05/03 01:40 編集

回答ありがとうございました >256(0x100)は0x10000になっていて(1回目の8bit左シフト) ・ここが分からないのですが、これはどうやって導き出すのでしょうか? ・下記やり方で変換しているのでしょうか? ・それとも、何か簡単に導き出すことができるのでしょうか? ・256を2進数変換すると、100000000 ・8bit左シフトすると、10000000000000000 ・16bitへ再変換すると、10000 ・だから、0x10000? ・それとも、16進数のまま8bit左シフトすることが出来るのでしょうか?
HiroshiWatanabe

2016/05/03 03: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範囲に相当する
re97

2016/05/04 02:28

コメント&長文解説いただき、ありがとうございました >16進数の値をそのまま8bit左シフトして結果を求める事はできますよ ・初めて知りました ・「左シフト」は2進数で行うものだと思っていたのですが、根本的に勘違いしていたことに気がつきました ・大変参考になりました
guest

0

桁落ちの問題

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

JavaScript

1'use strict'; 2function toColorCode (r, g, b) { 3 return '#' + ((r << 16) + (g << 8) + b).toString(16); 4} 5 6console.log(toColorCode(255, 255, 255)); // "ffffff" 7console.log(toColorCode(0, 0, 128)); // "#80"

桁落ちの回避策

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

JavaScript

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

N進数

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

JavaScript

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

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

JavaScript

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

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

別解コード

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

JavaScript

1'use strict'; 2function toColorCode (r, g, b) { 3 return '#' + (0x1000000 + (r << 16) + (g << 8) + b).toString(16).slice(1); 4} 5 6console.log(toColorCode(255, 255, 255)); // "ffffff" 7console.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/02 02:17

編集2016/05/03 02:55
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2016/05/03 01:26

回答ありがとうございました >256 を加算すると9bit目に1を置く事になります ・ここが分からないのですが、これはどうやって導き出すのでしょうか? ・下記やり方で変換しているのでしょうか? ・それとも、何か簡単に導き出すことができるのでしょうか? ・256を2進数変換すると、100000000 ・だから「256 を加算すると9bit目に1を置く事になる」ということ?
think49

2016/05/03 02:58

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

2016/05/04 02:34

・コメント&親記事修正、ありがとうございました ・ロジックを理解した後は、JavaScriptコードで試していく予定なので、提示いただいた内容を参考にさせていただきます
guest

0

演算子の優先順位を考慮してビットシフトよりも先に足し算が行われるので
(((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/01 03:45

TaroToyotomi

総合スコア1430

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2016/05/02 01:26

・回答ありがとうございました ・内容難しかったです >256+r==>0x100+0x01=0x101 ・この式の意味が分かりませんでした
swordone

2016/05/02 01:42

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

2016/05/02 18:30

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

2016/05/03 01:20

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

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/03 01:55

miu_ras

総合スコア902

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2016/05/04 02:44

・回答ありがとうございました >ビット演算とか2進数とか16進数とかあまり関係ありません。ただ単に桁数を合わせたいだけです。 >10進数で考えてもいいです ・参考になりました ・何となくそうなのかな、と思っていたのですが、文で明示していただいたので分かりやすかったです ・考えがすっきりしました >もしかするとこっちが分からなかった? ・はい ・256 + の意味が分かりませんでした ※左シフト(2進数でしか出来ないと思っていました)
guest

0

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

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

投稿2016/05/01 03:42

yoshi777

総合スコア674

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

re97

2016/05/02 01:24

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

2016/05/02 01:30

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

2016/05/03 01:19

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問