読者です 読者をやめる 読者になる 読者になる

時間計算における丸め

本稿では時間計算についての丸め操作を考える。 最初に丸めの定義は以下とする。

丸め(まるめ)とは、与えられた数値を、ある一定の丸め幅の整数倍の数値に置き換えることである。 https://ja.wikipedia.org/wiki/%E7%AB%AF%E6%95%B0%E5%87%A6%E7%90%86

丸めの対象

時間計算における丸めの対象は瞬間(Instant)あるいは日時(LocalDateTime)とする。

瞬間 とはタイムゾーン(場所)によらず一意な時間である。瞬間は一般にUTC時間で表される。 一方、日時 は特定の瞬間を表すものではなく、タイムゾーンによってその日時を表す瞬間は異なる。 瞬間日時タイムゾーンが与えられれば相互に変換することができる。

丸めの単位

時間計算における丸めの単位は継続時間(Duration)とする。 継続時間とは、長さを表す時間の概念で秒で表されるものとする(実際の実装ではナノ秒)。

ここでまず単純な例を挙げると:

  • 2001/02/03 01:02:03 を 10分(600秒) を単位に切り捨てる → 2001/02/03 01:00:00
  • 2001/02/03 01:02:03 を 10分(600秒) を単位に切り上げる → 2001/02/03 01:10:00

まず丸め処理をするためには、丸めの対象となる日時を数値に変換する必要がある。 この例だと丸めの単位が一日の長さの約数なので、日を無視して時間だけに注力すれば良い。 SI単位系を用いて計算すると 01:02:03(1 * 60 * 60) + (2 * 60) + 3 = 3723(秒) となるので、ここから 3723 % 600 = 123(秒) のように余りを求めてそれを足し引きすればいい。

これは自明は結果だが、以下のケースだとどうなるか:

  • 2001/02/03 01:02:03 を 7分 を単位に切り捨てる → ?

この丸めは一般に定義できない。 なぜなら7分(420秒)というのは一日の長さの約数ではないからだ。 一日の長さははSI単位系24 * 60 * 60 = 86400(秒) なので 86400 / 420 = 205.714286... のように割り切ることはできない。 すると日を含めた日時を数値に変換して余りを求めなければならないが、それはどの瞬間を起点とするか、1年の長さが何秒なのかによって結果が異なってしまう。 これは 紀年法と暦を定義しないと数値に変換することはできない ことを意味する。

実装

型レベル数値リテラルを使って型レベルFizzBuzz

型レベルFizzBuzz(及び、type familyにおけるガードの書き方) - claustrophobiaを見て自分も型レベルFizzBuzz書いてみました。 GHC 7.8以降で動作します。

Natを受け取るとFBkindを持つ型を返すFizzBuzz型族と、FBに対するsingletonになるSFB型を定義して、 あとは型からsingletonを生成してそれをprintしています。

SNumberT 1
SNumberT 2
SFizzT
SNumberT 4
SBuzzT
SFizzT
SNumberT 7
SNumberT 8
SFizzT
SBuzzT
SNumberT 11
SFizzT
SNumberT 13
SNumberT 14
SFizzBuzzT
SNumberT 16

TypeScript 0.95でコンパイルできないジェネリックメソッドのコード

typescript

0.91ではコンパイルできた以下のコードが0.95ではコンパイルできなくなっている。バグ?

interface IFoo {
    f<T>(): T;
}   

class Foo implements IFoo {
    f<T>(): T {
        return null;
    }
}   

エラーメッセージ:

/Users/emon/Desktop/test.ts(5,7): error TS2137: Class Foo declares interface IFoo but does not implement it:
        Types of property 'f' of types 'Foo' and 'IFoo' are incompatible:
                Call signatures of types '<T>() => T' and '<T>() => T' are incompatible.

追記:Issuesに上がってた。

Interface declaration with generics not working in TypeScript 0.9.5

PDOにInterface欲しい

programing php

PHPの色々なフレームワークでDatabase Driverのラッパーが量産されているのが不毛に思った。 ここに共通化されたインターフェイスがあればフレームワークの違いを気にせず色々できるのになと。

そこで、PSR-3のLoggerのように標準化できないのかなと思って調べてみると、DoctrinのDBALが目に付いた。

ソースを読んでみると、DBALのConnectionインターフェイスはPDOのサブセットになっている。 そうすると、PDOに対する実装であるPDOConnectionConnectionに対して実装を宣言するだけで済むわけだ。

