けんつの煽られ駆動開発記

何か作るときは大抵誰かに煽られた時です。

java【数値】

まずは、数値の中で比較的扱う頻度の高い整数の話から

1.整数

数学の世界には正の数にも負の数にも無限大までありますが
プログラミングの世界には整数といえど限りがあります
そしてjavaには整数を扱う5つのデータ型が存在し、それぞれ範囲が設定されています

データ型 範囲
byte -128以上127以下
char 0以上65535以下
short -32768以上32767以下
int -2147483648以上2147483647以下
long -9223372036854775808以上9223372036854775807以下

2.ビット長と値の範囲

1.整数で整数を扱うデータ型の値の範囲を示しました
ですが、実際なんでこんな中途半端なのかと言われればそれはビットと関係があります

そのため、まず各データ型のビット長を示します

データ型 ビット長
byte 8
char 16
short 16
int 32
long 64

ビットとは2つの状態を取る自称を抽象化した時の単位のことで
2進数の世界で桁数に相当するものをビット長という

これらビット長がデータ型の値の範囲を決めていきます
実際どのように影響しているかというと、このビット長を超える整数を格納しようとすると桁あふれという現象が起こり
あふれた分を格納可能な下限に足した数になってしまい、大抵の場合これは負数になってしまうためバグなんかの原因になります

int max = Integer.MAX_VALUE;
System.out.println(max);//2147483647が出力
max++;
System.out.println(max);//-2147483648

しかし桁溢れはこのように最初は格納範囲内だったのに、処理をしていくうちに格納範囲を超えてしまった場合におきて
はじめから整数リテラルとして定義されているもので範囲外のものはコンパイルエラーになります

3.整数型の使い分け

実際ここまでデータ型を扱ってきて、5つある整数のデータ型をどう使い分けるか

char,byte型

これらはそれぞれ文字を扱う場合、byteを扱う場合に限定するべきというのが定説です
一応小さい整数値として使用できるが、上記の場合以外ではint型と実行効率が大差無い上に無理をして使うとint型より実行効率が悪くなってしまいます

short int long型

これら3つの場合は「どれでもいいならintを使う」が定説です
実際にはCPUが何bitかということで判断するべきらしいのですが現在では32bit,64bitともにint型が一番安定した実行効率をほこるという考えがあるようです
なのでlongは極力、intで格納しきれない数の時にのみ使うべきです
またshortを使う場面はほとんどなく現代のマシンスペックではこれを使うだけのメリットが無く無理に使うとchar,byte型と同様に性能の悪化を招く危険性があります

4.四則演算

整数を扱うにはなくてはならないのが四則演算
javaでは4つの算術演算の二項演算子があります

演算子 意味
+
-
/

これは実際の数学と同じでほとんど直感的に扱うことが出来ますがいくつかの注意点があります
・大きな数の和での桁あふれ
・絶対値の大きな負数での差の桁あふれ
・絶対値の大きな数同士の積
・あまりが切り捨てになる
・0による割り算が例外を発生させる点

これらに気をつければ問題なく扱うことが出来るでしょう

そして、上記の注意点の時にさらっと書いたのですが/演算子は商しか考えていなくあまりが出る場合は切り捨てられます
そこであまりを扱う剰余演算子の「%」があります
例えば奇数、偶数判定や「fizzbuzz」問題をとくときに使用できて

for(int i = 1; i <= 100; i++){
    if(i%2 == 0){//2であまり0の時つまり2で割り切れる、偶数の時
        System.out.println(i);
    }
}

このコードでは2で割ってあまり0の時、つまり2で割り切れるので偶数の時のみiを出力するというものです
%演算子はこのように使います

5.符号反転

  • を付けることで差を表すだけでなく符号反転も出来ます
int n = 10;
System.out.println(-n);//print -> -10

6.型変換

はじめの方に型と種類の違いについて説明しましたが
javaは静的型付けなので違う型の変数に代入するとコンパイルエラーになります
例えば下記の例

int i = 0;
String str = i;//これがコンパイルエラー

というわけで、小さい範囲の型の値をそれより大きい範囲の型には代入できるますが
縮小変換はコンパイルエラーになることがあります

しかし範囲内であれば、理論上格納可能です
それでも小さい型から大きい型の様に自動的に変換はされないので、強制的に変換する必要があります
またその強制的(明示的)変換をキャストといいます

int i = 0;
short i_s = i;//これはコンパイルエラー

int i = 0;
short i_s = (short)i;//これがキャスト、コンパイルエラーにはならない

このように縮小変換時に便利でも範囲を超えている数に対してキャストし格納しようとすると桁溢れのような
想定外の結果がでてしまうので注意が必要です

それと数値型同士でのキャストでは問題ありませんが、文字列やboolean型とはキャストしてもコンパイルエラーになります

7.浮動小数点数

整数の次は浮動小数点数の説明をします
まずjavaでは浮動小数点数を扱うためにfloat,doubleという2つのデータ型が用意されています

浮動小数点型 ビット長
float 32
double 64

浮動小数点数といっても、ざっくり言えば小数のことです
なので扱いも整数とあまり変わりませんが、リテラル表記には多少注意が必要です
・fまたはFで終わるならfloat、d,Dならdouble
・無表記ならdoubleになる
という点で多少の注意が必要です
また指数を指定するリテラル表記もあり

1.8e1 //1.8*10の1乗->18

といったように定義出来ます

8.範囲を超える数を扱う

整数で言うlong型の格納範囲を超える整数を格納、扱う方法はないように感じますが
java.math.BigIntegerクラスを使うことで、範囲外の大きな数も扱うことが出来ます

それと同様に整数ではなく浮動小数点数を扱うものはjava.math.BigDecimalクラスです

このあたりは紹介するとキリがないのでリファレンスを参照してください