単位は落としても死なない
本記事について
TUT合同アドベントカレンダーの記事です
毎年メチャクチャ見間違うアドベントカレンダーが今回は合同らしいです。めでたい
しかし僕は別に技術的なことに対して他の人たちより明るくはないので、内容が思いつかないよう〜!wってなりました
なので、最近単位マウントを取られることがあったので、単位を落としても強い心で生きていくための心構えについて書きます。
自己紹介
神奈川県八王子市の方のTUTにいる3年です。
言いたいこと
単位を落としても死なない
単位よりも健康
です。それ以上のこともないです。 残りは単位を落としても死なないので健康のために落とすのはあり、みたいな話をします。
落単について
皆さんご存知の通り、単位をガンガン落とす人は少ないです。 では落としている人は何故単位を落とすのか?そしてそれは一体擁護できるような内容なのか?
落単の主な原因は3つほど挙げられます
- 出席日数が足りない
- テスト等で単位取得条件に達しない
- 気がついたら落ちてる
まず「出席日数が足りない」ですが、擁護できるかと言われるとNO。論外です。授業にでろ。 僕のような昼夜逆転生活にどっぷりみたいな人間でないと授業時間前に起きられないとかないので終わりですね。(というか、普通だったら眠くても授業に出ますね) ただし、病気とかやむを得ない理由があるなら別に問題ないと思います。
次に「テスト等で単位取得条件に達しない」
これは提出したレポートが最悪、成績を決めるテストで基準点に満たなかったので単位を落とすというケースです。
これも擁護不可能です。勉強しろ。以上です。
最後に「気がついたら落ちてる」についてですが、考える余地もありませんね。どういうことなんだ?僕にもわかりません。
と、大雑把にこんな感じですが、もうおわかりでしょう
落単は基本的に自業自得です。
しかし、自業自得なだけに逃げ道が少ない。病気ならまだしも、気づいてたら落ちてたなんてのは逃げようがありません。そんなんで病んでいては終わりです。
ではどうするのか?
単位は落としても死なない。単位より健康を選んだ。
と思い込むことです。
フル単の人間からしたら単位を落とすのはおかしくて、たまに猛烈に嫌味を言ってくる人がイますが、大丈夫です。
人は単位を落としても死にません。
死なないのです、単位を落としても。
それどころか、ヤバそうだと思ったら途中でキレば時間もできて精神的にもいい。 つまり早期落単は精神的にもいい行為であることは明白。
さらに次はどの単位を取ればいい、などの計画も建てられる。 単位を落とすことは実は一石二鳥なんです。
そうやって人は心を取り戻していくのです。
では皆さん、強い心を手に入れて快適なキャンパスライフをお過ごしください。
嘘です。普通に授業にでて単位を取得した方が健康にいいです。しっかりとりましょう。 卒業論文に着手できないとか目も当てられないので。
以上です。
ミリシタ一周年について
イベントが長くて泣いちゃたあ。
逆リファクタリングとfma関数
この記事について
100%ポエムです。あとは微妙な技術的要素。
俺は無知だからfma関数を使い道がよくわからん意味不明の関数だと思ってたんだけど、実際は浮動小数点の高速計算のために使われたり、そのためハードウェア実装されていたり、厳格に仕様があってIntelのCPUではHaswellから実装された最近重要なものだったと知った。
— ワイルド (@while_D_) 2018年4月27日
fma関数と僕
僕が所属しているサークルでは、人生において無意味みたいなことをときたまやっているのですが、先日逆リファクタリングをしようという動きがありました。 ざっくり逆リファクタリングを説明すると、いかにコードを汚くかけるかというもので、クソほどの役にもたちません。
実を言うと去年一度開催してまして、そのときにお世話になったのが記事名にもあるfma関数です。このfma関数は何をしてくれるかと言うと
fma(a, b, c); => a * b + c
といった具合に積和演算をしてくれます。この関数があると逆リファクタリングする際にあることができます。
そう...アラビア数字を1文字も使わなくてよいのです!!
ご存知の通りc++ではtrueが1、falseが0であり、fma関数から任意の数字を作り出すことが可能です。(これ書いてる途中に気がついたんですが、ビット演算ができるから別にfma関数なくても任意の数を作れますね)
以下はほんの一例
fma(fma(true, true, true), fma(true, true, true), true); => 2 * 2 + 1 = 5 fma(true, ~false, ~false) => -2
そもそもこの関数なんのためにあるんだ?
恥知らずなので最近業務でc++を書きはじめてバッドになってる先輩に「数字を使わないでFizzBuzzかけるんですよ〜〜」とか言ったらひとしきり大爆笑した後、謎関数呼ばわり。 気になったので調べてるとどうやらfma関数はC++99の時点であってかなりの古参関数らしい。
こんな掛けて足すだけの関数が本当に重要なのか……?とう疑念を持ちつつも調べていくと、どうやらハードウェアレベルの話でfma系の命令が実装されているっぽいことがわかった。その時は完全にSIMDとかSSEとかに無知だったので意味不明だったのだが、それらを調べると「俺のほうが無知、fmaは偉大みたい」な話に発展。
どうやらfmaをハードウェア側で実装すると丸めの計算が1回に減る上に、大量のベクトル計算ができるから爆速でいいねということだった。
となると当然fma命令を実際に回したかったのだが、僕の環境ではfma命令を入れてくれなかった。俺は偽物のfmaを呼び出して和積を計算。ちゃんとコンパイルオプションつけてコンパイルするとfma関数でfma命令を入れてくれるらしい。
最後に
そんなこんなでサークルのごく一部で無駄に熱いコンテンツになったfma。 そのおかげでCPUのアーキテクチャやマイコンなんかも触りたくなって結構いい感じにテックできたなといった感じです。機会があれば積極的に使っていこうと思います、それでは。
FMA周りが詳しく紹介されているサイト。
FMA (Fused Multiply-Add) について色んな観点でまとめてみた - 小清水さんとコンピューター数学
あと去年書いたコード。
#include <iostream> #include <cmath> using namespace std; int inc(int num); int zero(); int one(); int two(); int three(); int five(); int seven(); int ten(); int sixty_six(); int seventy(); int one_hundred_five(); int one_hundred_seventeen(); int one_hundred_twenty_two(); string Fizz(); string Buzz(); int main(){ for(int i=zero(); i <= fma(ten(), two(), zero()); i = inc(i)){ if(i%three() == zero() && i%five() == zero()) cout << Fizz() << Buzz() << endl; else if(i%three() == zero()) cout << Fizz() << endl; else if(i%five() == zero()) cout << Buzz() << endl; else cout << i << endl; } } int inc(int num) { return fma(num, one(), one()); } int zero(){ return false; } int one(){ return true; } int two(){ return fma(one(), one(), one()); } int three(){ return fma(two(), one(), one()); } int five(){ return fma(three(), one(), two()); } int seven(){ return fma(three(), two(), one()); } int ten(){ return fma(five(), two(), zero()); } int sixty_six(){ return fma(five(), ten(), fma(three(), five(), one())); } int seventy(){ return fma(ten(), seven(), zero()); } int one_hundred_five(){ return fma(ten(), ten(), five()); } int one_hundred_seventeen(){ return fma(one_hundred_five(), one(), fma(ten(), one(), two())); } int one_hundred_twenty_two(){ return fma(one_hundred_five(), one(), fma(ten(), one(), seven())); } string Fizz(){ string fizz; fizz.push_back((char)seventy()); fizz.push_back((char)one_hundred_five()); fizz.push_back((char)one_hundred_twenty_two()); fizz.push_back((char)one_hundred_twenty_two()); return fizz; } string Buzz(){ string buzz; buzz.push_back((char)sixty_six()); buzz.push_back((char)one_hundred_seventeen()); buzz.push_back((char)one_hundred_twenty_two()); buzz.push_back((char)one_hundred_twenty_two()); return buzz; }
蟻本の分割数の問題を整理
目的
僕には何を言っているのかさっぱりだったので、他の方の解説を見ながら整理して理解する
分割数
nをm個以下に順序を区別せずに分割する方法の総数
m=nのとき特にnの分割数と呼ぶ
問題の漸化式
dp[i][j] = dp[i][j-i] + dp[i-1][j]
このdpのメモは、jをi分割したときの総数(dp[i][j] = jをi分割したときの総数)
まずjをi分割するとなったときにi個のものが自動的に最低1の数としてまず確定する
例えば5を3分割した場合、次の2パターン
- 3, 1, 1
- 2, 2, 1
7を4分割した場合、次の3パターン
- 4, 1, 1, 1
- 3, 2, 1, 1
- 2, 2, 2, 1
このときどう分割したところで、それぞれの数は1より下にならない
つまりそれぞれの数から1を引いた数であるj-iの、順序を区別しない並べ方と考えることができる(このときは0を含むので注意)
イメージ的にはi個分の箱を用意して、j-i個のボールを重複のパターンがでないように入れる感じ
上記5を3分割した場合では
- 2, 0, 0
- 1, 1, 0
7を4分割した場合では
- 3, 0, 0, 0
- 2, 1, 0, 0
- 1, 1, 1, 0
実際にパターン数は合致している
最後に後ろのdp[i-1][j]はjのi未満の分割の総数だからそれを足して
dp[i][j] = dp[i][j-i] + dp[i-1][j]
となる
参考サイト
コドフォ初参加
Codeforces#467 div.2にでた
やる気がでてきたのでコドフォに出ました
やる気の維持のために振り返りとか何がわからんかったとかまとめたい
もっとやる気がでたら備忘録的に解説でもしようと思います
A.Olympiad
英語が全然できないので、わかってはいたが英文の問題に戸惑う
英語の読む方に時間かかった
言ってることは割と簡単だったので、重複を消して0以外の個数を数え上げてそれを出力して正解
B.Vile Grasshoppers
英語わかんねって思いながらサンプルと注意書きのところみたら理解できた
答えをnだとすると、nはpまでの数全てで割り切れない
ということはsqrt(109)までの素数リスト作ってyからp+1まで試し割りすればいいかなってなって実装して正解
C.Save Energy!
読解力がなさすぎて、翻訳を駆使しても何を言ってるのか全然わからなかった……
40分くらい英語と格闘して結局諦め
ストーブがついてない時間を計算してtに足せばいいのかな、とか思ってた
全体的に
英語がわからん 以上
bit全探索
をやってて、bitで組み合わせの全探索できるなみたな感じには思えたけど実装がわからなかったので覚え書き程度に書く。
bit全探索
ビットを仕切りに見立てて、ビットを全探索することで部分集合などを求める探索
今回の場合ようは、
1234567
という文字列があったとき
000110
というビットを用いて
1234|5|67
のように分割されているとみなすことができる。
計算量は2n
コード
以下提出したコード
#include <iostream> #include <vector> #include <cmath> #include <algorithm> #include <string> #include <queue> #include <stack> using namespace std; int main(){ string s; cin >> s; vector<string> nums; for (int i=0; i<s.length(); i++) nums.push_back(s.substr(i, 1)); long res = 0; long tmp; long digit; long sum = 0; string ssum = ""; for (int i=0; i< (1 << (nums.size() - 1)); i++) { // bit演算なので条件 sum = 0; tmp = 0; digit = 1; ssum = nums[0]; for (int k=0; k<nums.size()-1; k++) { if (i & (1 << k)) { // 見てるbitと現在見てる桁に+がついているとき sum += stol(ssum); ssum = ""; } ssum += nums[k+1]; } sum += stol(ssum); res += sum; } cout << res << endl; }
前にビットを使ったとき、アホなので"00000"みたいな文字列作って頑張ってた気がします
bitsetを使えばもっと綺麗にかけそうな気がしないでもない
JS記号プログラミングをやって思ったこと
はじめに
の24日目の記事です
アドベントカレンダーが始まってから24日も経つんですね、はやい
さて今回は、最近JavaScript記号プログラミングをやっていたので、それについて思ったことを書こうと思います
JavaScript 記号プログラミングについて
次のコードを見ていただくと、雰囲気はわかると思います
配列から数値が生成できたり、配列から文字列が作成できる。 しかも次のコードから関数オブジェクトが作成できるので、実質なんでもできます。
[]["constructor"]"constructor"
1 //1 -~[] //1 // constructorと出力 ([][$_=([]+{})[-~-~-~-~-~[]]+([]+{})[-~[]]+([][[]]+[])[-~[]]+(![]+[])[-~-~-~[]]+((!![]+[])[-[]])+((!![]+[])[-~[]])+([][[]]+[])[-[]]+([]+{})[-~-~-~-~-~[]]+(!![]+[])[-[]]+([]+{})[-~[]]+(!![]+[])[-~[]]][$_]((([]+{})[-~-~-~-~-~[]]+([]+{})[-~[]]+([][[]]+[])[-~[]]+(![]+[])[-~-~-~[]]+([]+{})[-~[]]+(![]+[])[-~-~[]]+(![]+[])[-~-~-~-~[]])+'.'+(![]+[])[-~-~[]]+([]+{})[-~[]]+(([]+[])[$_]+[])[-~-~-~-~-~-~-~-~-~-~-~-~-~-~[]]+([][$_]+[])[(-~[]<<-~-~-~-~[])+(~-~[])]+"'"+$_+"'"+([][$_]+[])[(-~[]<<-~-~-~-~[])+(~[])]))() // constructorと出力 (function(){console.log('constructor')})()
思ったこととか
- 文字数が少ないほど見にくくなっていい感じになる
- 使える文字数が増えるにつれ便利になっていくので推測しやすい
- =や,などの推測可能な文字はできるだけ避けた方がいい
- 上記のconstructorの例だとわかりやすいが、変数っぽく見える
- <<などのシフト演算なども避けたほうがいい
- 改行はしないほうがいい
だいたい以上のリスト通りやるとみにくくなるんじゃないかと思います
シンプルなほどわかりにくいってのはBrainf*ckやwhitespaceが教えてくれている
短く難読化しようとすると、以外にも法則が見つかってしまうので、ここが悩ましいところ
個人的にはダブルクォーテーションや、シングルクォーテーションなど、一発で文字列とわかってしまうのはあまり使いたくなかったのですが、時間なかったのでこれでやってしまった
あと記号プログラミングは先輩がやっていたからやってみたのですが、最初は敬遠していたものの、案外パズルみたいで楽しいですねこれ
皆さんもやってヤバイコード見つけて教えてください
明日のアドベントカレンダー最後の記事を飾るのはかったーさんです