Why is b1 faster than a1 in benchmarking?

このQ&Aのポイント
  • In the benchmarking of a1 and b2, it was found that b1 is slightly faster than a1, even when the positions of the function groups a and b are reversed. The benchmarking was performed by counting 10,000,000 times.
  • The local operator is used to temporarily change the values of special symbols such as $_. In the past, it was mentioned in the 'camel book' that this extra work of using local would take more time. However, the benchmarking results show that b1 is faster.
  • The reason behind this unexpected result lies in the internal workings of the local operator and the specific example chosen for benchmarking.
回答を見る
  • ベストアンサー

$_ と local($_)

sub a1{ $x = "abcd"; &a2(\$x); } sub a2{ ($_) = @_; $$_ =~ s/a/z/g; } sub b1{ $x = "abcd"; &b2(\$x); } sub b2{ local($_) = @_; $$_ =~ s/a/c/g; } で、a1とb2についてベンチマークをとった結果、なぜかb1の方が微妙に速いことがわかりました。a関数郡とb関数郡のソース上の位置を逆転させても結果は同じです。回数は、10000000 回カウントした結果です。期待とは違った結果に驚いています。 localは「$_等の特殊記号に一時的な変更を与える」という意味だ過去によんだ「らくだ本」に書いてあった気がするので、この余分な作業でlocalをしたほうが時間がかかると思っていたのですが・・。 これは内部でどういったことが起こっているのでしょうか? もしくはベンチマークするサブルーチンの例がまずかったでしょうか?

  • ytse
  • お礼率71% (88/123)
  • Perl
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

($_) = @_; の左側は、一時的なリストを作るために余計に時間が掛かるのではないかと思います。

ytse
質問者

お礼

ご指摘いただいた箇所を、 「$_ = $_[0]」と直した所、無事localを使わない方が速くなりました。これですっきりしました、ご回答ありがとうございます。

関連するQ&A

  • 三乗根

     立方根を求める関数と、積分の関数を組み合わせて、x1/3を積分する関数を作りたいのですが、積分範囲は 0から1 0から2 0から3 0から4 4から5 4から6 4から7 4から8 のものを求めたくて、あと一歩のところをどうかいていいか迷っています。 なるべくきれいな形にしたいです。範囲指定をどう表し、また、一番スマートでしょうか。どなたかご指導お願いいたします。。。 (><;)ちなみに下は途中まで出来たプログラムです!! sub cbrt { local($a)=@_; local($x0,$x1); $x0=1; $x1=(2*$x0**3+$a)/(3*$x0**2); while( abs($x1-$x0)> 1.e-15) { $x0=$x1; $x1=(2*$x0**3+$a)/(3*$x0**2); } return $x0; } sub simp { # シンプソン法による積分 local($a, $b, $n)=@_; local($s)=0; local($dx)=($b-$a)/$n; local($x); for($x=$a+$dx; $x<$b; $x += $dx ) { $s += (2*cbrt($x-$dx/2)+cbrt($x))/3; } $s += cbrt($a)/6 -cbrt($b)/6; return $s*$dx; } print simp(0,1,10000/2), "\n";

  • ハッシュリファレンスの未定義

    サブルーチン/ハッシュリ/ファレンスで悩んでいます。 my (@r); $r[1]{"A"} = "1-A"; # 代入 &s(\@r); print $r[1]{"A"},"\n"; # 参照 print $r[2]{"B"},"\n"; # 参照 サブルーチン側でできない。 # sub s() { my ($c)=@_; @$c[1]->{"A"} = "1111-AAAA"; # もちろん代入できる @$c[2]->{"B"} = "2-B"; # 代入 これができない(ハッシュリファレンスの未定義エラー) } サブルーチン側で新規ハッシュのところに代入ができないのですが どのようにすればいいのでしょうか。

    • ベストアンサー
    • Perl
  • Perlで複数の値を返す良い方法はありますか?

    以下のように多重代入できるかと思って確かめましたが、 結果は以下の通りでした。 $a=[] $b=[20] 方法はいろいろとありそうですが、Perl苦手でわかりません。 sub test{ local $cc = ''; local $s = ''; $cc = 'AAAAA'; $s = 20; # return $cc, $s; } $a, $b = &test; print "\$a=[$a]\n"; print "\$b=[$b]\n"; exit; __END__

    • ベストアンサー
    • Perl
  • 関数へのポインタで

    関数を場合によって使い分けたくて, 次のようにしています. double f1(double x) { return 3*x; } double f2(double x) { return 5*x; } double f3(double x) { return 10*x } /* 同じようにg1, g2, g3があります. */ 次のようなルーチンを使って, void sub(double (*F)(double), ...) { F(a); F(b); } int main() { double (*func_f[])(double)={f1, f2, f3}; double (*func_g[])(double)={g1, g2, g3}; sub(func_f[i], ...) } といった感じにしています. いま,f1*g2のような関数に対してsubを使いたいのですが,この場合はどのようにすればいいのでしょうか? (f1*g2)を一つの関数として扱えることができればいいと思うのですが,方法がわかりません. 教えて下さい. よろしくお願いします.

  • Arctantとtの極限

    C1:(x/a)^2+(y/b)^2≦1 C2:(x/b)^2+(y/a)^2≦1 (0<b<a)とし C1とC2の共通部分の面積をSとする g(x)=Arctanx t=b/a としたときに S/b^2をtとg(t)を用いて表し limS/b^2 t→0 を求めよ 解法では 0≦x 0≦y y≦x とSの共通部分が 1/8Sになるので 0≦x 0≦y y≦(b/a)x x^2+y^2≦b^2 の部分の面積1/2g(t)b^2 をa/b倍したものが1/8Sで S=4g(t)/t limS/b^2=4g'(0)=4 t→0 となるのですが 1/8S=1/2(ab/√(a^2+b^2))^2+a^2/b^2[ab/√(a^2+b^2),b]∫√(b^2-x^2)dx から Arcsina/√(a^2+b^2)=g(1/t) g(1/t)=π/2-g(t) なので S/b^2=4/(1+t^2)-{(1+t^2)g(t)-t}/t^2(1+t^2) これをt→0とすると lim(Arctant-t)/t^2 t→0 が不定形となってしまいます。 ロピタルの定理を使えば0に収束しますし Arctanxの級数展開を利用しても0に収束することは言えるのですが 大学受験の問題なのでできれば高校範囲で示したいのです。。。 (そもそも逆三角関数が出てきた段階で高校逸脱範囲なのだと思うのですが。。) なにかいい案をお持ちでしょうか?

  • fortran90 引数で渡された関数の呼び出し

    fortran90を始めて間もない者です。 メインプログラムより呼び出しているサブルーチンにユーザ関数を渡しています。 このサブルーチンを自前で作成するのが目的です。 引数で受け取った関数を、自前の別関数より呼び出すにはどうしたら良いでしょうか。 Cであれば関数のポインタをグローバルな変数にセットしてやれば可能だと思いますが・・・ !-------------------------------- subroutine sub(func1, a) real::a interface real function func1(x) real::x end function func1 real function func2(x) real x end function func2 end interface call sub2(func2, a) write(*,*) a return end subroutine sub !-------------------------------- real function func2(x) real::func2, x ! ここでfunc1を呼び出したい ! func2=func1(x) end function func2 !-------------------------------- subroutine sub2(funca, a) real::a interface real function funca(x) real::x end function funca end interface a=funca(10.) return end !-------------------------------- program main external func real a call sub(func, a) write(*,*) a end program !-------------------------------- function func(x) real func, x func=2.*x*x end function func

  • こういった文法構造はありうるの?

    # サブルーチンの宣言と定義 sub func { .... } # ここからすぐ下に { がくる { ....(仮にここをA部とします) } このように、サブルーチンの直後に、{ で始まるのは、文法上ありうるのでしょうか? CGIの中の一部です。 ちなみに、localで -wc とかつけて確認するとエラーにはなりません。 この場合、サブルーチン直後のA部は、どのようにプログラムが走るものなのでしょうか。 A部で、サブルーチンを呼んでもいません。 上手く説明できませんが、よろしくお願いします。

    • ベストアンサー
    • Perl
  • コーシーの平均値の定理の証明(高校数学)

    2つの関数f(x)g(x)が[a,b]で連続、(a,b)において微分可能であるとする。 g(a)≠g(b)かつ(a,b)でg´(x)≠0のとき、 a<c<bかつ {f(b)-f(a)}/{g(b)-g(a)}=f´(c)/g´(c) を満たす実数cがそんざいする。 証明についてその最初に k={f(b)-f(a)}/{g(b)-g(a)}とする F(x)=f(b)-f(x)-k{g(b)-g(x)}とする関数F(x)を考えるとあるのですが、 どのようにかんがえて関数F(x)というものを発想したのでしょうか? 理論的背景など教えてください

  • JavaScriptでPerlのサブルーチンを呼び出すには?

    JavaScriptでPerlのサブルーチンを呼び出すことはできますか。 #Perl Sub Func_a(){ ... } この Func_a 関数をJavaScriptから呼び出したいのです。

  • 四次式の接線

    四次関数f(x)と一次関数g(x)が相異なる二点で接するとき 二接点のx座標をa,b(a<b)とすると f(x)-g(x)=(x-a)^2*(x-b)^2であるから… と解説にあるのですが、両方とも二乗でないといけませんか? (x-a)(x-b)^3としてはいけないのでしょうか?

専門家に質問してみよう