目標
・リンクーProject Euler
・イミディエイトウィンドウ上でPrjectEulerを解く(Q1~Q10)
・VBEのモジュール上にコードを転記しデバッグを行わないように書けるとなお良し(けれど10問やって2勝8敗くらい)
・イミディエイトウィンドウの可能性を探る
ちなみに
・pythonで一度解いている。
・今回はアルゴリズムよりもイミディエイトウィンドウの使い方に重きを置いたため、分からないところは過去の解答を見た。
イミディエイトウィンドウ上で出来ないこと
・1行で完結しないIF構文
・Forループの中でのIF構文
・Exit Forコマンド、 Exit Doコマンド、つまりループの途中で抜けられない
・Dim、Redimでの宣言。配列を用意できない?
解答
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
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
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の優しさを感じる)
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防止の宣言チェック)無しに使ってはいけなかった
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
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という変数名は分かりづらい
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列目が必要ない。
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
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
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はコレクションを使っても現実的な処理時間になりそうな気がする。
・そうだとしたら無理に配列を使わなくても良かったかも