関数について     Last modified: May 15, 2002

 絶対値を得るには,用意されている関数だけを用いて,

   sqrt(x^2)

などとすることもできなくはないですが,こんなことは普通やりません。

 awk で絶対値を与える関数は標準では用意されていません。絶対値を求めるには,次のような関数を作ります。

# x の絶対値を求める
# 使用例: x = abs(-10.95)

function abs(x)
{
   return (x < 0) ? -x : x
}
 平方根を求める関数はあります(sqrt)。もしないとしたらどのような関数を作りますか?

以下に,いくつかの関数を示しておきます。

二数の小さい方  二数の大きい方
引数の符号により-1,0,1を返す
四捨五入  ある数を超えない最大の整数値  ある数より大きい最小の整数値
タンジェント
アークコサイン  アークサイン  アークタンジェント(1)  アークタンジェント(2)
平方根
ベータ関数  ガンマ関数
階乗(1)  階乗(2)
組合せの数(1)  組合せの数(2)
ポアソン分布の確率  二項分布の確率  カイ二乗分布の確率
半角数字を全角数字に変換  半角アスキー文字を全角アスキー文字に変換
年月日からユリウス日  ユリウス日を年月日に変換
ユリウス日から年  ユリウス日から月  ユリウス日から日  ユリウス日から曜日
ある年が閏年かどうかを判定する



# x, y の小さい方を求める
# 使用例: x = min(10, 5)

function min(x, y)
{
   return (x < y) ? x : y
}
関数目次へ戻る
# x, y の大きい方を求める
# 使用例: x = max(10, 5)

function max(x, y)
{
   return (x > y) ? x : y
}
関数目次へ戻る
# x > 0 のとき  1
# x = 0 のとき  0
# x < 0 のとき -1 を返す
# 使用例: y = sign(z)

function sign(x)
{
   return (x > 0) ? 1 : (x == 0) ? 0 : -1
   # 上の1行は以下と同じことを表す
   #  if (x > 0) {
   #    return 1
   #  }
   #  else if (x == 0) {
   #    return 0
   #  }
   #  else {
   #    return -1;
   #  }
}
関数目次へ戻る
# x を四捨五入した値を返す
# 使用例: y = round(z)

function round(x)
{
   return (x > 0) ? int(x+0.5) : int(x-0.5)
}
関数目次へ戻る int,round,floor,ceil の違い
# x を超えない最大の整数値を返す
# 使用例: y = floor(x)

function floor(x)
{
   return (x > 0) ? int(x) : (int(x) == x) ? x : int(x)-1
   # 上の1行は以下と同じことを表す
   #  if (x > 0) {
   #    return int(x)
   #  }
   #  else if (int(x) == x) {
   #    return x
   #  }
   #  else {
   #    return int(x)-1
   #  }
}
関数目次へ戻る int,round,floor,ceil の違い
# x より大きい最小の整数値を返す
# 使用例: y = ceil(z)

function ceil(x)
{
   return (int(x) == x) ? x : (x > 0) ? int(x)+1 : int(x)
   # 上の1行は以下と同じことを表す
   #  if (int(x) == x) {
   #    return x
   #  }
   #  else if (x > 0) {
   #    return int(x)+1
   #  }
   #  else {
   #    return int(x)
   #  }
}
関数目次へ戻る int,round,floor,ceil の違い
# x の tangent を求める
# 使用例: y = tan(z)

function tan(x)
{
   return sin(x)/cos(x)
}
関数目次へ戻る
# 1 ≧ x ≧ 0 の arc_cosine を求める
# 使用例: y = arc_cosine(z)
# 必要とする関数: arc_sine

function arc_cosine(x)
{
   return arc_sine(sqrt(1-x^2))
}
関数目次へ戻る
# 1 ≧ x ≧ 0 の arc_sine を求める
# 使用例: y = arc_sine(z)

function arc_sine(x,    a0, a1, a2)
{
   if (x == 0) {
       return 0
   }
   a0 = x*sqrt(1-x^2)
   a1 = x
   for (;;) {
       a2 = a1*sqrt(2*a1/(a1+a0))
       if (abs(a2-a1)/a1 < 1e-14) {
           return a2
       }
       a0 = a1
       a1 = a2
   }
}
関数目次へ戻る
# x の arctangent を求める
# 使用例: y = arc_tangent(z)

function arc_tangent(x,    a, b, a2, b2)
{
   a = 1/sqrt(1+x^2)
   b = 1
   for (;;) {
       a2 = (a+b)/2
       b2 = sqrt(a2*b)
       if (abs(a2 - b2)/b2 < 1e-14) {
           return x/sqrt(a2*b2*(1+x^2))
       }
       a = a2
       b = b2
   }
}
関数目次へ戻る
# x の arctangent を求める
# 使用例: y = atan(z)

function atan(x)
{
   return atan2(x, 1)
}
関数目次へ戻る
# 平方根を求める関数 sqrt2.awk
#
function sqrt2(x,     x1, x2) {
   if (x < 0) exit(1)
   if (x == 0) return 0
   x1 = 1
   for (;;) {
       x2 = (x1+x/x1)/2
       if (abs(x2-x1)/x2 < 1e-10) {
           return x2
       }
       x1 = x2
   }
}
関数目次へ戻る
# ベータ関数
# 値が求められないときには,"Inf" という文字列を返すことに注意

function beta(x, y,     z1, z2, z3) 
{
   z1 = gamma(x)
   z2 = gamma(y)
   z3 = gamma(x+y)
   return (z1 == "Inf" || z2 == "Inf" || z3 == "Inf") ? "Inf" : z1/z3*z2
}
関数目次へ戻る
# ガンマ関数
# 必要とする関数 abs
# 値が求められないときには,"Inf" という文字列を返すことに注意

function gamma(x,     a, b, z, factor, i, m, mg)
{
   if (x > 171.6) {
       printf "gamma: Overflow.\n" > "/dev/stderr"
       return "Inf"
   }
   if (x <= 1.5) {
       if (x >= 0.5) {
           a = x-1.0
           factor = 1.0
       }
       else {
           m = int(x)
           a = x-m
           if (a == 0) {
               printf "gamma: Invalid argument.\n" > "/dev/stderr"
               return "Inf"
           }
           if (a >= -0.5) {
               mg = abs(m)+1
           }
           else {
               mg = abs(m)+2
               a++
           }
           z = 1.0
           for (i = 0; i < mg; i++) {
               z *= x
               x++
           }
           factor = 1.0/z
       }
   }
   else {
       m = int(x)
       a = x-m
       if (a <= 0.5) {
           mg = m-1
       }
       else {
           mg = m
           a--
       }
       z = 1.0
       for (i = 0; i < mg; i++) {
           z *= (x-1.0)
           x--
       }
       factor = z
   }
   b = ((((((((-0.42202e-11*a +0.120028e-10)*a +0.923397e-10)*a -0.12736143e-8)*a +0.62756218e-8)*a -0.1595268e-9)*a-0.2054743152e-6)*a +0.13385015466e-5)*a -0.25889950224e-5)*a
   b = ((((((((((b -0.175458597517e-4)*a +0.1455961421399e-3)*a -0.3608378162548e-3)*a -0.80432977560424699e-3)*a +0.80232730222673465e-2)*a -0.1764524455014432e-1)*a -0.24552490005400017e-1)*a +0.19109110138769151)*a -0.23309373642178674)*a -0.42278433509846714)*a +1.0
   return factor/(1.0+a)/b
}
関数目次へ戻る
# 整数値 n(n ≧ 0 )の階乗 n! を求める
# 使用例: x = factorial(10)

function factorial(n,     retv, i)
{
   retv = 1
   for (i = 1; i <= n; i++) {
       retv *= i
   }
   return retv
}
関数目次へ戻る
# 整数値 n(n ≧ 0 )の階乗 n! を求める(再帰関数)
# 使用例: x = factorial2(10)

function factorial2(n)
{
   if (n == 0) {
       return 1
   }
   else {
       return n*factorial2(n-1)
   }
}
関数目次へ戻る
# n から m (n ≧ m ≧ 0 )を取り出す組合せを求める
# 使用例: x = combination(10, 5)

function combination(n, m,     i, c) 
{
   c = 1
   k = min(n, n-m)
   for (i = 1; i <= k; i++) {
       c *= (n-i+1)/i
   }
   return c
}
関数目次へ戻る
# 組合せ(なるべく正確に求める)

function combination2(n, m,     numerator, denominator, p, pivot, i, j, k, comb)
{
   comb = 1.0
   p = min(m, n-m)
   if (p > 0) {
       for (i = 1; i <= p; i++) {
           numerator[i] = n-p+i
           denominator[i] = i
       }
       for (k = 2; k <= p; k++) {
           pivot = denominator[k]
           if (pivot > 1) {
               j = -((n-p)%k)
               for (i = k; i <=p; i +=k) {
                   numerator[i+j] /= pivot
                   denominator[i] /= pivot
               }
           }
       }
       for (i = 1; i <= p; i++) {
           if (numerator[i] > 1) {
               comb *= numerator[i]
           }
       }
   }
   return comb
}
関数目次へ戻る
# ポアソン定数 lambda のポアソン分布の確率 f(lambda, x) を求める
# 使用例: y = Poisson(lambda, x)

