一週間で身につくC言語の基本

おさえておきたいプログラミングの基本

【応用編:1日目】 C言語と数値に関する処理

ここからはいよいよC言語の応用編です。

1-1.数値処理

C言語には数値ならびに数学を扱うために必要な処理が多数存在します。実用的なプログラムを作る上でこれらは欠かせません。そこで応用編の第一歩として数値・数学に関する処理および関数、更には注意点などについて説明していきます。

(1) 乱数

乱数とはでたらめな数のことです。ゲームなどでさいころを振ったり、カードをシャッフルするなどといった処理を行うには乱数の処理が欠かせません。ここでは、C言語で乱数を扱う方法を紹介していきます。

listex1-1:main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
                                
int main(int argc,char** argv){
    int a,b;
    // 乱数の初期化
    srand((unsigned) time(NULL));
    //	1から10までの乱数を発生させる
    a = rand() % 10 + 1;
    b = rand() % 10 + 1;
    //	計算結果を出力
    printf("%d + %d = %d\n",a,b,a+b);
    return 0;
}
実行結果(実行する度に変化する)
7 + 5 = 12

(2) 乱数関連の関数

このプログラムの特徴は、実行するたびに結果が変わることです。それは10行目、11行目で変数a,bに値を代入する際に使用するrand()関数に理由があります。まずは、このプログラムで用いられている関数を紹介しましょう。(表1-1)

表1-1.乱数に関する関数
関数書式意味使用例
srand()srand(unsigned seed);randで発生させる乱数の系列を変更。srand((unsigned) time(NULL));
rand()rand()0~RAND_MAX の間の疑似乱数を返す。
(RAND_MAXは処理系依存)
rand() % 10 + 1;

(3) time関数

これだけを見るとsrand()を使用する意味がよくわからないと思います。実はC言語で発生させる乱数は擬似的なもので、この処理を行わないと何度も同じパターンの乱数が発生してしまいます。

そこで、srand()関数を用いて変数を初期化するのですが、この時引数が同じでは、やはり同じパターンの数値しか出ません。そこで引数として、秒単位で現在時刻を返すtime()関数を用い、実行するごとに違う系列の乱数が出現するようにしているわけです。

表1-2.time関数
関数書式意味使用例
time()time_t time(time_t *timer);1970年1月1日の00:00:00 から現在までの
経過時間を秒単位で取得する。
time(NULL);

なお、rand()関数、srand()関数を利用するにはstdlib.hを、time()関数を利用するには、time.hをインクルードする必要があります。

(4) 乱数の範囲を指定する

では、プログラムの中身を紹介していきましょう。まず、8行目で乱数を初期化しています。次に、10,11行目で乱数を発生させていますが、 通常、rand()関数は、0からRAND_MAXという非常に大きな値を発生させます。そのため、1から10の乱数を発生させるにはまず%10をします。

これは10で割った余りという意味なので、乱数は0から9の範囲に限定されますから、それに1を足せば、1から10の値を得ることが出来るのです。(図1-1)

図1-1.1から10までの乱数を発生させる原理
1から10までの乱数を発生させる原理

考え方としては難しいですが、以下の方法を覚えておくと、非常に便利でしょう。

1からnまでの乱数をえる方法
rand() % n + 1
0からnまでの乱数をえる方法
rand() % (n + 1)

1-2.数学関数

C言語には、沢山の数値計算用の関数が用意されています。それらは非常にたくさんあり、全てをここで紹介することはできませんが、比較的使用頻度の高いものをここでいくつか紹介していきましょう。

(1) 三角関数

まずは、三角関数を使ったサンプルを見てみましょう。

listex1-2:main.c
#include <stdio.h>
#include <math.h>

#define PI 3.14
                                
int main(int argc,char** argv){
    int angle;
    double rad;
    printf("角度を入力してください(0~360):");
    scanf("%d",&angle);
    //  角度をラジアンに変換
    rad = PI * (double)angle / 180.0;
    //  三角関数での計算
    printf("sin(%d)=%f\n",angle,sin(rad));
    printf("cos(%d)=%f\n",angle,cos(rad));
    printf("tan(%d)=%f\n",angle,tan(rad));
    return 0;
}
実行結果(キーボードから角度を入力しEnterキーを押す)
角度を入力してください(0~360):45 ← キーボードから数値を入力しEnterキーを押す。 sin(45)=0.706825 cos(45)=0.707388 tan(45)=0.999204

sincostanは、その綴りのとおり、ずばりサインコサインタンジェントを意味します。つまり、数学でいうところの三角関数です。なお、これらはすべて、math.hに含まれています。(表1-3.参照)

表1-3.三角関数
関数書式意味使用例
tan()tan(double rad);()に指定したラジアンを入れるとタンジェントが得られる。doube a = tan(2*3.14);
sin()sin(double rad);()に指定したラジアンを入れるとサインが得られる。doube a = sin(2*3.14);
cos()cos(double rad);()に指定したラジアンを入れるとコサインが得られる。doube a = cos(2*3.14);

(2) ラジアン

C言語の三角関数の引数として与えるのは角度ではなくラジアンだという点に注意してください。通常、角度を0度から360度までで測るやり方を、度数法(どすうほう)と言いますが、これに対し、ラジアンで角度を指定する方法を弧度法(こどほう)と言います。

ラジアンという考え方は180度をπ(パイ)ラジアンと考えるやり方で、一般の角度をラジアンに変換するには180で割りそこに円周率をかけてやる必要があります。

(3) 定数の設定

この計算は、12行目で行っていますが、円周率を表すPIが定義されているのは4行目です。#defineマクロはすでにファイル分割で扱いましたが、このように、定数を定義するのにも用いることが出来ます。

#defineマクロによる定数の定義
#define PI 3.14

このようにすれば、PIという文字列が出てくれば、このソースの中では、3.14として扱うことが出来ます。

マクロには、定数を表現する方法のほかに、引数を与えて関数のような処理を行う引数付きマクロと呼ばれるものがあります。詳しくは、こちらをご覧ください。

1-3.その他の数学関数

(1) よく使う数学関数

続いては、その他よく使う数学関数を見てみましょう。

listex1-3:main.c
#include <stdio.h>
#include <math.h>

int main(int argc, char** argv) {
    int n = -2;
    double d1 = -2.5, d2 = 4.0;
    printf("%dの絶対値は%d\n", n, abs(n));
    printf("%fの絶対値は%f\n", d1, fabs(d1));
    printf("%fの2乗は%fです。\n", d2, pow(d2, 2));
    printf("%fの平方根は%fです。\n", d2, sqrt(d2));
    return 0;
}
実行結果
-2の絶対値は2 -2.500000の絶対値は2.500000 4.000000の2乗は16.000000です。 4.000000の平方根は2.000000です。

使用した関数の説明をしましょう(表1-4)。

表1-4.よく使う数学関数
関数書式意味使用例
abs()abs(int n);与えられた整数の絶対値を求める。int n = abs(-10);
fabs()fabs(double d);与えられた実数の絶対値を求める。double d = fabs(-3.1);
pow()pow(double x,double y);xのy乗を求める。double d = pow(3.0,2.0);
sqrt()sqrt(double d);与えらられた実数の平方根を求める。double d = sqrt(25.0);

絶対値を求める関数には、abs(),fabs()の二種類があります。状況に応じて使い分けましょう。

1-4.ビット演算

(1) ビット単位の演算を行う

今まで数値の演算ばかり扱ってきましたが、ビット演算も大事な演算です。以下にC言語におけるビット演算のサンプルを取り上げてみました。実行してみてください。

listex1-4:main.c
#include <stdio.h>

int main(int argc, char** argv) {
    //  16進数
    unsigned char i = 0xf;  //  2進数:00001111
    unsigned char j = 0xff; //  2進数:11111111
    printf("%x << 1 = %x\n", i, i << 1);          //  1ビット左シフト: 2進数:00011110 = 0x1e0
    printf("%x >> 1 = %x\n", i, i >> 1);          //  1ビット右シフト: 2進数:00000111 = 0x7
    printf("%x | %x = %x\n", i, j, i | j);         //  OR演算  : 2進数:11111111 = 0xff
    printf("%x & %x = %x\n", i, j, i & j);         //  AND演算 : 2進数:00001111 = 0xf
    printf("~%x = %x\n", i, (unsigned char)~i);   //  NOT演算 : 2進数:11110000 = 0xf0
    return 0;
}
実行結果
f << 1 = 1e f >> 1 = 7 f | ff = ff f & ff = f ~f = f0

(1) ビット演算の演算子

以下、演算子とその処理の内容を表にまとめます(表1-5)。これらの演算は、いわゆる数学的な処理とは違いますが、様々な場面で応用されることがあります。基本的な使い方をおさえておきましょう。

表1-5.ビット演算に用いる演算子
演算子意味使用例
<<左シフト。指定されたビット数分、数値を左シフトする。00001111 << 1 → 00011110 
>>右シフト。指定されたビット数分、数値を右シフトする。00001111 >> 1 → 00000111
|論理和(OR演算)。二つの数値の論理和をとる。00001111 | 11111111 → 11111111
&論理積(AND演算)。二つの数値の論理積をとる。00001111 & 11111111 → 00001111
~否定演算(NOT演算)。入力された1なら0に、0なら1に反転。~00001111 → 11110000

練習問題 : 問題1.

一週間で学べるコースの一覧
Udemy
...
2024/10/01

Udemyでも学びましょう!

一週間でわかるC言語・C++言語がオンライン講座になりました!動画音声によってさらにわかりやすくなりました!! 1講座で2つの言語を学ぶことができる上に、練習問題の回答もダウンロードできます。

Read →
Impress一週間シリーズ
1週間でC言語の基礎が学べる本
2024/10/01

書籍化された一週間シリーズ

本講座が「1週間でC言語の基礎が学べる本」として書籍化されました!サイトの内容プラスアルファでより学習しやすくなっています!Impressより発売中です!!

Read →
Impress一週間シリーズ
...
2024/10/01

書籍化された一週間シリーズ

一週間シリーズは書籍化されています。こちらもどうぞ!

Read →
プログラマーなら欲しいグッズ
プログラミンググッズ

プログラミンググッズ

快適なプログラミング環境を構築したい人々にぜひとも揃えてほしいグッズです。

Read →
制作・管理
シフトシステム株式会社

シフトシステム株式会社

このサイトはシフトシステム株式会社によって制作・管理がなされています。

Read →