整数と浮動小数点数

こんにちは、めのんんです!

前回までは前置きでした。
すごく長い前置きでしたけど、今回からは本格的にCを使ってプログラミングしていきますね。

Cの整数型と浮動小数点型

今回の内容は整数と浮動小数点数です。
PHPでも整数や浮動小数点数を扱うようにCでも大体同じように扱います。
ただ、CはPHPよりずっと型の種類が多いのでその点は大変かもしれません。
一応、どんな型があるのか紹介しますね。

  • _Bool
  • char
  • signed char
  • unsigned char
  • short
  • unsigned short
  • int
  • unsigned int
  • long
  • unsigned long
  • long long
  • unsigned long long

ここまでが「整数型」です。
正確には「標準整数型」というようです。

  • float
  • double
  • long double
  • float _Complex
  • double _Complex
  • long double _Complex
  • float _Imaginary
  • double _Imaginary
  • long double _Imaginary

はい、ここまでが「浮動小数点型」です。
このうちfloat、double、long doubleの3つは「実浮動小数点型」といいます。
PHPではfloatとdoubleは同じ型でしたがCでは別の型になります。
整数型と実浮動小数点型をあわせて「実数型」と呼ぶようです。

_Complexが付く3つの型は「複素数型」、_Imaginaryが付く3つの型は「虚数型」といいます。
_Complexも_Imaginaryもすべての処理系がサポートしているわけではありません。
GCCは_Complexはサポートしていますが_Imaginaryはサポートされていません。

int型とdouble型

たくさんの型があってすぐには覚えられそうにないですね。
一度にあまりたくさん詰め込むと消化不良を起こしますので、今回はたくさんある型の中からint型とdouble型だけを解説します。

int型

int型はたくさんあるCの整数型の中ではもっとも代表的なものです。
PHPの整数型の表現範囲は環境依存ですが、Cのint型もコンパイラに依存します。

Cの標準規格はこのようにコンパイラに依存するような仕様は「処理系定義」と呼ばれます。
「処理系」というのは大雑把にいってコンパイラと実行環境のことだと思ってください。

厳密なことをいうとすごく難しくなるので、ちょっと乱暴ですがここでは簡単な解説にとどめます。
どうしても厳密なことを知りたい型は、「1の補数表現」、「絶対値と符号ビット」、「詰め物ビット」、「トラップ表現」を検索して調べてみてくださいね。

GCCではint型の表現範囲は-2147483648から+2147483647になります。
PHPの32ビット環境の整数型もこの表現範囲ですね。
これより広い表現範囲の値を扱うには別の型を使う必要があります。

int型の定数はPHPと同じように書くことができます。
10進数は普通に書けばいいですし、8進数や16進数も使えます。
ただし、2進数はCの標準規格ではサポートされていないのですが、GCCは独自拡張として2進数をサポートしていますし、書き方もPHPと同じです。
書き方でちょっとだけ注意しないといけないのは、PHPではアンダースコアで桁を区切ることができましたが、Cではコンパイルエラーになります。

12345   // 10進数
012345  // 8進数
0x12345 // 16進数
0b11011 // 2進数(GCCの独自拡張)
12_345  // コンパイルエラー! Cではアンダースコアによる桁区切りはサポートされない。

double型

double型は浮動小数点型の中でもっとも代表的なものです。
PHPと同じく表現範囲や精度は環境依存です(そう、処理系定義ですね!)。

double型についても厳密なことをいうとすごく難しくなります。
int型同様、どうしても興味がある方は、「仮数部」、「指数部」、「浮動小数点数の基数」、「丸めモード」を検索してみてください。

GCCでは、double型の表現範囲は±1.79769313486232308になります。
この表現範囲は多くのPHPの浮動小数点型と同じだと思います。

double型の定数の書き方もPHPと同じです。
ただし、整数の場合と同じでアンダースコアによる桁区切りは使えませんので注意してくださいね。

ところで、Cでは浮動小数点数にも16進数で表現することができます。
16進数を使うときは整数の場合と同じで「0x」または「0X」で始めます。
指数部は「e」ではなく「p」で始め、10の累乗ではなく2の累常になります。
なお、16進数で浮動小数点数を表現する場合は「p」以降の指数部を省略することができません。