PDOをインターフェイスとして定義することで、PDOの機能をそのまま同じインターフェイスで使うことができるし、PDOを使う時には不要な抽象化レイヤーを挟まないのでシンプルでいいなと。 PDOは事実上の標準なので多くの場合これで必要十分だと思う。

しかしながら、DBALにはクエリビルダーなど不要な機能も含まれているしdoctrin/commonへの依存もある。Connection部分だけ抜きだしたpackageがあればいいのだけど、今の所ないようだった。

ということでPDOのサブセットとしてのインターフェイスだけを提供するcomposerのpackageを作りました。

https://github.com/emonkak/pdo-interface

VimScriptでIteratorを作ってメソッドチェインで処理する

programing vim

業務でPHPを使っていてarray系の関数の酷さに耐えかねて作ってしまったUnderbar.phpですが、 VimScriptでもIteratorを作ってメソッドチェインで処理したくなってきますね!

ということで書きました。特に実用性はありません。

Opera 15のショートカットキーカスタマイズ

opera

/Applications/Opera.app/Contents/Versions/15.0.1147.132/Opera Framework.framework/Resources/opera.pakにデフォルト設定のJSONが入っていたので、これを参考にProfileディレクトリのPreferencesを書き換えれば色々できそう。 nストロークキーをマッピングできるかどうかは不明。 あとActionの連結ができればこれはもう最強伝説だね!

まあどうせまたLinux版は1年以上放置されそうだけど……。

