以下は目次です。
C言語の標準ライブラリには、数学的な処理を行うための関数(以下、数学関数と表記)が多数含まれています。開発するプログラムの分野によっては、非常に有用になることもありますし、反対にほとんど用がないこともあるかもしれません。
この章では、分野を問わず使用頻度が高そうなものに限定して紹介します。ただし、数学的な解説はしません(そこは専門ではないので控えます)。また、数学関数を使う上で知っておくべきことについて触れます。
数学関数のほとんどは、<math.h> で宣言されています。ここにある関数は、引数や戻り値に float、double、long double のいずれかの型を使うようになっています。わずかながら整数型が使える数学関数がありますが、そういったものは <stdlib.h> の方に分離されています。
ほかに、math.h にある数学関数の複素数バージョンが <complex.h> にあります。
gcc で <math.h>
の関数を使うときには、コンパイルオプションに -lm
を追加してください。数学関連のライブラリが分けられているため、このように明示的にリンクの指示を与える必要があります。
数学関数のいくつかは、計算が不可能であったり、結果が表現不可能であったりする可能性を持っています。このようなエラーが起きていることを検出する方法を知っておく必要があります。
数学関数が発生させるエラーには種類があります。
実引数の指定が適切な範囲内にない場合、定義域エラー (domain error) が発生します。実例としては、平方根を求める sqrt関数(後で取り上げます)において、実引数を負数にした場合があります。
結果が表現できない場合、値域エラー (range error)(「ちいき」と読みます)が発生します。値域エラーが発生する原因には、結果が巨大すぎて表現できないオーバーフロー (overflow) と、微小すぎて表現できないアンダーフロー (underflow) があります。
実例として、べき乗を求める pow関数(後で取り上げます)は値域エラーを発生させることがあります。
一般に、定義域エラーは、実引数を注意して指定することで防げます。各関数ごとに、定義域エラーを発生させない有効な値の範囲があるはずなので、その範囲を逸脱していないかどうか確認できるでしょう。たとえば、sqrt関数では、実引数を負数にしなければ、定義域エラーの発生を防げます。
一方で、値域エラーは、防ぐことが難しいこともあります。値域エラーの発生の有無は、関数の実装次第な部分もあるためです。
いずれにしても、注意して防ぐことが困難であるならば、適切な仕組みをもって検出する必要があります。数学関数のエラーは、errno の仕組みや、浮動小数点例外の仕組みを使って検出します。
どの仕組みが使われるかは、処理系によって異なります。math.h にある math_errhandling というマクロがどう置換されるかによって知ることができます。可能性は次の3通りです。
#define math_errhandling (MATH_ERRNO)
#define math_errhandling (MATH_ERREXCEPT)
#define math_errhandling (MATH_ERRNO | MATH_ERREXCEPT)
Visual Studio 2017
での置換結果は、(MATH\_ERRNO | MATH\_ERREXCEPT)
になっています。
置換結果に MATH_ERRNO が含まれている場合は errno の仕組みが使われ、MATH_ERREXCEPT が含まれている場合は、浮動小数点例外の仕組みが使われます。
errno を使う場合は、定義域エラーの発生時には errno に EDOMが、値域エラーの発生時は ERANGEが格納されます。
EDOM も ERANGE も、その置換結果は 0 ではない値なので、エラーを errno で報告する標準ライブラリ関数を呼び出す際には、その呼び出しの直前で 0 を代入しておき、呼び出しの直後で値を調べるようにします。実際のプログラムは、この後、各関数を説明する中で掲載します。
浮動小数点例外 (floating-point exception) を使う場合は、数学関数がエラーを発生させたら、その内容に応じた浮動小数点例外を発生させます。浮動小数点例外が発生すると、浮動小数点状態フラグ (floating-point status flag) に、浮動小数点例外の種類に応じた値がセットされます。浮動小数点状態フラグは、直接的にはアクセスできないところにある変数のような存在です。
errno の仕組みが、数学関数以外でも使われることと同じく、浮動小数点例外の仕組みも数学関数以外でも使われます。たとえば、無限大から無限大を減算するような、通常の演算でも使用される可能性があります。
浮動小数点例外の種類に応じて、以下のマクロが <fenv.h> で定義されています。
マクロ | 意味 |
---|---|
FE_INVALID | 定義域エラー。不正な演算を要求 |
FE_DIVBYZERO | 値域エラー。結果が無限大になってしまう場合 |
FE_OVERFLOW | 値域エラー。結果がオーバーフローしている |
FE_UNDERFLOW | 値域エラー。結果がアンダーフローしている |
FE_INEXACT | 結果が精度の問題で正確に表現できず、丸められている |
FE_ALL_EXCEPT | 上記のうち、処理系が対応しているものすべての組み合わせ |
ただし、処理系がすべての浮動小数点例外に対応している保証はなく、一部のみの対応である可能性があります。いずれにしても、FE_ALL_EXCEPT は、対応しているすべての浮動小数点例外の組み合わせを意味します。
FE_INEXACT については、浮動小数点数の計算で丸めが起こるのはよくあることなので、わりと至るところで発生します。エラーというよりは、報告という感覚で受け取った方がいいかもしれません。
実際にエラーの有無を調べる流れは、errno を使ったものに似ています。
手順 | errno | 浮動小数点例外 |
---|---|---|
1 | errno に 0 を代入 | feclearexcept関数を呼び出して、浮動小数点状態フラグをクリアする |
2 | 数学関数を呼び出す | 数学関数を呼び出す |
3 | errno の値を調べる | fetestexcept関数を呼び出して、浮動小数点状態フラグの状態を調べる |
feclearexcept関数と fetestexcept関数は、fenv.h に以下のように宣言されています。
int feclearexcept(int excepts);
int fetestexcept(int excepts);
いずれも実引数には、先ほどのマクロのいずれか、あるいは組み合わせを指定します。普通は、feclearexcept関数の方は FE_ALL_EXCEPT を指定して、すべてのフラグをクリアすることになるでしょう。
実引数に複数のマクロを指定するときにはビット和演算(第49章)を行います。
fetestexcept関数は、指定した浮動小数点例外のうちのいずれか1つでも発生していたら、0以外の値を返します。
正確にいえば、戻り値は、浮動小数点状態フラグと実引数とのビット積演算(第49章)を行った結果です。
なお、ここまでに取り上げた浮動小数点例外に関する機能を使うには、FENV_ACCESS という標準プラグマを、次のように定義する必要があります。
#pragma STDC FENV_ACCESS on
ただし、Visual Studio 2017 は標準プラグマに対応していないため、次のように Visual Studio の独自のプラグマを定義します。
#pragma fenv_access (on)
以下、sqrt関数(後述)で定義域エラーの発生を調べる例です。
#include <fenv.h>
#include <math.h>
#include <stdio.h>
#if defined(_MSC_VER) // Visual Studio であるか?
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS on
#endif
void sqrt_test(double x)
{
(FE_ALL_EXCEPT);
feclearexceptdouble result = sqrt(x);
if (fetestexcept(FE_INVALID)) {
("定義域エラーが発生しました。");
puts}
else {
("%lf\n", result);
printf}
}
int main(void)
{
(9.0); // OK
sqrt_test(-9.0); // 定義域エラー
sqrt_test(0.0); // OK
sqrt_test}
実行結果:
3.000000
定義域エラーが発生しました。
0.000000
【C11】極エラー (pole error) が追加されています。これは、実引数が有限ではあるものの極限に近いために、計算結果が無限大になることで発生します。ただし取り扱いとしては値域エラーと同様です。エラー処理に errno を用いる場合は、ERANGE がセットされます。浮動小数点例外を用いる場合は、FE_DIVBYZERO で表される例外が発生します。
絶対値を求めるには、fabsf関数、fabs関数、fabsl関数を使います。
float fabsf(float x);
double fabs(double x);
long double fabsl(long double x);
実引数に指定した値の絶対値を返します。非常に単純な関数であり、エラーを発生させることもありません。
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", fabs(1.0));
printf("%lf\n", fabs(-1.0));
printf("%lf\n", fabs(0.0));
printf}
実行結果:
1.000000
1.000000
0.000000
また、<stdlib.h> に、整数型を扱う abs関数、labs関数、llabs関数があります。
int abs(int i);
long int labs(long int i);
long long int llabs(long long int i);
こちらも、実引数に指定した値の絶対値を返します。
整数型で表現できる値の範囲の都合上、もっとも小さい負数の絶対値を表現できない可能性があります。この場合に返される結果は未定義です。
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
("%d\n", abs(1));
printf("%d\n", abs(-1));
printf("%d\n", abs(INT_MIN)); // 未定義の結果を返す可能性がある
printf("%d\n", abs(INT_MIN + 1));
printf}
具体的には、数の表現に、2の補数表現を使う環境で問題になります。この表現方法では、負数の方が正数よりも 1つだけ多くの数を扱えます(たとえば -128~+127のように)。2の補数表現は非常に一般的であり、ほとんどの環境がこの表現方法を使っています(「情報処理技術編>負の数の表現」のページを参照)
べき乗を求めるには、powf関数、pow関数、powl関数を使います。
float powf(float x, float y);
double pow(double x, double y);
long double powl(long double x, long double y);
x の y乗を計算して返します。
これらの関数は、以下のようにエラーを発生させることがあります。
【上級】処理系が IEC 60559 の仕様に準拠している場合、さらに細かな規定が追加されています。準拠の状況は、__STDC_IEC_559__マクロが定義されているかどうかで判定できます。
2番目が曖昧ですが、結果が無限大になってしまうようなケースで値域エラーになります。また、この条件を見る限りでは、x と y がともに 0 の場合もエラーになるはずですが、実際にはエラーにならず、1.0 を返す実装もあります(Visual Studio 2017 は 1.0 を返します)。
C11 では、x が 0 で、y も 0 の場合は定義域エラー。x が 0 で、y が 0未満の場合は、定義域エラーまたは極エラーになるとされています。
動作を確認してみましょう。
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
void pow_test(double x, double y)
{
= 0;
errno double result = pow(x, y);
if (errno == EDOM) {
("定義域エラーが発生しました。");
puts}
else if (errno == ERANGE) {
("値域エラーが発生しました。");
puts}
else {
("%lf\n", result);
printf}
}
int main(void)
{
(2.0, 3.0); // OK
pow_test(2.0, 0.0); // OK (0以外を 0乗すると、つねに 1.0)
pow_test(0.0, 2.0); // OK (0 を n乗すると、つねに 0.0)
pow_test(2.0, -3.0); // OK
pow_test(-2.0, 3.0); // OK
pow_test(0.0, 0.0); // 定義域エラー (1.0 のこともある)
pow_test(0.0, -2.0); // 値域エラー
pow_test(-2.0, 1.5); // 定義域エラー
pow_test(DBL_MAX, 2.0); // 値域エラー
pow_test(DBL_MIN, -2.0); // 値域エラー
pow_test}
実行結果:
8.000000
1.000000
0.000000
0.125000
-8.000000
1.000000
値域エラーが発生しました。
定義域エラーが発生しました。
値域エラーが発生しました。
値域エラーが発生しました。
平方根を求めるには、sqrtf関数、sqrt関数、sqrtl関数を使います。
float sqrtf(float x);
double sqrt(double x);
long double sqrtl(long double x);
x の平方根を返します。たとえば、9 の平方根には +3 と -3 がありますが、常に正の平方根が返されます。
これらの関数は、実引数が負数の場合、定義域エラーを発生させます。
動作を確認してみましょう。
#include <errno.h>
#include <math.h>
#include <stdio.h>
void sqrt_test(double x)
{
= 0;
errno double result = sqrt(x);
if (errno == EDOM) {
("定義域エラーが発生しました。");
puts}
else {
("%lf\n", result);
printf}
}
int main(void)
{
(9.0); // OK
sqrt_test(-9.0); // 定義域エラー
sqrt_test(0.0); // OK
sqrt_test}
実行結果:
3.000000
定義域エラーが発生しました。
0.000000
小数点以下を切り上げたり、切り捨てたりした結果が欲しい場面があります。このような場合、ある浮動小数点数から、一番近い整数を得る関数が利用できます。
ceil系の関数は、実引数の値の小数点以下を切り上げた結果を返します。ceilf関数、ceil関数、ceill関数があります。
float ceilf(float x);
double ceil(double x);
long double ceill(long double x);
結果の型は整数型ではなく、引数と同じ型で返されます。また、これらの関数はエラーを発生させることはありません。
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", ceil(10.1));
printf("%lf\n", ceil(10.9));
printf("%lf\n", ceil(-10.1));
printf("%lf\n", ceil(-10.9));
printf}
実行結果:
11.000000
11.000000
-10.000000
-10.000000
floor系の関数は、実引数の値の小数点以下を切り捨てた結果を返します。floorf関数、floor関数、floorl関数があります。
float floorf(float x);
double floor(double x);
long double floorl(long double x);
結果の型は整数型ではなく、引数と同じ型で返されます。また、これらの関数はエラーを発生させることはありません。
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", floor(10.1));
printf("%lf\n", floor(10.9));
printf("%lf\n", floor(-10.1));
printf("%lf\n", floor(-10.9));
printf}
実行結果:
10.000000
10.000000
-11.000000
-11.000000
roundf関数、round関数、roundl関数は、実引数の値を小数点以下で四捨五入した結果を返します。一番近い2つの整数値のちょうど中間の値(つまり、4.5 とか -4.5 のような値)の場合は、0 から遠い方の値を返すことになっています(つまり、4.5 なら 5.0 が、-4.5 なら -5.0 が返されます)。
float roundf(float x);
double round(double x);
long double round(long double x);
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", round(10.1));
printf("%lf\n", round(10.9));
printf("%lf\n", round(-10.1));
printf("%lf\n", round(-10.9));
printf}
実行結果:
10.000000
11.000000
-10.000000
-11.000000
lroundf関数、lround関数、lroundl関数 も round関数と同じことをしますが、結果を long int型で返します。便利そうな気もしますが、引数の型(浮動小数点数型)で表現できる値が、必ずしも long int型で表現できるとは限らないことに注意が必要です。戻り値の型で表現できない場合の結果は未規定です。また、実引数の絶対値が大きすぎると、値域エラーを発生させます。
long int lroundf(float x);
long int lround(double x);
long int lround(long double x);
#include <stdio.h>
#include <math.h>
int main(void)
{
("%ld\n", lround(10.1));
printf("%ld\n", lround(10.9));
printf("%ld\n", lround(-10.1));
printf("%ld\n", lround(-10.9));
printf}
実行結果:
10
11
-10
-11
llroundf関数、llround関数、llroundl関数 は、戻り値型が long long int型であること以外は、先ほどの lround系の関数と同様です。
long long int llroundf(float x);
long long int llround(double x);
long long int llround(long double x);
truncf関数、trunc関数、truncl関数は、小数点以下を捨て去った結果を返します(規格のとおりにいうと、絶対値が実引数の絶対値よりも大きくない値を返します)。たとえば、floor関数では -4.5 に対して、-5.0 を返しますが、trunc関数は -4.0 を返します。
float truncf(float x);
double trunc(double x);
long double truncl(long double x);
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", trunc(10.1));
printf("%lf\n", trunc(10.9));
printf("%lf\n", trunc(-10.1));
printf("%lf\n", trunc(-10.9));
printf}
実行結果:
10.000000
10.000000
-10.000000
-10.000000
nearbyintf関数、nearbyint関数、nearbyintl関数は、現在の丸め方向 (rounding direction) に従って、小数点以下を丸めた整数値を返します。丸め方向は、浮動小数点数の演算の際、精度上表現できない値になったときに、どのような処置を取るかを決定するものです。これは、<fenv.h> にある関数やマクロによって変更・取得できます。
float nearbyintf(float x);
double nearbyint(double x);
long double nearbyintl(long double x);
#include <stdio.h>
#include <math.h>
int main(void)
{
("%lf\n", nearbyint(10.1));
printf("%lf\n", nearbyint(10.9));
printf("%lf\n", nearbyint(-10.1));
printf("%lf\n", nearbyint(-10.9));
printf}
実行結果:
10.000000
11.000000
-10.000000
-11.000000
rintf関数、rint関数、rintl関数は、nearbyint関数と同じことをしますが、結果が実引数の値と一致することを期待しています。つまり、実引数がすでに整数値になっていることを求めており、そうでない値を渡すと、FE_INEXACT浮動小数点例外を発生させることがあります。
float rintf(float x);
double rint(double x);
long double rintl(long double x);
#include <fenv.h>
#include <stdio.h>
#include <math.h>
#if defined(_MSC_VER)
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
void call_rint(double x)
{
(FE_ALL_EXCEPT);
feclearexcept
double result = rint(x);
("%lf%s\n",
printf,
result(FE_INEXACT) ? " : FE_INEXACT" : ""
fetestexcept);
}
int main(void)
{
(10.0); // この場合、結果も 10.0 なので、nearbyint とまったく同じ
call_rint(10.1); // この場合、10.1 が 10.0 に変換される。一致しないので FE_INEXACT が発生するかもしれない
call_rint(10.9); // 同上
call_rint(-10.1); // 同上
call_rint(-10.9); // 同上
call_rint}
実行結果:
10.000000
10.000000 : FE_INEXACT
11.000000 : FE_INEXACT
-10.000000 : FE_INEXACT
-11.000000 : FE_INEXACT
lrintf関数、lrint関数、lrintl関数は、rint系の関数と同じことをしますが、結果を long int型で返します。戻り値の型で表現できない場合の結果は未規定です。また、実引数の絶対値が大きすぎると、値域エラーを発生させます。
long int lrintf(float x);
long int lrint(double x);
long int lrintl(long double x);
llrintf関数、llrint関数、llrintl関数は、戻り値型が long long int型であること以外は、先ほどの lrint系の関数と同様です。
long long int llrintf(float x);
long long int llrint(double x);
long long int llrintl(long double x);
logf関数、log関数、logl関数は、自然対数(底がネイピア数 e の対数)を求めます。
float logf(float x);
double log(double x);
long double logl(long double x);
log10f関数、log10関数、log10l関数は、常用対数(底が 10 の対数)を求めます。
float log10f(float x);
double log10(double x);
long double log10l(long double x);
いずれの関数も、実引数が負数の場合、定義域エラーが発生します。また、実引数が 0 の場合には、値域エラーが発生することがあります。
【上級】処理系が IEC 60559 の仕様に準拠している場合、さらに細かな規定が追加されています。準拠の状況は、__STDC_IEC_559__マクロが定義されているかどうかで判定できます。
log10関数の使用例として、10進数の桁数を調べる関数を作ってみます。
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int get_digits(int n)
{
if (n == 0) {
return 1;
}
= 0;
errno double result = log10(abs(n));
(errno == 0);
assert
return (int)result + 1;
}
int main(void)
{
("%d\n", get_digits(0));
printf("%d\n", get_digits(1));
printf("%d\n", get_digits(100));
printf("%d\n", get_digits(10000000));
printf("%d\n", get_digits(-1));
printf("%d\n", get_digits(-100));
printf("%d\n", get_digits(-10000000));
printf}
実行結果:
1
1
3
8
1
3
8
常用対数を求めることは、すなわち「ある数が 10 の何乗であるか」ということですから、この性質を利用して、10進数の桁数を得られます。単純に使うと 1 小さい数が得られるので +1 する必要はあります(たとえば、10 が 10 の 1乗であることを考えれば、意味が分かるでしょう)。
log10関数の実引数は 1以上にしないとエラーが発生してしまう可能性があるため、0以下の数の桁数を得たいときに対する備えが必要です。負数への備えとしては、絶対値を渡すようにしておけばよいです。0 の場合は直接 1(桁) を返すことにしています。
三角関数についても用意されています。
正弦は sinf関数、sin関数、sinl関数で求められます。
余弦は cosf関数、cos関数、cosl関数で求められます。
正接は tanf関数、tan関数、tanl関数で求められます。
float sinf(float x);
double sin(double x);
long double sinl(long double x);
float cosf(float x);
double cos(double x);
long double cosl(long double x);
float tanf(float x);
double tan(double x);
long double tanl(long double x);
引数 x には、角度をラジアン単位で指定します。
「度」と「ラジアン」を変換するような関数やマクロは標準にはありません。必要があれば、自前で作っておくとよいでしょう。円周率の定義も標準にはないので、自前での定義が必要です。
円周率に関して、M_PI という名前の定義をよく見かけますが、これは標準のものではありません。
次のサンプルプログラムでは、45°刻みで、sin、cos、tan の結果を出力しています。
#include <math.h>
#include <stdio.h>
#define PI 3.14159265358979323846
#define DEG_TO_RAD(deg) ((deg) / 180.0 * (PI)) // 度からラジアンへの変換
int main(void)
{
double deg = -180.0;
for (int i = 0; i <= 8; ++i) {
("sin(%.1f) = %lf\n", deg, sin(DEG_TO_RAD(deg)));
printf+= 45.0;
deg }
= -180.0;
deg for (int i = 0; i <= 8; ++i) {
("cos(%.1f) = %lf\n", deg, cos(DEG_TO_RAD(deg)));
printf+= 45.0;
deg }
= -180.0;
deg for (int i = 0; i <= 8; ++i) {
("tan(%.1f) = %lf\n", deg, tan(DEG_TO_RAD(deg)));
printf+= 45.0;
deg }
}
実行結果:
sin(-180.0) = -0.000000
sin(-135.0) = -0.707107
sin(-90.0) = -1.000000
sin(-45.0) = -0.707107
sin(0.0) = 0.000000
sin(45.0) = 0.707107
sin(90.0) = 1.000000
sin(135.0) = 0.707107
sin(180.0) = 0.000000
cos(-180.0) = -1.000000
cos(-135.0) = -0.707107
cos(-90.0) = 0.000000
cos(-45.0) = 0.707107
cos(0.0) = 1.000000
cos(45.0) = 0.707107
cos(90.0) = 0.000000
cos(135.0) = -0.707107
cos(180.0) = -1.000000
tan(-180.0) = 0.000000
tan(-135.0) = 1.000000
tan(-90.0) = -16331239353195370.000000
tan(-45.0) = -1.000000
tan(0.0) = 0.000000
tan(45.0) = 1.000000
tan(90.0) = 16331239353195370.000000
tan(135.0) = -1.000000
tan(180.0) = -0.000000
90°のときの正接は定義できないため、おかしな結果になっていますが、エラーとはなりません。
<math.h> や <complex.h> の数学関数は、型に応じた使い分けが必要です。特に、後から扱う型を変更した場合、呼び出す関数も修正しなければならないことに注意が必要です。暗黙的に型変換できてしまうため気付きづらく、意図しない精度で計算が行われてしまう可能性があります。
そこで、<tgmath.h> という標準ヘッダに、型総称マクロ (type-generic macro) と呼ばれる特殊なマクロが定義されており、型の種類 (float、double、long double と、それぞれの複素数型のみ)を問わずに、同じ関数名が使えるようになっています。
たとえば、次のサンプルプログラムのように、float、double、long double のいずれの型でも「fabs」という名前で使用できます。
#include <stdio.h>
#include <tgmath.h>
int main(void)
{
("%f\n", fabs(-12.34f));
printf("%lf\n", fabs(-12.34));
printf("%Lf\n", fabs(-12.34L));
printf}
実行結果:
12.340000
12.340000
12.340000
<tgmath.h> は、Visual Studio 2017 では使用できません。
【上級】型総称マクロは、処理系がこれを特別扱いして「うまく処理」しているだけであり、我々はこの機能を真似できません。C11 からは、総称選択 (generic selection) という新機能が追加されたことにより、真似することができるようになりました。
問題① 2つの浮動小数点数が、どれだけ離れているかを計算するプログラムを作成してください。
問題② 2次元平面上にある2つの点の間の距離を計算するプログラムを作成してください。
()
の前後の空白の空け方)(
の直後、)
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一)≪さらに古い更新履歴を展開する≫
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |