Bug #368

境界における Math.atanh 等の動作

Added by Yui NARUSE about 7 years ago. Updated over 4 years ago.

[ruby-dev:35669]
Status:Closed
Priority:Normal
Assignee:Yui NARUSE
ruby -v:1.9.2dev Backport:

Description

=begin
現在の Ruby trunk では、FreeBSD 7 において、
test/ruby/test_math.rb は以下のように失敗します。

y% ruby19 test/ruby/test_math.rb
Loaded suite test/ruby/test_math
Started
......F...........FFF.....
Finished in 0.036791548 seconds.

1) Failure:
test_atanh(TestMath) [test/ruby/test_math.rb:97]:
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.

2) Failure:
test_log(TestMath) [test/ruby/test_math.rb:113]:
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.

3) Failure:
test_log10(TestMath) [test/ruby/test_math.rb:129]:
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.

4) Failure:
test_log2(TestMath) [test/ruby/test_math.rb:121]:
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.

26 tests, 126 assertions, 4 failures, 0 errors

これらの原因はいずれも境界における定義の違いに由来しているものと思わます。

例えば、NetBSD4 だと atanh のマニュアルには以下のようにあり、
atanh(1) は NaN となります。

RETURN VALUES
If |x|>=1, atanh(x) and atanhf(x) return +inf, -inf or NaN, and sets the
global variable errno to EDOM.

しかし、FreeBSD7 では以下のようになっており、atanh(1) は infinity を返します。

RETURN VALUES
The atanh() and the atanhf() functions return the inverse hyperbolic tan-
gent of x if successful. If the argument has absolute value 1, a divide-
by-zero exception is raised and an infinity is returned. If |x| > 1, an
invalid exception is raised and an NaN is returned.

参考:
http://www.hiroshima-cu.ac.jp/japanese/IPC/hunet99/sun/WorkShop/ja/html_docs/common-tools/numerical_comp_guide/standard.doc.html
=end


Related issues

Related to Ruby trunk - Bug #2189: Math.atanh(1) & Math.atanh(-1) should not raise an error Closed 10/10/2009

History

#1 Updated by Yui NARUSE about 7 years ago

=begin
成瀬です。

Tadashi Saito wrote:

気を取り直してSUSv3を見たのですが、atanh(x)の項には

If x is ±1, a pole error shall occur, (...)

とあるので、「errnoを設定しないFreeBSD 7の振る舞いが例外的である」として

Errno::EDOMかErrno::ERANGEを返す

という実装に(Ruby側が)する方が良いのではないでしょうか。

log*(0)についても、同様の記述で

If x is ±0, a pole error shall occur

でした。ので、やはりRuby側が頑張るのが望ましいのではないかと思います。

ふむ、それですと、こんな感じですかね。
変更内容的に副作用が気になっていたりはするんですが。

--- math.c (revision 18249)
+++ math.c (working copy)
@@ -41,7 +41,7 @@ domain_check(double x, const char *msg)
if (errno) {
rb_sys_fail(msg);
}
- if (isnan(x)) {
+ if (isnan(x) || isinf(x)) {
#if defined(EDOM)
errno = EDOM;
#elif defined(ERANGE)
@@ -369,9 +369,7 @@ math_log2(VALUE obj, VALUE x)
Need_Float(x);
errno = 0;
d = log2(RFLOAT_VALUE(x));
- if (errno) {
- rb_sys_fail("log2");
- }
+ domain_check(d, "log2");
return DOUBLE2NUM(d);
}

--
NARUSE, Yui naruse@airemix.jp

=end

#2 Updated by Yui NARUSE about 7 years ago

=begin
成瀬です。

NARUSE, Yui wrote:

ふむ、それですと、こんな感じですかね。
変更内容的に副作用が気になっていたりはするんですが。

副作用があったので、エラーの出る関数個別に、
「引数が Infinity ではないのに 結果が Infinity」な場合を
エラーとするようにしてコミットしました。

--
NARUSE, Yui naruse@airemix.jp

=end

#3 Updated by Yui NARUSE about 7 years ago

=begin
成瀬です。

At Mon, 28 Jul 2008 10:24:31 +0900,
Tadashi Saito wrote:

斎藤と申します。

On Mon, 28 Jul 2008 02:56:45 +0900
Yui NARUSE redmine@ruby-lang.org wrote:

現在の Ruby trunk では、FreeBSD 7 において、
test/ruby/test_math.rb は以下のように失敗します。
(snip)
1) Failure:
test_atanh(TestMath) [test/ruby/test_math.rb:97]:
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.

参考になるか分かりませんが、C99規格(JIS X3010)でも、atanh(1) or atanh(-1) に
ついては「値域エラーが発生する『ことがある』」としか書いておらず、ERANGEがセットされる
保証はないようです。

なるほど。
で、FreeBSDではセットされないケースなのですね。

4) Failure:
例えば、NetBSD4 だと atanh のマニュアルには以下のようにあり、
atanh(1) は NaN となります。
(snip)
しかし、FreeBSD7 では以下のようになっており、atanh(1) は infinity を返します。

テストを見ると、返り値は関係ないと思いますが、どうでしょうか。

あー、これを書いている時点ではMath.atanhの実装が頭にありまして、
そこではCのatanhがerrnoをセットしているか、
NaNだったらErrno::EDOMかErrno::ERANGEを
返すようになっているのですよ。

さておき、Rubyではどこにそろえるのがいいのですかねぇ。
Cの実装をそのまま反映して、例外を投げずにInfinityを返すのでもテストを通すとか?

=end

#4 Updated by Yui NARUSE about 7 years ago

  • Status changed from Open to Closed
  • Assignee set to Yui NARUSE

=begin
例外を投げるようにしました。
=end

#5 Updated by Yui NARUSE almost 6 years ago

  • ruby -v set to 1.9.2dev

=begin
この件ですが、最近コミッタに加わったMarc-Andre Lafortuneさんが、Bug #2189 で仕様変更を提案しています。
ご興味のある方は参加ください。

なお、Redmineがこのチケットに関連する斎藤さんのメールを終えていないのでこちらも参照ください。
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/35669
=end

Also available in: Atom PDF