"Keybindings": {
  "Settings": { "AdvancedEnabled": false },
  "Basic": {
    "AccessKeyToggle": ["Esc+Shift"],
    "AddBlankTab": ["Ctrl+T","Command+T"],
    "AddToBookmarks": ["Command+Shift+D","Command+D"],
    "Back": ["Command+Left"],
    "Bookmarks": ["Command+Shift+B", "Command+B"],
    "CloseActiveTab": ["Command+W", "Ctrl+F4"],
    "ClosePrivateWindow": ["Ctrl+Shift+Q"],
    "CloseWindow": ["Command+Shift+W"],
    "Copy": ["Command+C"],
    "Cut": ["Command+X"],
    "CycleBackwardInActivationList": ["Ctrl+F2"],
    "CycleForwardInActivationList": ["Ctrl+F1"],
    "Delete": ["Del"],
    "DevTools": ["Command+Alt+I"],
    "DevToolsConsole": ["Command+Alt+J"],
    "DevToolsInspect": ["Command+Alt+C"],
    "EditProperties" : ["Command+i"],
    "ErrorConsole": ["Command+Shift+O"],
    "Exit": ["Command+Q"],
    "Extension": ["Command+Shift+E"],
    "Find": ["Command+F"],
    "FindInline": ["OemPeriod","OemComma"],
    "FindNext": ["Command+G"],
    "FindPrevious": ["Command+Shift+G"],
    "FitToWidth" : ["F11+Ctrl"],
    "FocusAddressbar" : ["Command+L","Command+E","Ctrl+F5"],
    "FocusNextWidget": ["Tab"],
    "FocusPage" : ["Ctrl+F6"],
    "ForceReload": ["Shift+F5","Command+Alt+R"],
    "Forward": ["Shift+Backspace","Alt+Right","Command+Right"],
    "GoToEnd": ["End","Ctrl+End"],
    "GoToPage" : ["F2"],
    "GoToSpeedDial_1" : ["Command+1"],
    "GoToSpeedDial_2" : ["Command+2"],
    "GoToSpeedDial_3" : ["Command+3"],
    "GoToSpeedDial_4" : ["Command+4"],
    "GoToSpeedDial_5" : ["Command+5"],
    "GoToSpeedDial_6" : ["Command+6"],
    "GoToSpeedDial_7" : ["Command+7"],
    "GoToSpeedDial_8" : ["Command+8"],
    "GoToSpeedDial_9" : ["Command+9"],
    "GoToTop": ["Home","Ctrl+Home"],
    "HideOpera": ["Command+H"],
    "History": ["Command+Shift+H", "Command+Alt+2"],
    "Homepage" : ["Space+Meta", "Command+Home"],
    "NavigateDown": ["Down"],
    "NavigateLeft": ["Left"],
    "NavigateRight": ["Right"],
    "NavigateUp": ["Up"],
    "NavStop": ["Esc"],
    "OpenDocument" : ["Command+O"],
    "OpenLinkInBackground": ["Command+Shift+Enter"],
    "OpenLinkInNewPage": ["Command+Enter"],
    "OpenMenu" : ["Command+M"],
    "OpenPrivateWindow": ["Command+Shift+N"],
    "OpenWindow": ["Command+N"],
    "PageDown" : ["PageDown","Space"],
    "PageLeft" : ["Command+PageUp"],
    "PageRight" : ["Command+PageDown"],
    "PageUp" : ["PageUp"],
    "ParentDirectory": ["Command+Backspace"],
    "Paste": ["Command+V","Meta+Y"],
    "PasteAndGo": ["Command+Shift+V"],
    "PastePassword": ["Command+Alt+Enter"],
    "Preferences": ["Command+OemComma"],
    "Print" : ["Command+P"],
    "PrintPreview": ["Command+Shift+P"],
    "QuickPreferences": ["Alt+F12"],
    "Redo": ["Command+Y","Command+Shift+Z"],
    "Reload": ["F5","Command+R"],
    "ReloadFrame": ["Alt+F5"],
    "ReopenLastClosedTab": ["Command+Shift+T"],
    "ResetZoom" :["Mul", "Command+0", "Command+Num0"],
    "Save" : ["Command+S"],
    "SelectAll": ["Command+A"],
    "SelectPreviouslyActiveTab": ["Ctrl+Grave"],
    "SelectTabToTheRight": ["Ctrl+Tab"],
    "SelectTabToTheLeft": ["Ctrl+Shift+Tab"],
    "ShowContextMenu": ["Command+Shift+M"],
    "ShowHelp" : ["Command+Shift+OemSlash"],
    "SwitchToNextPage": ["Command+Shift+Right"],
    "SwitchToPreviousPage": ["Command+Shift+Left"],
    "ToggleFullscreen": ["Command+Shift+F"],
    "ToggleKeyboardSelection" : ["F7"],
    "ToggleOverstrike": ["Ins"],
    "Transfers": ["Command+J"],
    "Undo": ["Command+Z"],
    "ValidateSource": ["Command+Shift+U"],
    "ViewSource": ["Command+U", "Command+Alt+U"],
    "ZoomIn" : ["Command+OemPlus", "Command+Shift+OemPlus", "Shift+OemPlus", "Command+Plus", "Plus", "OemPlus"],
    "ZoomOut" : ["Command+OemMinus", "Command+Minus", "Minus", "OemMinus"]
  },
  "Advanced": {
    "Back": ["Z"],
    "FastForward": ["Shift+X"],
    "Find": ["OemSlash"],
    "FocusNextFrame": ["3"],
    "FocusPreviousFrame": ["Shift+3"],
    "Forward": ["X"],
    "LoadAllImages" : ["I"],
    "ResetZoom": ["6", "Num6"],
    "Rewind": ["Shift+Z"],
    "SelectNextElement" : ["D"],
    "SelectNextHeading" : ["S"],
    "SelectNextLink" : ["A"],
    "SelectPrevElement" : ["E"],
    "SelectPrevHeading" : ["W"],
    "SelectPrevLink" : ["Q"],
    "ShowAddressDropdown" : ["H"],
    "ShowImagesToggle": ["Shift+I"],
    "ZoomIn": ["0", "Num0"],
    "ZoomInMore": ["8"],
    "ZoomOut": ["9", "Num9"],
    "ZoomOutMore": ["7"]
  }
}

PHPでフィボナッチ数列を出力するソースコードを出力するプログラム

programing php

Quineみたいなものだけど、自身のソースコードを次々に書き換えて
それを新たに起動したPHPプロセスに標準入力として与えている。

fib.php

<?php
function php($input) {
    $process = proc_open('php', array(array('pipe', 'r'), array('pipe', 'w')), $pipes);
    if (is_resource($process)) {
        fwrite($pipes[0], $input);
        fclose($pipes[0]); 
    
        $output = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        proc_close($process);
    
        return $output;
    }
}
function callback($output) {
    $n = 50;
    $lines = explode("\n", trim($output));
    $count = count($lines);
    $lines[] = end($lines) + prev($lines);
    $f = __FILE__;
    $s = file_get_contents($f);
    $s = preg_replace("/__FILE__[;]/", "'$f';", $s);
    $s = preg_replace('/0\n1\n/', implode("\n", $lines), $s);
    return $count < $n ? php($s) : end($lines);
}
ob_start("callback") ?>
0
1
<?php ob_end_flush() ?>

Result

$ time php fib.php 
12586269025
php fib.php  0.51s user 0.28s system 92% cpu 0.851 total