また、お世話になります。
現在、新しい関数電卓を作成中です。
むかし、C言語を始めた頃に sin、cos、tan という数学関数があった。
そして、数年前に知ったばかりですが C99 規格により asin、acos、atan、sinh、
cosh、tanh も追加されたようです。しかし、逆双曲線関数の asinh、acosh、atanh が
math.h を見ても見つかりません。
[質問1]
なぜ?
逆双曲線関数はないのか?
[質問2]
逆双曲線関数を実装するにはどうすべきか?
[環境環境]
Windows Vista SP2
VC2008(無料版)
[実行環境]
Windows Vista SP2 以上
新しい関数電卓には逆双曲線関数のボタンを付けいたので
ご存知の方はアドバイスをお願いします。
> 逆双曲線関数はないのか?
VC++はC99に対応していないため,ありません。
> 逆双曲線関数を実装するにはどうすべきか?
ないなら,他の関数から実装すればよいかと思いますが……。
Wikipediaの
http://ja.wikipedia.org/wiki/%E5%8F%8C%E6%9B%B2%E7%B7%9A
%E9%96%A2%E6%95%B0#.E9.80.86.E5.8F.8C.E6.9B.B2.E7.B7.9A.E9.96.A2.E6.95.B0
とかは,参考になるでしょうか。
(1)確かにありませんね…不思議。需要がないからかもしれないです。
(2)実装です。
#include <cmath>
double asinh(double v){
if(v<0)return -log(-v+sqrt(v*v+1));
else return log(v+sqrt(v*v+1));
}
double acosh(double v){
return log(abs(v)+sqrt(v*v-1));//主値のみを返す
}
double atanh(double v){
return 0.5*log((1+v)/(1-v));
}
サクッと書いてみましたがatanhはv=0周辺でけた落ち誤差が発生するかもしれません。
あとboostに関数が用意されているようですのでそちらを用いるのもありかと思います。
YuO さんへ
Wikipedia の『双曲線関数』を参考にしてみます。
http://ja.wikipedia.org/wiki/%E5%8F%8C%E6%9B%B2%E7%B7%9A%E9%96%A2%E6%95%B0
Alq3 さんへ
> (2)実装です。
ありがとうございます。
Wikipedia の『双曲線関数』の最後に逆双曲線関数を指数関数で表した図があります。
この図では asinh(x)=log(x+√(x^2+1))となってます。
Alq3 さんの実装では 0 以下と 0 以上の記述がありますね。
Wikipedia の図が間違ってるのでしょうか?
あと Wikipedia の図で acosh(x)=log(x±√(x^2-1))となってます。
Alq3 さんの実装では『主値のみを返す』となってますが、
asinh のように 0 以下の処理も書いた方がよいでしょうか?
どうなのでしょう?
Wikipedia の『双曲線関数』と Alq3 さんの実装をもとに私も実装してみました。
#include <math.h>
#include <stdio.h>
//------------------------------------------------
// asinh
//------------------------------------------------
double asinh( double x )
{
return log(x + sqrt(x * x + 1.0));
}
//------------------------------------------------
// acosh
//------------------------------------------------
double acosh( double x )
{
return log(x + sqrt(x * x - 1.0));
}
//------------------------------------------------
// atanh
//------------------------------------------------
double atanh( double x )
{
return (log((1.0 + x) / (1.0 - x)) / 2.0);
}
//------------------------------------------------
// メイン関数
//------------------------------------------------
int main( void )
{
// ゼロ値
printf( asinh(0.0) =%30.20f\n, asinh(0.0) );
printf( acosh(0.0) =%30.20f\n, acosh(0.0) );
printf( atanh(0.0) =%30.20f\n, atanh(0.0) );
printf( \n );
// プラス値
printf( asinh(+30.0)=%30.20f\n, asinh(+30.0) );
printf( acosh(+30.0)=%30.20f\n, acosh(+30.0) );
printf( atanh(+0.33)=%30.20f\n, atanh(+0.33) );
printf( \n );
// マイナス値
printf( asinh(-30.0)=%30.20f\n, asinh(-30.0) );
printf( acosh(-30.0)=%30.20f\n, acosh(-30.0) );
printf( atanh(-0.33)=%30.20f\n, atanh(-0.33) );
printf( \n );
return 0;
}
[実行結果]
asinh(0.0) = 0.00000000000000000000
acosh(0.0) = -1.#IND0000000000000000(無効な値)
atanh(0.0) = 0.00000000000000000000
asinh(+30.0)= 4.09462222433053040000
acosh(+30.0)= 4.09406666863208550000
atanh(+0.33)= 0.34282825441539394000
asinh(-30.0)= -4.09462222433053120000
acosh(-30.0)= -1.#IND0000000000000000(無効な値)
atanh(-0.33)= -0.34282825441539394000
↑
とりあえず Windows 電卓を使って適当な値が一致するのは確認しました。
こんな感じであっていますか?
解決!
ありがとうございました。
>この図では asinh(x)=log(x+√(x^2+1))となってます。
>Alq3 さんの実装では 0 以下と 0 以上の記述がありますね。
>Wikipedia の図が間違ってるのでしょうか?
間違っていません。
ただしlog(x+√(x^2+1))ですと、xが小さくなりすぎると桁落ち誤差が発生するので場
合分けをしています。
>あと Wikipedia の図で acosh(x)=log(x±√(x^2-1))となってます。
>Alq3 さんの実装では『主値のみを返す』となってますが、
>asinh のように 0 以下の処理も書いた方がよいでしょうか?
>どうなのでしょう?
少し計算してみればわかりますが
log(x+√(x^2-1))=-log(x-√(x^2-1))です。
なので二つの値は絶対値が等しい、正負の数なのです。
よって+のほうだけ返せば十分だと思います。
そもそも2つの数を返す電卓っておかしくないですかね。
ちなみに、asinhの場合分けとは全く無関係な話です。