質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Q&A

解決済

1回答

2339閲覧

Golangの以下のコードにおいて、再帰関数のほうが単純なFor文より早い理由

RheoTommy

総合スコア13

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

0グッド

0クリップ

投稿2019/12/21 11:19

編集2019/12/21 11:27

前提

比較する2つの関数はmainに定義されているsolvesolve2です。また、solveは関数内でdivideByTwoを参照しています。
実行時間の計測にはtime.Nowを用いました。
テストケースは乱数を用いて作成しています。

自分なりの推測

最初は再帰関数のほうが、関数参照の分遅くなると考えていましたが、実際には違いました。
2つの計算量が異なっている場合は教えてください。(計算量の違いはパット見ではわかりませんでした。)

これは計算量が同じである場合の推測ですが、solve2関数内のifにおいて、毎回int(math.Pow(2, float64(k))という型変換とべき乗計算を行っているのが実行時間が遅い要因担っているのかもしれません。

しかし、それにしても2つのケースで決定的に実行速度が違うので、どこかで計算量の差異があるのではと考えています。

実行結果

console

1200 29099523047102087168 8881098465174618112 2080663027845169152 4571153621781053440 2344123606046343168 1485061977125421056 4983232987685453824 2860911663287107584 514536257427079168 3716595592487501824 782500435255623680 -8863084066665136128 9190720939556339712 5730830525828956160 5324380659458768896 3687322194909593600 1364590687093260288 1628051265294434304 3645663898356416512 -8193173622093774848 558446353793941504 6155294790708625408 1721500957562372096 7047007516927983616 9061242450269437952 -7246291800439128064 -9115285645797883904 3252724830868340736 3142386639997763584 3395714119037353984 6239737283721822208 460493061898633216 8318148511753306112 7692148163548807168 6113636494155448320 6031445800955936768 1956814038092480512 711568741124538368 1673087261568139264 5659898831697870848 7221522002488590336 3480156612050550784 5849050016047431680 635007547459239936 2740440373254946816 4670232813583204352 4592545720011063296 4869517097094348800 6935543426150563840 1524468473864912896 2204512017597857792 4190599453268246528 8095220330198466560 2476979795053772800 3378825620434714624 -8644659484737667072 3252724830868340736 5110459677158670336 -7521011377708728320 -7912824545289961472 2760706571578114048 -8864209966571978752 2934095157231878144 176766285374291968 -9138929543841579008 -7380273889353400320 6262255281858674688 8109857028987420672 5386305154335113216 6470546764624560128 1760907454301863936 4928063892250165248 -8310267212405407744 -7504122879106088960 6133902692478615552 5736460025363169280 1776670052997660672 8403716904673345536 9003821555020464128 7229403301836488704 -8736983277098762240 1074108511127863296 1281274093986906112 3528570308044783616 -8041177134670020608 67553994410557440 3415980317360521216 -8714465278961909760 4382002437431492608 2255177513405775872 -8449878800853893120 -7934216643519971328 2867667062728163328 -8192047722186932224 8940771160237277184 7322852994104426496 622622648483971072 -7363385390750760960 2483735194494828544 1800313951041355776 8360932708213325824 1522216674051227648 1706864258773417984 -7460212782739226624 4152318856435597312 9019584153716260864 3840444582240190464 5951506907570110464 -8774137974024568832 4090394361559252992 3489163811305291776 -8815796270577745920 -8773012074117726208 -8783145173279309824 6062970998347530240 1461418079081725952 -8011903737092112384 6910773628200026112 -8007400137464741888 6637179950837268480 8699828580172955648 6533597159407747072 4483333429047328768 2341871806232657920 2327235107443703808 1431018781596975104 556194553980256256 3475653012423180288 -7390406988514983936 -8333911110449102848 6815072136118403072 8079457731502669824 5501146944833060864 6430014367978225664 1562749070697562112 4222124650659840000 1721500957562372096 3173911837389357056 4937071091504906240 8899112863684100096 1379227385882214400 5120592776320253952 4067876363422400512 1726004557189742592 4072379963049771008 8827055269646172160 609111849601859584 6515582760898265088 7939846143054184448 9093893547567874048 4099401560813993984 8277616115106971648 -8488159397686542336 410953465997557760 2596325185179090944 -8106479329266892800 5406571352658280448 102456891522678784 1804817550668726272 2543407889557487616 4242390848983007232 3638908498915360768 8533195393960247296 9181713740301598720 8807914971229847552 1378101485975371776 8267483015945388032 4738912707900604416 8718968878589280256 2216896916573126656 1313925191285342208 4178214554292977664 5107081977438142464 496521858917597184 5522539043063070720 3561221405343219712 5244441766072942592 4971973988617027584 -7894810146780479488 3422735716801576960 3862962580377042944 -7734932360008826880 -7524389077429256192 1531223873305968640 7567173273889275904 882705526964617216 980658818859925504 3360811221925232640 -9160321642071588864 9019584153716260864 637259347272925184 4687121312185843712 7689896363735121920 8918253162100424704 2306968909120536576 7607705670535610368 6413125869375586304 -8688569581104529408 6981705322331111424 -7799108654698856448 350 time: 0.000229423 450 time: 0.001806263 5

main関数

go

1package main 2 3import ( 4 "bufio" 5 "fmt" 6 "math" 7 "os" 8 "strconv" 9 "time" 10) 11 12func main() { 13 sc := bufio.NewScanner(os.Stdin) 14 sc.Split(bufio.ScanWords) 15 sc.Scan() 16 17 n, _ := strconv.Atoi(sc.Text()) 18 19 nums := make([]int, n) 20 21 for i := 0; i < n; i++ { 22 sc.Scan() 23 k, _ := strconv.Atoi(sc.Text()) 24 nums[i] = k 25 } 26 27 t0 := time.Now() 28 ans, _ := solve(0, nums) 29 t1 := time.Now() 30 fmt.Println(ans, " time:", t1.Sub(t0).Seconds()) 31 32 t2:=time.Now() 33 ans2:=solveAtOnce(nums) 34 t3:=time.Now() 35 fmt.Println(ans2," time:",t3.Sub(t2).Seconds()) 36} 37 38func divideByTwo(nums []int) ([]int, bool) { 39 nums2 := make([]int, len(nums)) 40 for i := 0; i < len(nums); i++ { 41 n := nums[i] 42 if n%2 == 0 { 43 nums2[i] = n / 2 44 } else { 45 return nums, false 46 } 47 } 48 return nums2, true 49} 50 51func solve(i int, nums []int) (int, []int) { 52 nums2, t := divideByTwo(nums) 53 if !t { 54 return i, nums 55 } 56 return solve(i+1, nums2) 57} 58 59func solveAtOnce(nums []int) int { 60 for k := 1; ; k++ { 61 for _, num := range nums { 62 if num%int(math.Pow(2, float64(k))) != 0 { 63 return k - 1 64 } 65 } 66 } 67} 68

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

毎回int(math.Pow(2, float64(k))という型変換とべき乗計算を行っているのが実行時間が遅い要因担っているのかもしれません。

そうだと思います。
(任意の数の)冪乗の計算は非常に遅い命令です(※)。Goの実装は知りませんが、素直に浮動小数点数の冪乗命令を呼んでいるなら、結果に疑問はありません。
たぶんこれはシフトで済みますよね?


2^X-1を計算するF2XM1命令というのがあって、まあ素直に考えるとこの命令を使うことになるのですが、これがこちらの表によると例えばSkylakeで実行に65-80クロック掛かるようです(レイテンシ)。
https://www.agner.org/optimize/instruction_tables.pdf
実際には冪乗の計算はこの命令を使わずにする方法もあるようですが、まあそれで格段に速くなるということもないでしょう。

投稿2019/12/21 17:36

編集2019/12/21 18:33
ikadzuchi

総合スコア3047

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問