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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

1279閲覧

「符号あり符号なし〇〇bitの整数」という意味について

SweetSugar

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

2クリップ

投稿2018/02/06 13:43

皆さんいつもお世話になっております。
SweetSugarと申します。

本日は「符号あり」「符号なし」の意味についてお聞きしたいことがあります。
また、本文はJavaであることを前提として書いてあります。説明の不十分な点がございましたら申し訳ございません。

まず初めに、例えばbyte型の場合は表現できる値の範囲として**「-128〜127」であるかと思います。
私はこれを「符号あり」と理解しています。
よって「符号なし」とは「符号あり」のマイナスの範囲を無くし正の範囲をその分増やした
「0〜255」**であると理解しています。
この考え方は正しいのでしょうか。仮に正しいとした場合、符号ありなしの必要性についても伺いたく思います。

次に実際のコードを作成する場合、例えば**「 ストリームから次の2byte分のバイナリデータを”符号なしの16bit長の2進数”として取得しなさい 」と指示があった場合にそれは「 DataInputStream#readUnsignedShort() 」**を使用して取得したint型の返り値が目的のものという事になるのでしょうか。

現在、符号なしやありの意味そしてバイナリデータ取得の方法などについてイメージをはっきりとつかめておりません。

お忙しいと事申し訳ございませんがご教授いただけると幸いです。
よろしくお願いいたします。

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

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

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

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

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

guest

回答3

0

解釈の通りで正しいです。

二進値では数字を0と1のみで表現するので負数をどうするかといった課題があります。たとえば―1は8ビットの符号付二進数で11111111と表現されます。もちろん、これは符号無二進数としても意味のあるものであり、この場合は255という数字になります。

つまり、同一のビット列であっても符号付で解釈するか符号無で解釈するかによって異なる値となります。ですので二進値の変換の際にはどちらの方法を使うかを決めておく必要があります。

ちなみに、負数の表現には「二の補数」というルールを用いることが一般的です。このルールでは、最上位ビットが1である場合を負数と定め、この絶対値は「当該ビット列のビット反転に1を加えた値」となります。例えば「11111111」の絶対値は、ビット反転して「00000000」に1を加えて「1」となります。

このルールですと、負数と非負数の加減算を自然に定義できます。また、ビット拡張もしやすいです。非負数の場合は上位ビットを0で埋めるだけで拡張でき、負数の場合は上位ビットを1で埋めるだけで拡張できます。(言い換えれば最上位ビットをそのまま上の桁に追加するだけで良い)

投稿2018/02/07 11:48

HogeAnimalLover

総合スコア4830

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

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

SweetSugar

2018/02/07 15:34

HogeAnimalLoverさん ご返信ありがとうございました。 また、昨日中にご回答頂いたにも関わらずご返信が遅くなってしまい申し訳ございません。 符号なしかありかを指定する必要性に先頭bitを符号を意味するbitなのかどうかを判定する意味もあるという事でした。 計算時に引き算の概念を使うよりも、負数を足すという方法のほうがコンピュータの内部的に都合が良いということを思い出しました。 貴重なご意見ありがとうございました。 今後ともよろしくお願いいたします。
guest

0

  1. 符号無しと符号有りの考え方について

 それで正しいです。
必要性という点で言えば、符号あり、そして2の補数について学んでいただくのがいいかと思います。
上手い具合に符号ありに拡張できているのです。

  1. ストリームからの読み込み

 ストリーム上のデータは、本質的にはバイトデータの羅列です。ですから、「ここからの2バイトは整数として読む」「ここからの10バイトは文字列として読む」といったように、どう解釈するかはプログラム側で指定してやらねばなりません。データに型の属性が含まれているわけではないからです。
※プロトコルという形で、「この位置のデータが1なら、その後の2バイトを読んで……」という手順を決めることはできますが、その場合でもバイト列を解釈しながら読んでいるのは変わりありません

なお、2バイト以上のデータを数値として読む場合、注意が必要になります。実行している環境、そしてデータを作った環境によって、複数バイトからなる整数の場合、どちらが上位バイトになるかが異なってくるからです。
データとして 0x0123(10進数で291)というデータだとして、

  • インテル系列の場合  23 01
  • モトローラ系列の場合 01 23

と、順番が逆転します。(インテル系の並び方を「リトルエンディアン」、モトローラ系を「ビッグエンディアン」と呼びます)
※CPU によってはどっちで動くか変えられるようなものもある

投稿2018/02/06 14:30

tacsheaven

総合スコア13703

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

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

SweetSugar

2018/02/07 15:15

tacsheavenさん ご返信ありがとうございました。 また、昨日中にご回答頂いたにも関わらずご返信が遅くなってしまい申し訳ございません。 ストリームからバイトデータを取得する場合についても、基本的にはどのようにすべきかを理解できました。 一つエンディアンについて伺いたいことがあります。 ネットで調べたある記事には「javaはビックエンディアンがデフォルト」とありました。 つまり「インテル系列から2byte以上の読み込みを行う時はリトルエンディアンにバイトオーダを指定すべきであり、モトローラ系列であればバイトオーダを明示的に行わなくても良い」と考えても問題ないのでしょうか。また、インテル系列やモトローラ系列は単純にCPUの種類についての事なのでしょうか。 立て続けの質問となり申し訳ございませんが、ご返信いただけると幸いです。 よろしくお願いいたします。
tacsheaven