1.23      // これはそのまま1.23
1.23e5    // 1.23×10の5乗
0x7.ffp4  // 7.996094×2の4乗

数値の入出力方法

ここまででint型とdouble型について解説してきました。
せっかくなので、数値を出力したり入力したりしたいですよね。
ここからは標準出力に数値を書き出す方法、それから標準入力から数値を読み込む方法について解説します。

数値の出力

標準出力に数値を書き出すには「printf」関数を使います。
printf関数はPHPにもあるのでおなじみですね。
細かいことを抜きにすれば、int型やdouble型の数値を出力するだけならCのprintf関数はPHPのprintf関数と同じように使うことができます。
残念ながら「%b」はサポートしていません。

int i = 12345;
printf("%d", i);    // 「12345」が出力されます。
printf("%x", i);    // 「3039」が出力されます。
printf("%o", i);    // 「30071」が出力されます。

double x = 1.234e5;
printf("%e", x);    // 「1.234000e+05」が出力されます。
printf("%f", x);    // 「123400.000000」が出力されます。
printf("%g", x);    // 「123400」が出力されます。
printf("%a", x);    // 「0xf.104p+13」が出力されます。

使うことはあまりないと思いますけど、浮動小数点数を16進数で出力するには「%a」または「%A」を使います。
「%a」と「%A」の違いは、「%x」と「%X」の違いのようなものだと考えてください。

ところで上の例を見れば気付かれたかもしれませんが、PHPと違ってCでは変数(正確にはオブジェクトでしたね!)を使うときに「$」は付けません。

数値の入力

標準入力からの数値の読み込みには「scanf」関数を使います。
PHPにはsscanf関数というのがあると思いますが、それと似たようなもので、文字列から数値を取り出すのではなく標準入力から数値を取り出します(ちなみにCにもsscanf関数があります)。

scanf関数も細かいことを気にしなければ大体PHPのsscanf関数と同じように使うことができますが、2点注意しないと行けないことがあります。

1つは、数値を格納する変数には前に「&」を付ける必要があります。
詳しいことは別の機会に解説しますが、ここではとりあえずそういうものだと覚えておいてください。
PHPでもオブジェクトの参照では「&」を付けますが、それと同じような意味だと思ってください。

2つめは、double型の数値を読み込みときには「%lf」や「%le」のように「l(エル)」を付ける必要があることです。
この「l」はprintf関数でdouble型の数値を出力する場合には必要ありません(「l」を付けてもかまいません)。

int i;
scanf("%d", &i);     // 10進数として整数値を読み込む。
scanf("%x", &i);     // 16進数として整数値を読み込む。scanf("%o", &i);     // o進数として整数値を読み込む。
scanf("%i", &i);     // 基数を検出して整数値を読み込む。

double x;
scanf("%lf", &x);    // 10進数として浮動小数点数を読み込む。
scanf("%la", &x);    // 16進数として浮動小数点数を読み込む。

printf関数同様、「%a」を使えば16進数で読み込むことができます(あまり使う機会はないでしょうけど)。

scanf関数はいろいろ扱いが難しいところもあるのですが、ちょっと動作を確認したいときなどに使うには便利な関数です。
print関数もscanf関数も、詳細については別の機会に解説できたらと考えています。

具体的なプログラム例

それでは、ここまで解説した内容を使って具体的なプログラムを書いてみましょう。

#include <stdio.h>

int main(void)
{
  double x;
  double y;

  puts("Input 2 numbers.");
  scanf("%lf%lf", &x, &y);               // 数値を2つ入力する。
  printf("%g + %g = %g\n", x, y, x + y); // 読み込んだ数値の合計を出力する。
  return 0;
}

本当はまだ加算演算子を解説していないんですが使っちゃいました。
見れば何をやっているのか理解できますよね?

printf関数もscanf関数も使うためには「stdio.h」を#includeで取り込む必要があります。
puts関数もそうでしたね。

以上で今回の解説を終わります。
入出力ができるようになれば、一気にできることが広がりますね。

次回は配列について解説しようと思います。
どうぞご期待ください!