逆双曲線関数の実装方法は? – プログラミング – Home

逆双曲線関数の実装方法は?
 
通知
すべてクリア

[解決済] 逆双曲線関数の実装方法は?


ぴょぴょ
 ぴょぴょ
(@ぴょぴょ)
ゲスト
結合: 17年前
投稿: 82
Topic starter  

また、お世話になります。

現在、新しい関数電卓を作成中です。
むかし、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 以上

新しい関数電卓には逆双曲線関数のボタンを付けいたので
ご存知の方はアドバイスをお願いします。


引用未解決
トピックタグ
YuO
 YuO
(@YuO)
ゲスト
結合: 22年前
投稿: 320
 

> 逆双曲線関数はないのか?
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
とかは,参考になるでしょうか。


返信引用
Alq3
 Alq3
(@Alq3)
ゲスト
結合: 15年前
投稿: 28
 

(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に関数が用意されているようですのでそちらを用いるのもありかと思います。


返信引用
ぴょぴょ
 ぴょぴょ
(@ぴょぴょ)
ゲスト
結合: 17年前
投稿: 82
Topic starter  

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 以下の処理も書いた方がよいでしょうか?
どうなのでしょう?


返信引用
ぴょぴょ
 ぴょぴょ
(@ぴょぴょ)
ゲスト
結合: 17年前
投稿: 82
Topic starter  

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 電卓を使って適当な値が一致するのは確認しました。
こんな感じであっていますか?


返信引用
ぴょぴょ
 ぴょぴょ
(@ぴょぴょ)
ゲスト
結合: 17年前
投稿: 82
Topic starter  

解決!
ありがとうございました。


返信引用
Alq3
 Alq3
(@Alq3)
ゲスト
結合: 15年前
投稿: 28
 

>この図では 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の場合分けとは全く無関係な話です。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました