20211128のJavaに関する記事は6件です。

FizzBuzzは無慈悲な面接の女王

この記事はFOLIOアドベントカレンダー2021の5日目です1 創世記 最初にnandがあった。nandは神であった。 (defn nand [x y] 神) (deftest nand-test (testing "nand" (is (true? (nand false false))) (is (true? (nand false true))) (is (true? (nand true false))) (is (false? (nand true true))))) ジム・ケラーが「光あれ」と言った。するとnotがあった。 (defn not [x] (nand x x)) 2日目、光は世界をandとorに分けた。 (defn and [x y] (not (nand x y))) (defn or [x y] (nand (not x) (not y))) 3日目、神は「nandの上にxorを作れ」と言った。そしてそのようになった。 (defn xor [x y] (and (or x y) (nand x y))) 4日目、神は選択肢を作った。 (defn mux [x y select] (or (and x (not select)) (and y select))) (defn dmux [in select] [(and in (not select)) (and in select)]) 4日目、神は、複数の引数を持つようにした。 (defn and3 [x y z] (and x (and y z))) (defn and4 [a b c d] (and (and a b) (and c d))) (defn or3 [x y z] (or x (or y z))) (defn or4 [x0 x1 x2 x3] (or (or x0 x1) (or x2 x3))) (defn mux8 [a b c d e f g h select] (let [[s0 s1 s2] select] (or8-1 [(and4 a (not s0) (not s1) (not s2)) (and4 b s0 (not s1) (not s2)) (and4 c (not s0) s1 (not s2)) (and4 d s0 s1 (not s2)) (and4 e (not s0) (not s1) s2) (and4 f s0 (not s1) s2) (and4 g (not s0) s1 s2) (and4 h s0 s1 s2)]))) (defn dmux8 [in select] (let [[s0 s1 s2] select and4 (fn [i0 i1 i2 i3] (and (and i0 i1) (and i2 i3)))] [(and4 in (not s0) (not s1) (not s2)) (and4 in s0 (not s1) (not s2)) (and4 in (not s0) s1 (not s2)) (and4 in s0 s1 (not s2)) (and4 in (not s0) (not s1) s2) (and4 in s0 (not s1) s2) (and4 in (not s0) s1 s2) (and4 in s0 s1 s2)])) 6日目、神は「16bitを使え」と命じた。 (defn not16bit [in] (let [[in0 in1 in2 in3 in4 in5 in6 in7 in8 in9 in10 in11 in12 in13 in14 in15] in] [(not in0) (not in1) (not in2) (not in3) (not in4) (not in5) (not in6) (not in7) (not in8) (not in9) (not in10) (not in11) (not in12) (not in13) (not in14) (not in15)])) (defn and16bit [x y] (let [[x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15] x [y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15] y] [(and x0 y0) (and x1 y1) (and x2 y2) (and x3 y3) (and x4 y4) (and x5 y5) (and x6 y6) (and x7 y7) (and x8 y8) (and x9 y9) (and x10 y10) (and x11 y11) (and x12 y12) (and x13 y13) (and x14 y14) (and x15 y15)])) (defn or16bit [x y] (let [[x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15] x [y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15] y] [(or x0 y0) (or x1 y1) (or x2 y2) (or x3 y3) (or x4 y4) (or x5 y5) (or x6 y6) (or x7 y7) (or x8 y8) (or x9 y9) (or x10 y10) (or x11 y11) (or x12 y12) (or x13 y13) (or x14 y14) (or x15 y15)])) (defn mux16bit [x y select] (let [[x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15] x [y0 y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11 y12 y13 y14 y15] y] [(mux x0 y0 select) (mux x1 y1 select) (mux x2 y2 select) (mux x3 y3 select) (mux x4 y4 select) (mux x5 y5 select) (mux x6 y6 select) (mux x7 y7 select) (mux x8 y8 select) (mux x9 y9 select) (mux x10 y10 select) (mux x11 y11 select) (mux x12 y12 select) (mux x13 y13 select) (mux x14 y14 select) (mux x15 y15 select)])) 7日目、神はブラック企業勤めだったので有休をもらえなかった。 天岩戸 高天原にいた天照大御神は、度重なる須佐之男の狼藉に耐え兼ね、天岩戸に隠れてしまった。こうして順序回路が生まれた。2 (defn make-register [] (let [r (ref false)] (fn [in load] (if load 岩戸に隠れる) 岩戸から出てくる)))) (deftest make-register-test (testing "register" (is (false? (let [r (make-register)] (r false true) (r false false)))) (is (false? (let [r (make-register)] (r false true) (r true false)))) (is (true? (let [r (make-register)] (r true true) (r false true)))) (is (true? (let [r (make-register)] (r true true) (r true true)))))) 神々は、隠れたアマテラスに出てきてもらうため、レジスターをたくさん並べてメモリーを作った。 (defn make-register16 [] (let [r0 (make-register) r1 (make-register) r2 (make-register) r3 (make-register) r4 (make-register) r5 (make-register) r6 (make-register) r7 (make-register) r8 (make-register) r9 (make-register) r10 (make-register) r11 (make-register) r12 (make-register) r13 (make-register) r14 (make-register) r15 (make-register)] (fn [in load] (let [[in0 in1 in2 in3 in4 in5 in6 in7 in8 in9 in10 in11 in12 in13 in14 in15] in] [(r0 in0 load) (r1 in1 load) (r2 in2 load) (r3 in3 load) (r4 in4 load) (r5 in5 load) (r6 in6 load) (r7 in7 load) (r8 in8 load) (r9 in9 load) (r10 in10 load) (r11 in11 load) (r12 in12 load) (r13 in13 load) (r14 in14 load) (r15 in15 load)])))) (defn make-ram8 [] (let [r0 (make-register16) r1 (make-register16) r2 (make-register16) r3 (make-register16) r4 (make-register16) r5 (make-register16) r6 (make-register16) r7 (make-register16)] (fn [in addr load] (let [[l0 l1 l2 l3 l4 l5 l6 l7] (dmux8 load addr) ro0 (r0 in l0) ro1 (r1 in l1) ro2 (r2 in l2) ro3 (r3 in l3) ro4 (r4 in l4) ro5 (r5 in l5) ro6 (r6 in l6) ro7 (r7 in l7)] (mux16bit-8 ro0 ro1 ro2 ro3 ro4 ro5 ro6 ro7 addr))))) 国生み神話 伊邪那岐と伊邪那美は結婚し、ALUを完成させるよう命ぜられた。二柱は天沼矛で地上をかき混ぜ、加算器を作った。 (defn half-adder [x y] [(xor x y) (and x y)]) ところが手順に間違いがあって、キャリービットを扱うことができなかった。外部コンサルタントに相談したところ、ブロックチェーンを使うよう勧められた。占いに従ってもう一度やり直したところ、全加算器が生まれた。 (defn full-adder [x y cin] (let [[s0 c0] (half-adder x y) [s1 c1] (half-adder s0 cin)] [s1 (or c0 c1)])) こうして、伊邪那岐と伊邪那美はプロジェクトマネジメントの経験を積み、ALUを作り出した。 (defn alu [x y zx nx zy ny f no] (let [ x-zero (and16bit x (expand16 (not zx))) y-zero (and16bit y (expand16 (not zy))) x-negate (xor16bit x-zero (expand16 nx)) y-negate (xor16bit y-zero (expand16 ny)) [radd] (adder16bit x-negate y-negate false) rand (and16bit x-negate y-negate) out-added (mux16bit rand radd f) out (xor16bit out-added (expand16 no)) zr (not (or16 out)) ng (nth out 15)] [out zr ng])) 34 因幡の白兎 大己貴命がScalaMatsuriに向かっている途中、因幡の国に通りがかった。そこで白い兎が皮を剥がれているのを見つけ、いったいどうしたのか尋ねた。 「私はどうしてもRubyカンファレンスに出たかったのですが、泳がないで島を渡る方法がなかったのです。そこにワニの群れが現れたので、私は彼らを利用しようと思いました。私は彼らに、『RISCとCISCどちらが優れているか競争しよう』と持ち掛け、人力プログラムカウンターとして一列に並んでほしい、と頼みました」。そして数を数えるふりをしながら、彼らを踏み台にして、島を渡ろうとしました。 (defn make-pc [] (let [r (make-register16)] (fn [in inc load reset] (r (mux16bit-4 zero16 zero16 in (inc16bit (r false16 false)) [(or inc (not load)) (not reset)]) (or (or load inc) reset))))) 「ところが渡りきったところで、うっかり『LinuxよりWindowsのほうが普及してるよね』と言ってしまい、怒ったワニは私の皮を剥いでしまったのです」 大己貴命は(それって大概自分が悪くね?)と思ったが、心優しい彼はそう指摘する代わりに、FedoraのCD-Rを兎にプレゼントした。 国造り 大己貴命は須勢理毘売命に惚れ、父親の須佐之男命に結婚を認めてくれるよう頼んだ。ところが須佐之男は、「最近多いんだよねーJAVA5とかちょっとかじった程度で、俺プログラマーやってますって顔する子」と言って結婚を認めなかった。大己貴命はパイソニアンの群れがいる部屋の中に閉じ込められてしまった。しかし、事前に須勢理毘売命に聖杯を授かっていた大己貴命は歴史学者を倒し、CPUを完成させた。 (defn -cpu [a-register d-register pc instruction inM reset disable-loading] (let [ [instruction-type v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15] instruction ; A-instruction [_ exit ; Exit command _ a c1 c2 c3 c4 c5 c6 d1 ; Save to A? d2 ; Save to D? d3 ; Save to M? j1 j2 j3 ] instruction ; C-instruction a-current (a-register dont-care false) d-current (d-register dont-care false) [outM zr ng] (alu d-current (mux16bit a-current inM a) ; if comp-a == true inM else A-register c1 c2 c3 c4 c5 c6) _ (a-register (mux16bit [v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 false] outM instruction-type) (and (or (not instruction-type) d1) (not disable-loading))) _ (d-register outM (and d2 (not disable-loading))) pc-load (and3 instruction-type ; not an a-instruction (or4 (and3 j1 j2 j3) ; 1 1 1; just jump (and j1 ng) ; j1 is true and output < 0 (and j2 zr) ; j2 is true and output is 0 (and j3 (not (or ng zr))) ; j3 is true and output > 0 ) (not disable-loading)) ; not disabled pc-inc (not (or pc-load disable-loading)) ; neither load nor disabled pc-out (pc a-current pc-inc pc-load reset) exit-out (and instruction-type exit) ; c-instruction & exit code is true ] [outM d3 a-current pc-out exit-out] )) (defn make-cpu [] (let [ a-register (make-register16) d-register (make-register16) pc (make-pc) cpu (fn [instruction inM reset disable-loading] (-cpu a-register d-register pc instruction inM reset disable-loading)) ] (fn ([instruction inM reset] (cpu instruction inM reset false)) ([instruction inM reset disable-loading] (cpu instruction inM reset disable-loading))) )) 67 ところが須佐之男は「君、変なところで改行挟む癖あるよね」と難癖をつけ結婚を認めなかった。そこで、須勢理毘売命のプルリクの助けを受けて、コンピューターを完成させた。 (defn console [in load] (if load (print (i2s (ba2i in))))) (defn computer [program-memory] (let [ cpu (make-cpu) ram (make-ram16k) memory (fn [in addr load] (let [[a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14] addr addr-memory [a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13] [l0 l1] (dmux load a14) ro (ram in addr-memory l0) _ (console in l1) ] (mux16bit-4 ro false16 false16 false16 [a13 false]) ) ) ] (loop [] (let [ [_ _ current-address pc] (cpu false16 false16 false true) instruction (program-memory pc) inM (memory false16 current-address false) [outM writeM addressM _ exit] (cpu instruction inM false) ] (memory outM addressM writeM) (if (false? exit) (recur)))))) 8 こうして大己貴命は、須佐之男に結婚を認めさせた。 今日はMPが足りないみたいだ 面接官「特技はLISPとありますが?」 学生 「はい。LISPです。」 面接官「LISPとは何のことですか?」 学生 「魔法です。」 面接官「え、魔法?」 学生 「はい。魔法です。敵全員に大ダメージを与えます。」9 (defn lex [^String code] (filter #(not (blank? %)) (re-seq #"[\w\"]+|[\s\(\)\{\}\;]|\+\+|<=|==|=|%" code))) (defn parse [code] (let [[t0 t1 t2 t3 t4] code] (cond (= t2 "=") {:type "assign" :name t1 :value (parse-value t3) :rest (drop-semi (drop 4 code))} (= t1 "<=") {:type "le" :x (parse-value t0) :y (parse-value t2) :rest (drop-semi (drop 3 code))} (= t1 "++") {:type "inc" :name t0 :rest (drop-semi (drop 2 code))} (and (= t1 "%") (= t3 "==")) {:type "rem" :x (parse-value t0) :y (parse-value t2) :z (parse-value t4) :rest (drop-semi (drop 5 code))} (= t0 "for") (parse-for code) (= t0 "if") (parse-if code) (and (re-matches #"[\w]+" t0) (= t1 "(") (= t3 ")")) {:type "call" :name t0 :arg (parse-value t2) :rest (drop-semi (drop 4 code))} :else (let [v (parse-value t0)] (merge v {:rest (rest code)}))))) 面接官「・・・で、そのLISPは当社において働くうえで何のメリットがあるとお考えですか?」 学生 「はい。オブジェクト指向が襲って来ても守れます。」 面接官「いや、当社には襲ってくるような輩はいません。それに人に危害を加えるのは犯罪ですよね。」 学生 「でも、Smalltalkにも勝てますよ。」 面接官「いや、勝つとかそういう問題じゃなくてですね・・・」 (defn a-inst [in] (into [false] (cond (int? in) (bit15 (i2ba in)) (string? in) (bit15 (s2ba in)) (= 15 (count in)) in ; bit array[15] (= 16 (count in)) (bit15 in)))) ; bit array[16] (defn c-inst ([comp dest] (c-inst false comp dest)) ([a comp dest] (c-inst a comp dest op-no-jump)) ([a comp dest jump] (c-inst [false false] a comp dest jump)) ([ext a comp dest jump] (vec (concat [true] ext [a] comp dest jump)))) (defn compile-for [code var] (let [offset (:offset var) {init :init cond :cond loop :loop body :body} code [op-init var'] (-compile init var) c-op-init (count op-init) [op-cond] (-compile cond (assoc var' :offset (+ offset c-op-init))) c-op-cond (count op-cond) [op-body] (-compile body (assoc var' :offset (+ offset c-op-init c-op-cond 2))) c-op-body (count op-body) [op-loop] (-compile loop (assoc var' :offset (+ offset c-op-init c-op-cond 2 c-op-body))) c-op-loop (count op-loop) ] [(vec (concat op-init op-cond [(a-inst (+ offset c-op-init c-op-cond 2 c-op-body c-op-loop 2)) ; @ the end of the loop (c-inst false op-d op-dest-null op-jeq) ; D,JEQ ; if cond=false jump ] op-body op-loop [(a-inst (+ offset c-op-init)) ; @cond (c-inst false op-0 op-dest-null op-jmp) ; JMP ])) var])) (defn compile-if [code var] (let [offset (:offset var) {cond :cond then :then else :else} code [op-cond] (-compile cond var) c-op-cond (count op-cond) [op-then] (-compile then (assoc var :offset (+ offset c-op-cond 2))) c-op-then (count op-then) [op-else] (-compile else (assoc var :offset (+ offset c-op-cond c-op-then 4))) c-op-else (count op-else) ] [(vec (concat op-cond [(a-inst (+ offset c-op-cond 2 c-op-then 2)) ; A = offset + len(op-cond) + 2 +len(op-then) + 2 (c-inst false op-d op-dest-null op-jeq) ; D,JNE ; if cond = false jump to op-else ] op-then [(a-inst (+ offset c-op-cond 2 c-op-then 2 c-op-else)) ; A = offset + len(op-cond) + 2 + len(op-then) + 2 + len(op-else) (c-inst false op-0 op-dest-null op-jmp)] ; D,JMP ; jump to last op-else )) var])) (defn -compile [code var] (let [type (:type code)] (increment-offset (cond (= type "assign") (compile-assign code var) (= type "int") [(compile-int code) var] (= type "str") (compile-str code var) (= type "ref") (compile-ref code var) (= type "le") (compile-le code var) (= type "inc") (compile-inc code var) (= type "rem") (compile-rem code var) (= type "call") (compile-call code var) (= type "for") (compile-for code var) (= type "if") (compile-if code var))))) 10 学生 「FizzBuzzだって実行できるんですよ。」 面接官「ふざけないでください。それにFizzBuzzって何ですか。だいたい・・・」 (defn -main [] (computer (make-program-memory (compile (parse (lex " for (int i = 1; i <= 100; i++) { if (i % 15 == 0) { println(\"FizzBuzz\"); } else if (i % 5 == 0) { println(\"Buzz\"); } else if (i % 3 == 0) { println(\"Fizz\"); } else { println(i); } } ")))))) (deftest main-test (testing "main" (is (= (str (->> (range 1 101) (map #(match [(rem %1 3) (rem %1 5)] [0 0] "FizzBuzz" [0 _] "Fizz" [_ 0] "Buzz" :else %1) ) (join "\n")) "\n") (with-out-str (-main)))))) 学生 「FizzBuzzです。FizzBuzz問題とも書きます。FizzBuzzというのは・・・」 面接官「聞いてません。帰って下さい。」 学生 「あれあれ?怒らせていいんですか?使いますよ。FizzBuzz。」 面接官「いいですよ。使って下さい。FizzBuzzとやらを。それで満足したら帰って下さい。」 > lein run 1 2 Fizz 4 Buzz ... 学生 「運がよかったな。今日はRAMが足りないみたいだ。」 面接官「帰れよ。」 クレジット ソースコード 本記事は、AphyrのRewriting the Technical Interviewに直接の着想を得ている。11 実装詳細の大部分は、『コンピュータシステムの理論と実装』によるところが大きい。 この記事はあくまで個人の見解であり、所属会社の立場を表すものではない。念のため。 ↩ 本記事では、nandとmake-registerの二つをプリミティブなコンポーネントとして使用する。 ↩ 出典:Noam Nisan, Shimon Schocken『コンピュータシステムの理論と実装』 ↩ nthを使っているが、引数が定数なのでずるではない。 ↩ 「Javaだろ!」とお怒りの方は、誤字脱字に寛容になろう ↩ 『コンピュータシステムの理論と実装』に加え、C命令の2bit目を終了コマンドとして使用している。 ↩ きちんとコードを読んだ人は(そんな人はいないだろうが)、レジスターを二回呼び出していることにお気づきだろう。これは、電気の流れを関数の呼び出しとして表現しているためである。組み合わせ回路の即座に変更されるべき値と、順序回路の呼び出しに従って変わるべき値の、信号が巡回して帰ってくるというもともとの意味の『回路』を再現しているのである……というのは建前で、コードの美しさのため1クロック=1回の関数呼び出しとしたかったのだが、アドベントカレンダーの〆切的に無理だったので断念した。disable-loadingはその「読み取り」の際に、レジスターを更新しないようにするため追加したフラグである。 ↩ コンソールはハードウェアなので直接printを呼んでいる ↩ この記事の作者はClojureが全く書けないのである。本物のLISPerであればマクロを使うところだ。 ↩ 「スタックマシンを使えよ」というお怒りはもっともである。 ↩ Hexing the Technical Interviewの解説を読みたい人は、本記事の筆者のホームページを見よう! ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Intellijでjlinkビルドエラーが出たとき文字化けした話

Intellij IDEA Ultimateを使ってJavaFXアプリケーションを開発しているとき、jlinkを使ってビルドしたくなって設定にclean javafx:jlinkと入力した。 そしたらなんと!!エラーが出てビルドが失敗してしまったのだ... エラーを読んでググって解決すればいいと思ってエラー文を見ると [WARNING] Required filename-based automodules detected. Please don't publish this project to a public artifact repository! �G���[: jlink�ł͎������W���[���͎g�p�ł��܂���: file:///C:/Users/mfmii/.m2/repository/net/synedra/validatorfx/0.1.13/validatorfx-0.1.13.jar�����validatorfx [ERROR] Command execution failed. ...読めない そう、文字化けが発生してしまったのだ!! 原因を探る コンソール側はUTF8なので、ビルドしたときのエラーメッセージが日本語でUTF8でなかったと思われる。 文字化けした文字コードを解析するとUTF-8なんで、ナニカからUTF8になって文字化けが発生したのだろう。 これはShift_JISだろうと思いネットの文字化け修正サイトで直してみた。しかし... string(265) "?スG?ス?ス?ス[: jlink?スナは趣ソス?ス?ス?ス?ス?スW?ス?ス?ス[?ス?ス?スヘ使?スp?スナゑソス?スワゑソス?ス?ス: file:///C:/Users/mfmii/.m2/repository/net/synedra/validatorfx/0.1.13/validatorfx-0.1.13.jar?ス?ス?ス?ス?スvalidatorfx" 逆に解読不可能になった。 解決策1 とりあえずもじばけらったを使用して総当りしてみる。 結果: 惨敗 もう解読不可なんてレベルじゃないナニかができた 解決策2 Intellij IDEAでjavaの文字コード、言語を切り替えてとりあえず英語でもなんでもいいから出そうとしてみる。 結果: 変わらない どんだけ設定いじっても文字化けしたままだった 解決策3 Intellij IDEAのコンソール出力をShift_JISに切り替えてみる。 結果: どうやって変えるのかわからない 教えて下さい... 最終解決策 Intellij IDEAを使わずにコマンドプロンプトから実行する。 cd /d G:\...\demo\ C:\Users\mfmii\.jdks\adopt-openjdk-11.0.12\bin\java.exe <省略> clean javafx:jlink 結果: できた 結局Shift_JISで正しかったらしい ちなみにエラーはこいつだった エラー: jlinkでは自動モジュールは使用できません: file:///C:/Users/mfmii/.m2/repository/org/yaml/snakeyaml/1.29/snakeyaml-1.29.jarからのorg.yaml.snakeyaml このためにテスト前の貴重な時間の3時間かけたのにこのオチだとなんか悲しいかな...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker 環境で Jetty または Tomcat を使って Webアプリを実行する。

前提 Windows環境 「c:\usr\webapps」にWARを配置しておく。 コマンド Jetty 最新版を利用する場合 docker run --rm -it -p 8000:8000 -p 8080:8080 -v c:/usr/webapps:/var/lib/jetty/webapps jetty Tomcat 9.0 を利用する場合 docker run --rm -it -p 8000:8000 -p 8080:8080 -v c:/usr/webapps:/usr/local/tomcat/webapps tomcat:9.0 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoder229をやった(Java)

AtCoder229をやった。 AとB問題の解答例だけみたけど、やっぱり自分はまだまだだなとしみじみと思う。 A 【#(黒)】と【.(白)】の場合分け問題 "辺"としてみたときに隣り合っていたら、"Yes"を違う場合は"No"を出力する。 全パターン列挙でもよい。 私の場合は、全パターン列挙に近いが、途中で場合分けをした。 例えば、以下のYesの入力例 1)  2)  3)  4) ##  #.  #.  ## ##  #.  ##  .. 1と2はリスト型のHashSet()を使えば重複削除により、1ラインとして扱うことができます。 その場合は【#】が含まれていれば"Yes"です。 4は、1と2以外として扱うため、上下が逆でも"Yes"になります。 最後に3は、1と2以外として扱うけど、【#】の個数をカウントして3以上だと"Yes"を出すロジックとなっています。 import java.util.*; public class Main { public static void main(String[] args) throws Exception { // Your code here! Scanner scan = new Scanner(System.in); ArrayList<String> list = new ArrayList<String>(); while (scan.hasNextLine()) { String str = scan.nextLine(); list.add(str); } Set<String> set = new HashSet<String>(list); int cnt = 0; if(set.size() == 1){ if(list.get(0).split("")[0].equals("#") || list.get(0).split("")[1].equals("#")){ System.out.println("Yes"); }else{ System.out.println("No"); } } else { if(list.get(0).split("")[0].equals("#") && list.get(0).split("")[1].equals("#") || list.get(1).split("")[0].equals("#") && list.get(1).split("")[1].equals("#") ){ System.out.println("Yes"); } else { for(int i = 0; i < list.size(); i++){ if(list.get(i).split("")[0].equals(".")){ cnt++; } if(list.get(i).split("")[1].equals(".")){ cnt++; } } if(cnt >= 2){ System.out.println("No"); } } } } } B 数値として考えると大変なので、文字列として考えてあげるのがよさそう。 桁違いの場合、特に桁多い側はその分1~9の値でくるので、それは繰り上がりしないし、 事前に排除してループを回してあげればいいような気がします。 ※コメントは後で付けました。気にしないでください。 import java.util.*; public class Main { public static void main(String[] args) throws Exception { // Your code here! Scanner scan = new Scanner(System.in); ArrayList<String> list = new ArrayList<String>(); String str = scan.nextLine(); list.add(str); String[] strIndex = new String[2]; boolean flg = true; for(int i = 0; i < 2; i++){ strIndex[i] = list.get(0).split(" ")[i]; } /* 桁数が同じの場合 ex) 328 + 620 * else if 一つ目の桁数が二つ目の桁数より小さい場合 ex) 28 + 620 * else if 一つ目の桁数が二つ目の桁数より大きい場合 ex) 1328 + 620 */ if(strIndex[0].length() == strIndex[1].length()){ for(int i = 0; i < strIndex[0].length(); i++){ int cnt = Integer.parseInt(strIndex[0].substring(i, i+1)) + Integer.parseInt(strIndex[1].substring(i, i+1)); if(cnt >= 10){ flg = false; break; } } } else if(strIndex[0].length() < strIndex[1].length()) { int strLength = strIndex[1].length() - strIndex[0].length(); strIndex[1] = strIndex[1].substring(strLength, strIndex[1].length()); for(int i = 0; i < strIndex[0].length(); i++){ int cnt = Integer.parseInt(strIndex[0].substring(i, i+1)) + Integer.parseInt(strIndex[1].substring(i, i+1)); if(cnt >= 10){ flg = false; break; } } } else if(strIndex[0].length() > strIndex[1].length()) { int strLength = strIndex[0].length() - strIndex[1].length(); strIndex[0] = strIndex[0].substring(strLength, strIndex[0].length()); for(int i = 0; i < strIndex[0].length(); i++){ int cnt = Integer.parseInt(strIndex[0].substring(i, i+1)) + Integer.parseInt(strIndex[1].substring(i, i+1)); if(cnt >= 10){ flg = false; break; } } } if(flg){ System.out.println("Easy"); } else { System.out.println("Hard"); } } } いつかC問題もJavaで解きたいな(n回目)。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでOutOfMemoryError: GC Overhead limit exceededを穏当に解決した話

この記事は、シアトルコンサルティング株式会社 Advent Calendar 2021の3日目の記事です。 こんにちは、シアトルコンサルティングの長岡です。 はじめに 業務で1000万件くらいのデータに対し、DB1のデータをマスタDBと比較し、一致したデータがあれば別名に変換しDB2へ出力するというようなプログラムを作成し実行した際に、OutOfMemoryError: GC Overhead limit exceededが発生し、現場メンバー揃って苦戦したのでその時のことを書いていこうと思います。 OutOfMemoryError: GC Overhead limit exceededとは Javaのヒープ領域にオブジェクトを割り当てるための十分な空間がない時に発生するエラーです。 冒頭でも触れた通り、処理すべきデータ量が膨大な時に頻発します。 JavaプロセスがGCの実行時間の98%以上を費やし、各実行で2%未満のヒープしか回復されない場合に、このエラーをスローするように設定されているみたいです。 試した事 調べてみるとヒープ領域のデフォルトサイズが512MBみたいだったので、JVMの起動時に-Xmx3Gを指定して、実行してみました。 すると数時間動いた末に、再度OutOfMemoryError: GC Overhead limit exceededが発生しました。 スケジュールの関係上あまり余裕が無かった為、対応できませんでしたが、メモリリークが発生しない実装ができれば解決する話です。 結果 試行錯誤は早々に諦めてプログラムで扱うデータ数を指定して分割して実行することにしました。 調べてみると、100万件を過ぎたあたりからプログラムのスローダウンが始まり、処理速度がどんどん落ちている事が分かりました。 その為、プログラムを10個に分けて100万件ずつデータを扱うように修正し、同時進行でプログラムを実行し約1時間で無事データを変換することができました。 さいごに 今回はテストデータを作成する為に作成したプログラムだったので今回のような方法で穏当に解決しましたが、本番アプリケーションのプログラム内で同じようなことが発生した場合は今回のような対応ではなく、メモリリークが起きている原因を特定し、より良いプログラムに修正する必要があると思いました。 今回は1000万件のデータに対し、メモリリークを意識しない実装が原因で起きたエラーだったので、大量のデータを扱うプログラムを組む際はお気を付けください。 参考 ・OutOfMemoryの公式ドキュメント ・参考にした記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのマルチスレッド実装例(後編)(排他制御編)

この記事は、シアトルコンサルティング株式会社 Advent Calendar 2021の2日目の記事です。 こんにちは、シアトルコンサルティングの長岡です。 はじめに 前回はプログラムをマルチスレッドで実行してみました。 Javaのマルチスレッド実装例(前編) 今回はマルチスレッドでプログラムを実行した際の注意点として上げられる、排他制御について書いていこうと思います。 今回も前回同様駆け出しエンジニアの方達にも理解できる内容となっております! なぜ排他制御が必要なのか? 前回の記事でも書きましたが、マルチスレッドの処理で同じオブジェクトにアクセスしてしまうと同じフィールドの値を書き換えてしまう為、最終的に期待した値が帰ってこないことがあります。 その為、同じオブジェクトにアクセスする場合はsynchronizedを使用し、排他制御を実装する必要があります。 排他制御の実装 排他制御を実装するにあたり、まずは排他制御なしでプログラムを動かしてみます。 プログラムの内容は初期値0の共通オブジェクトに対し、1000追加するメソッドを1000スレッドで動かし、最後にオブジェクトの値を出力します。 想定通りの動きをするパターンもある為、上記のプログラムをfor文で10回動かしてみます。 Main.java package main; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Main { public static void main(String[] args) throws InterruptedException { for(int i = 0; i < 10; i++) { Bank.bank = 0; int threadNum = 1000; // 引数に生成するスレッド数を渡す ExecutorService exec = Executors.newFixedThreadPool(threadNum); Callable<String> sub1 = new Sub1(); List<Callable<String>> tasklist = new ArrayList<>(); for(int j = 0; j < threadNum; j++) { tasklist.add(sub1); } List<Future<String>> future = exec.invokeAll(tasklist); System.out.println(Bank.bank); exec.shutdown(); } } } Sub1.java package main; import java.util.concurrent.Callable; public class Sub1 implements Callable<String>{ public void addBank() { Bank.bank += 1000; } @Override public String call() throws Exception { addBank(); return null; } } Bank.java package main; public class Bank { public static int bank = 0; } 出力結果 999000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 一番最初の出力が999000になっていますね。 bankの値が998000のタイミングで同時に1000追加する処理を行った為、このような結果になったのだと思います。 今回の様な結果を防ぐ為、排他制御を実装していきます。 排他制御の実装は非常に簡単です。 下記の様にスレッドで呼び出すメソッドにsynchronizedをつけるだけです。 Sub1.java public synchronized void addBank() { Bank.bank += 1000; } では、実行してみます。 出力結果 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 1000000 全て想定通り出力されていますね。 参考 ・synchronizedについて
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む