2018/02/10 04:38

JavaはJavaバイトコードという中間コードを利用して動いています。なので実際に動いている環境のCPUに関係なく、ビッグエンディアンで動作するようになっています。 問題になるのはインテル系CPUで使うことを想定されたバイナリデータを読み書きする場合です。その場合、エンディアンが違うことを意識して、「読み書きする前後で並び順を交換する」必要が出てきます。 ※下手にバイトオーダを指定して挙動を変えてしまうと大変なので、読み書きするデータを加工する方向で対応する また、このエンディアン問題はバイナリデータだけではなく、通常のテキストでも起こりえます。UTF-16などにはこれへの対処のため、「エンディアン判定するためのマーク(Byte Order Mark)」があります。 インテル系・モトローラ系というのは、その通りでCPUの種類……というか、設計した会社です。インテル系はいうまでもなく x86 と称される現在のパソコンCPUの標準。モトローラは現在は PowerPC など組み込み系の分野で使われていたりします。他には組み込み系やら携帯、ゲーム機でも多い ARM なんてのもありますが。
SweetSugar

2018/02/11 10:10

tacsheavenさん SweetSugarです。 返信が遅くなってしまい申し訳ございません。 javaがビッグエンディアンである理由がjavaの特性ゆえであると理解できました。 また、インテル系・モトローラ系についても具体的にご教授いただきありがとうございます。 byteオーダーに関する知識は書籍などを読んでもイメージがつきにくく、そうゆうものであるとしていましたがtacsheavenさんのご回答で何が起きているのかを少し理解できたかと思います。 重ね重ねの質問にも親切にご対応していただき、誠にありがとうございました。 今後ともよろしくお願いいたします。
guest

0

ベストアンサー

考え方は合っていますよ。
(2進数)「1111 1111」= (16進数)0xFF = (符号無し10進数)255 or (符号有り10進数)-128

2進数は1繰り上がる毎に2^n乗になるので、符号無し10進数にすると、
「1111 1111」は「(128+64+32+16) + (8+4+2+1)」= 255。

この先頭bitをプラス128かマイナス128か、符号として利用しているのが符号有りです。
上の式の128がマイナス128になるので、-128~127を表現することになります。

符号の有無の必要性については、そのまま計算結果でマイナスになる数字の必要性があるかってことになります。
全ての計算結果がプラスで表せる訳ではありません。
例えば符号無しで「1-2」を計算すると-1は表現出来ません。範囲外の数字なので255とするか、エラーになります。
だからといって全ての型を符号有りの大きい型にすると、無駄に重たいデータになります。
使う値を必要に応じて最低限使うことが大事です。

2Byte取得は、bit演算の計算式にするとイメージしやすいです。
「readUnsignedShort」は、 ((byte[1] & 0xff) << 8) + (byte[0] & 0xff) 
と同じです。

詳しくは「bit演算」で検索すると良いです。
JavaはByte型が符号有りしか無い上、
bit演算の右シフトが符号有りシフト「>>」と符号無しシフト「>>>」と2種類あるので、
使う時に混乱するかもしれませんが、
2進数の原理を理解せずにバイナリデータを扱うと、
予想外の計算結果になっても原因がわからないままになってしまいます。

投稿2018/02/06 14:48

Wind

総合スコア442

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

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

SweetSugar

2018/02/07 15:28

Windさん ご返信ありがとうございました。 また、昨日中にご回答頂いたにも関わらずご返信が遅くなってしまい申し訳ございません。 シフト演算の知識を使うと理解の助けになるとのことでした。 もう一度シフト演算の項目を読み直して考察したいと思います。 一つ質問がございます。 例えば、「16bit長の符号なし2進整数でストリームからデータを取得する」場合に数字として出力を行う場合は、特に指定が無い限り「10進数で表示する」と考えても良いのでしょうか。 非常に抽象的な聞き方で申し訳ございませんが、質問の意図としては「取得したバイナリデータを数字として人が理解しようとする」場合に皆さんはその数字が何進数であるかを前提として理解しようとするのかを伺いたいという事であります。 立て続けの質問となり申し訳ございませんが、ご返信いただけると幸いです。 よろしくお願いいたします。
Wind

2018/02/07 16:16

数値の表示については、バイナリデータを見る人がどう理解したいか、によりますね。 通常のアプリでデータから取得した値を見せる時は10進数が良いです。 例えば温度や時間を16進数で表示されても見難いだけですし。 bit演算などを行う時は、どのbitを立てているかが解る様に16進数が良いです。 例えば私や他の方の回答を読んで頂ければわかりますが、説明で16進数の値を記述し、値が16進数と明記する為に「0x」を付けています。 これはバイナリデータをPC的に理解するには16進数の方が見易いからです。
SweetSugar

2018/02/08 15:40

Windさん お返事ありがとうございます。 進数表記についての具体的な例を上げていただきありがとうございます。 Windさんのご回答で進数表記に対するイメージがつきました。 今の理解をコードに反映して試して見たいと思います。 重ね重ねの質問にも親切にご対応していただき、誠にありがとうございました。 今後ともよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問