function Poisson(lambda, x)
{
   return exp(-lambda)*lambda^x/factorial(x)
}
関数目次へ戻る
# 母比率 p の二項分布の確率 f(p, n, x) を求める
# n は試行回数,x は対象事象の観察回数
# 使用例: y = Binomial(p, n, x)
# 必要とする関数: combination

function Binomial(p, n, x)
{
   return combination(n, x) * p^x * (1-p)^(n-x)
}
関数目次へ戻る
# 自由度 df のカイ二乗分布において確率密度 f(x) を求める
# 使用例: chi_dist(2.34, 2)

function chi_dist(x, df)
{
   return x^(df/2.0-1.0) * exp(-x/2) / 2^(df/2.0) / gamma(df/2.0)
}
関数目次へ戻る
# 0 〜 9 の数字の列の各文字を,0〜9に置き換える
# 使用例: i2zen("0123456789012")
#          i2zen(12345)

function i2zen(num,     i, retv)
{
   for (i = 1; i <= length(num); i++) {
       retv = retv substr("0123456789", substr(num, i, 1)*2+1, 2)
   }
   return retv
}
関数目次へ戻る
# いわゆるアスキー半角文字列の各文字を,いわゆる全角文字に置き換える
# 使用例: a2zen("01234ABCxyz#@")

function a2zen(str,     i, retv)
{
   for (i = 1; i <= length(str); i++) {
       retv = retv substr(" !”#$%&’()*+,−./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_‘abcdefghijklmnopqrstuvwxyz{|}〜",
       index(" !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
             substr(str, i, 1))*2-1, 2)
    }
    return retv
}
関数目次へ戻る
# 西暦年月日からユリウス日を得る
# y 年 m 月 d 日

function J_day(y, m, d)
{
   return d-32075+int( 1461*(y+4800+ int( (m-14)/12) )/4 ) \
          +int( 367*(m-2-int( (m-14)/12 )*12)/12 ) \
          -int( 3*( int( (y+4900+int( (m-14)/12 ))/100 ) )/4 )
}
関数目次へ戻る
# ユリウス日 jul から西暦年を取り出す

function year(jul)
{
   return substr(date(jul), 1, 4)
}
関数目次へ戻る
# ユリウス日 jul から月を取り出す

function month(jul)
{
   return substr(date(jul), 6, 2)+0
}
関数目次へ戻る
# ユリウス日 jul から日を取り出す

function day(jul)
{
   return substr(date(jul), 9, 2)+0
}
関数目次へ戻る
# 指定された西暦年月日の曜日を求める
#  引数
#    y 西暦年(4桁)
#    m 月
#    d 日
#    i 戻り値の種類指定
#  戻り値
#    i が 1 のとき     y年 m月 d日の 曜日を表す漢字1文字
#    i が 1 以外のとき y年 m月 d日の 曜日を表す英字3文字
# 必要とする関数: J_day

function week(y, m, d, i)
{
   return (i == 1) ? substr("日月火水木金土", ((J_day(y, m, d)+1)%7)*2+1, 2) \
                   : substr("SunMonTueWedThuFriSat", ((J_day(y, m, d)+1)%7)*3+1, 3)
}
関数目次へ戻る
# ユリウス日から西暦年月日を得る

function date(jul,     l, n, iy, jm, kd)
{
   l = jul+68569
   n = int(4*l/146097)
   l -= int((146097*n+3)/4)
   iy = int(4000*(l+1)/1461001)
   l -= int(1461*iy/4)-31
   jm = int(80*l/2447)
   kd = l-int(2447*jm/80)
   l = int(jm/11)
   jm = jm+2-12*l
   iy = 100*(n-49)+iy+l
   return sprintf("%4d/%02d/%02d", iy, jm, kd)
}
関数目次へ戻る
# 西暦年 y を与えてその年が閏年かどうかを判定する

function uruudosi(y)
{
    return (month(J_day(y, 2, 29)) == 2) ? 1 : 0
}
関数目次へ戻る
・ 直前のページへ戻る  ・ E-mail to Shigenobu AOKI