Help us understand the problem. What is going on with this article?

Project Euler vba イミディエイトウィンドウ

More than 1 year has passed since last update.

目標

リンクーProject Euler
・イミディエイトウィンドウ上でPrjectEulerを解く(Q1~Q10)
・VBEのモジュール上にコードを転記しデバッグを行わないように書けるとなお良し(けれど10問やって2勝8敗くらい)
・イミディエイトウィンドウの可能性を探る

ちなみに

・pythonで一度解いている。
・今回はアルゴリズムよりもイミディエイトウィンドウの使い方に重きを置いたため、分からないところは過去の解答を見た。

イミディエイトウィンドウ上で出来ないこと

1行で完結しないIF構文
Forループの中でのIF構文
Exit Forコマンド、 Exit Doコマンド、つまりループの途中で抜けられない
Dim、Redimでの宣言。配列を用意できない?

解答

Proplem1
loopMax = 1000
sum=0: For i = 1 to loopMax - 1: sum=sum+iif(i mod 3 = 0 or i mod 5 = 0,i,0): next i
?sum
Proplem2
f=1:ff=2:loopMax=10000:Max=4000000:sum=2
For i = 3 to loopMax: fi = f + ff: f = ff: ff = fi: isEven = (fi mod 2 = 0):sum = sum + iif(isEven, fi, 0):exitFlag = (fi > max): select Case exitFlag: case True: i = loopMax: end select:next i
?sum
Proplem3
a=600851475143:set primeFactors = new Collection:loopMax = int(sqr(a)):
for i = 2 to loopMax:isFactor = a/i = int(a/i):do while isFactor:primeFactors.add i:a= a/i:isFactor = a/i =int(a/i):loop:next i
For Each pf in primefactors: ?pf : Next: 

Problem3ポイント

・600851475143はLong型(4byte整数)の範囲を超えているので、計算はDouble型で行う
・本当はisFacotr = (a mod i = 0)としたい
・Double型(8byte)の有効数字は2進数で52Bit、10進数で15-16桁くらい
・13桁未満の割り算で余りの有無を確認するのには大丈夫(projectEulerの優しさを感じる)

Proplem4
For i = 100 to 999: For j = 100 to 999: a = cstr(i * j): isPalindrome = True: For k = 1 to len(a) \ 2: Select Case mid(a,k,1) <> mid(a,len(a) + 1 - k, 1): Case True: isPalindrome = False: End Select: Next k: Select Case isPalindrome And i * j > maxPalindromeNumber:Case True: maxPalindromeNumber = i * j:End Select:next j:next i
?maxPalindromeNumber

Problem4ポイント

・maxPalindromeNumberのような長い変数名はVBEの支援機能(自動補完,typo防止の宣言チェック)無しに使ってはいけなかった

Proplem5
Ans = 6: For i = 4 to 20: a = Ans: b = i: Do while b <> 0: c = a mod b: a = b: b = c:Loop: Ans = Ans * i / a:Next i
?ans
Proplem6
Sum = 0:SquaredSum = 0: For i = 1 to 100: Sum = Sum + i: SquaredSum = SquaredSum + i ^ 2:Next i
SumSquared = Sum ^ 2
?SumSquared - SquaredSum

・SumSquaredとSquaredSumという変数名は分かりづらい

Proplem7
set a = excel.Workbooks.Add:msgbox "少し待つ": b = a.worksheets(1).range("A1:B1000000").value
?typename(b)
Variant()
For i = 1 to 1000000:b(i,1) = True:b(i,2) = i:next i
cnt = 0: For i = 2 to 1000000:select Case b(i,1):Case True:cnt = cnt + 1:For j = i*2 to 1000000 step i:b(j,1) =false:next j:end select:select case cnt >= 10001:case true: ans = i:i = 1000000:end select:next i
?ans
a.close 

Problem7ポイント

・Problem10を見据えて高速化の為、エラトステネスの篩のアルゴリズムを使う
・今回はセル配列をコピーすることで配列を用意する。
・10万-100万くらいの配列を用意する方法は他に思いつかなかった。
・コレクションは速度的に不利そう(特にProblem10はpythonの時に処理速度が問題になった)ので採用しなかった。
・2回に一回くらいaとbがEmptyになってる(謎)
・Problem10やってから気づいたけれど2列目が必要ない。

Proplem8
a="7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
For i = 1 to 1000 - 12: b=1 :for j = 0 to 12: b = b * clng(mid(a,i+j,1)):next j:max = worksheetfunction.Max(b,max):next i
?max
Proplem9
For a = 1 to 333:For b = 1 to 500:c = 1000 - b - a:select case b > a and a^2 + b^2 = c^2 :case true:Ans=array(a,b,c):end select :next b:next a 
e=1:for each d in ans:?d:e=e*d:next:?"ans=" & e
Proplem10
set a = excel.Workbooks.Add:msgbox "少し待つ": b = a.worksheets(1).range("A1:B1000000").value
?typename(b)
Variant()
For i = 1 to 1000000:b(i,1) = True:b(i,2) = i*2+1:next i
sum = 2:For i = 1 to 1000000:select Case b(i,1):Case True:sum = sum +b(i,2):For j = i+b(i,2) to 1000000 step b(i,2):b(j,1) =false:next j:end select:next i
?sum
a.close

Problem10ポイント

・セルの最大値が1048576だったので200万の配列は用意出来なかった。

感想

・今回の挑戦によりいくつか再発見が出来た。
・イミディエイトウィンドウでさらさら書くにはアルゴリズムが頭の中で十分に整理出来ている必要がある。
・その上で文法ミス等なく一発でかけるには更に精進が必要
・Problem7とProblem10はコレクションを使っても現実的な処理時間になりそうな気がする。
・そうだとしたら無理に配列を使わなくても良かったかも

ryo_ryo
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away