とりあえず、プログラマの数学を買ってみた。
今更ながら、簡単なところから読み飛ばさずに理解しながら読んでみようかなと。
初歩的なところですが、なぜnの0乗が1なのかにガッテンしました。

- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2005/03/24
- メディア: 単行本
- 購入: 24人 クリック: 315回
- この商品を含むブログ (310件) を見る
とりあえず、プログラマの数学を買ってみた。
今更ながら、簡単なところから読み飛ばさずに理解しながら読んでみようかなと。
初歩的なところですが、なぜnの0乗が1なのかにガッテンしました。
仕様は、
・持ち金をチャージできる。
・チャージ時の総額と総利用額と残金を表示。
・使った時は、何に使ったかと金額を入力。
・過去20件の利用データを表示。
・過去100件の利用データ中の何に使ったかをドロップダウン表示して選択できる。
・エラーチェックはまだしていない。
・オモローと表示していた部分を「ご利用は計画的に。」に変更。
気づいたこと。知ったこと。
・djangoのテンプレートに渡す値にmodelを使えるのが管理が煩雑にならないので楽だと思った。
・GQLでSQLのTOP 20をやりたいときは、ORDER BY等の後にLIMIT 20とやる。
・ORDER BY等はおおむねSQLと同じ。
・時間制限のため、コードが汚い(エクスキューズです。)。
・datetime型を使う場合はdatetimeモジュールをインポートする。
・djangoのテンプレート側で四則演算が出来ない。
・スペルミスで結構エラーになった。
サンプルか修正したオブジェクトだけ表示。
・テンプレート
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang="ja" xml:lang="ja" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>{{ userName }}のお小遣い帳</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta http-equiv="Content-Script-Type" content="text/javascript" /> <link href="./styles/styles.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="./scripts/util.js" ></script> <script type="text/javascript" src="./scripts/index.js" ></script> </head> <body> <div id="body"> <div id="header"> <div id="user"> お小遣い帳 </div> <div id="navigationOperation" >■</div> </div> <div id="navigation" > <div id="logonControl"> {{ userName }} <br /> <a href="{{ logoutUrl }}">ログオフ</a> </div> <div id="settings"> <form action="/" method="post"> <div>年間チャージ額:<br /><input type="text" name="chargedValue" value="{{ setting.chargedValue }}" tabindex="1" accesskey="1" /><br /></div> <div>前回チャージ後総額:<br />{{ setting.properValue }}円<br /></div> <div>総利用額:<br />{{ setting.totalPayment }}円<br /></div> <div>残額:<br />{{ currentValue }}円<br /></div> <div><input type="submit" value="設定" tabindex="2" accesskey="s" /></div> {% if settingErrorMessage %} <div class="errorMessage">{{ settingErrorMessage }} </div> {% endif %} </form> </div> </div> <div id="contents"> <form action="/" method="post"> <div>使った内容:<select name="titles" tabindex="3"> <option value="" selected="selected"></option> {% for value in titles %} <option value="{{ value }}" >{{ value }}</option> {% endfor %} </select><input type="text" name="title" value="" tabindex="4" accesskey="c" /></div> <div>使った金額:<input type="text" name="payment" value="" tabindex="5" accesskey="3" /><br /></div> <div><input type="submit" value="設定" tabindex="6" accesskey="s" /></div> {% if paymentErrorMessage %} <div class="errorMessage">{{ paymentErrorMessage }} </div> {% endif %} </form> <div id="list" > 過去20件の利用状況: <table border="1" cellspacing="0" > <tr> <th>日付</th> <th>使った内容</th> <th>金額</th> </tr> {% for value in outputValues %} <tr> <td>{{ value.date }}</td> <td>{{ value.title }}</td> <td>{{ value.value }}</td> </tr> {% endfor %} </table> </div> </div> <div id="footer">ご利用は計画的に。</div> </div> </body> </html>
・データモデル
# -*- coding: utf-8 -*- from google.appengine.ext import db class UserMaster(db.Model): #paymentを利用するユーザのマスタを定義するクラスです。 #db.Modelを継承しています。 author = db.UserProperty() chargedValue = db.IntegerProperty() totalPayment = db.IntegerProperty() properValue = db.IntegerProperty() class PaymentInfo(db.Model): author = db.UserProperty() title = db.StringProperty() value = db.IntegerProperty() date = db.DateTimeProperty(auto_now_add=True)
・index.py
# -*- coding: utf-8 -*- import wsgiref.handlers import cgi import datetime from google.appengine.ext import db from google.appengine.ext import webapp from google.appengine.api import users import models import os from google.appengine.ext.webapp import template from google.appengine.ext.db import djangoforms class MainPage(webapp.RequestHandler): def view(self,user,settingErrorMessage = None,paymentErrorMessage = None): settings = models.UserMaster.gql("where author = :author",author=user) setting = None if settings.count() > 0: setting = settings[0] else: setting = models.UserMaster() setting.author = user setting.chargedValue = 600000 setting.properValue = setting.chargedValue setting.totalPayment = 0 setting.put() outputValues = models.PaymentInfo.gql("where author = :author order by date DESC LIMIT 20",author=user) titles = self.titles(user) template_values = { 'userName' : user.nickname(), 'logoutUrl': cgi.escape(users.create_logout_url("/")), 'setting' : setting, 'currentValue':setting.properValue - setting.totalPayment, 'outputValues': outputValues, 'titles': titles, 'settingErrorMessage': settingErrorMessage, 'paymentErrorMessage': paymentErrorMessage } path = os.path.join(os.path.dirname(__file__), 'index.html') self.response.out.write(template.render(path, template_values)) def titles(self,user): selections = models.PaymentInfo.gql("where author = :author order by title",author=user) values = [] prev = '' for value in selections: if prev != value.title: values.append(value.title) prev = value.title return values def get(self): user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) return self.view(user) def post(self): user = users.get_current_user() if not user: self.redirect(users.create_login_url(self.request.uri)) return if self.request.get('chargedValue'): if self.request.get('chargedValue').isdigit(): settings = models.UserMaster.gql("where author = :author",author=user) setting = settings[0] setting.properValue = setting.properValue + int(self.request.get('chargedValue')) setting.put() else: self.view(user,u'チャージ金額には数字を入力してください。') return else: payment = models.PaymentInfo() payment.author = user if len(self.request.get('titles')) == 0: payment.title = self.request.get('title') else: payment.title = self.request.get('titles') payment.value = int(self.request.get('payment')) payment.put() settings = models.UserMaster.gql("where author = :author",author=user) setting = settings[0] setting.totalPayment = setting.totalPayment + payment.value setting.put() self.view(user) def main(): application = webapp.WSGIApplication( [('/', MainPage)], debug=True) wsgiref.handlers.CGIHandler().run(application) if __name__ == '__main__': main()
Equiptは、サブスクリプション版のOffice HomeおよびStudentに、Microsoftが提供するウイルス対策製品となる「OneCare」をバンドルしており、OneCare単体での推奨購入価格より20ドルだけ高い、年間69ドルの利用価格が設定されている。
MS、Officeのサブスクリプションサービス「Microsoft Equipt」を発表:ニュース – CNET Japan
これは、うれしい。
日本に展開される事があるのか、展開されるとしたらいつなのかは、全然謎だけど。
.NET関連で困った時、昔は
1.Google
2.MSDN
という順番だったのだが結局正しい情報として検索結果の中からMSDを選択することが多かったので、最近は
1.MSDN
2.Microsoftの開発者向け情報サイト(http://asp.net等)
2.Google
という順番が多い。
そして、大抵1番で終了するパターンが多い。
あえてGoogleを使うときもMSDNの中を検索する為に利用する事が多い。
ナレッジベースなんかはGoogleでKB{番号}で検索した方が明らかに早いし。
それだけに、MSDNの重さとか、使いやすさがもうちょっと、どうにかならんもんかなと思う。
用があって久しぶりにHotmailを使ってみた。
未読メールが死ぬほどあったので、一括で既読にしたかったんだけど、なぜかツールバーに存在するのは
「未開封にする」
のみだった。
結局、未読メールを既読にするのは諦めてブラウザを閉じた。
「開封済みにする」がなんで無いのだろうか・・・。
追記:
コメントでご指摘していただいたので、いろんな環境でアクセスしたところ。
どうも、標準バージョンだと「未開封にする。」しかできないだけのようです。
IEを利用して拡張バージョンのUIを使う事で、コンテキストメニューに「開封済みにする。」が表示されました。
これで、とりあえず纏めて開封済みにできました。
標準バージョンにも、「開封済みにする。」を用意しておいてほしいですね。
なんとか目的を達成できましたが、とりあえず、インタフェースに不満があることには変わりないですね。
とりあえず、FireFox2.0でも拡張バージョンが使えると書いてあったので、是非3.0にも対応してほしいところです。
ヘルプを見てみましたが、「拡張バージョン」とか「標準バージョン」とかが明記されていないですね。
「拡張バージョンの時のみできる」等の記述があれば良いのにと思いました。
まあ、そんなに利用しないので良いのですが・・・。
ちなみに、gmailは、簡易HTML表示でもちゃんと、一通りの操作ができるようになっていました。
通常匿名メソッドを実装する時は、宣言と代入が同じになるパターンが多い。
例えば、下記のコードのように。
public void 匿名メソッドで再帰() { Func<int, bool> カウントダウン = (x) => { if (x == 0) { return true; } Console.WriteLine(x); x--; return カウントダウン(x); }; カウントダウン(40); }
しかし、上記のコードだと、
未割り当てのローカル変数 'カウントダウン' が使用されました。
と言われてコンパイルエラーになる。
では、どうしたら良いかというと、先に匿名メソッドを代入する変数を宣言しておけばよい。
下記のコードならコンパイルエラーにならないで正しく動作する。
public void 匿名メソッドで再帰() { Func<int, bool> カウントダウン = null; カウントダウン = (x) => { if (x == 0) { return true; } Console.WriteLine(x); x--; return カウントダウン(x); }; カウントダウン(40); }
なんでそうなのかをコンピュータによる実証以外に証明する事ができないので、ドラクエで言うと、まだ冒険の書を作ったところ。
いや、冒険の書すら作れていないのか。
最近、続けている話題ですが、とりあえず見つけた法則が正しいのかどうかを実証するために法則を見つける前のコードをPCで実行させてみたら、さすがに死ぬほど時間がかかって800000に辿りつくまでですら一晩かかったので、バイナリサーチで書き直してみた。
配列なら、Array.BinarySearchがあるのだけれども・・・。
バイナリサーチにしたら、intの幅に関しては、1時間20分くらいで、戻ってくるようになった。
アルゴリズム一つでぜんぜん違うという事を改めて(今更ながら)実感。
public void nまでの整数を二つの組に分けて合計した結果が同じだった数字リスト実証() { Func<int, bool> 奇数が奇数個ある = x => ((x / 2) + (x % 2)) % 2 != 0; //Enumerable.Select().Sum()は使わない方向で Func<long, long, long> xからyまでの計 = (x, y) => ((x + y) * ((y - x + 1) / 2)) + (((y + x) / 2) * ((y - x + 1) % 2)); Func<int, long,long,long, bool> nまでの数字の合計の半分とnを二つの組にした合計が同じものがある = null; nまでの数字の合計の半分とnを二つの組にした合計が同じものがある = (n, 総和の半分, 始点, 終点) => { long 探索点 = (終点 + 始点) / 2; long 総和 = xからyまでの計(探索点, (long)n); if (総和 == 総和の半分) { return true; } if (始点 == 終点) { return false; } if (総和 > 総和の半分) { 始点 = 探索点; } else { 終点 = 探索点; } if (始点 + 1 == 終点) { if (総和 > 総和の半分) { 始点++; } else { 終点--; } } return nまでの数字の合計の半分とnを二つの組にした合計が同じものがある(n, 総和の半分, 始点, 終点); }; var 該当するnのリスト = Enumerable .Range(2, int.MaxValue - 2) .Where(n => !奇数が奇数個ある(n) && nまでの数字の合計の半分とnを二つの組にした合計が同じものがある(n, xからyまでの計(1, n) / 2, 1, n)) .Select(n => n); foreach (var n in 該当するnのリスト) { Console.WriteLine(n); } }
以前、コードの10戒と題して、犬の10戒をまねしたコーディングルールを掲載しました。
しかし、若干カジュアルすぎるため仕事に適用するには文体を改修する必要があるかもしれません。
長いコーディング標準は、読むのも守るのもメンテするのも大変です。
なので、短いけど守ってほしい事と理由を犬の10戒の真似をしてまとめてみました。
そこで今回は、これを少しフォーマルなものにしてみました。