Hatena::ブログ(Diary)

GANAwareはてな版 RSSフィード Twitter

2015-08-28 C# の double の %

C# 5.0 の double の % がなんか仕様とは異なる値を返す気がするという話。

Download C# Language Specification 5.0 from Official Microsoft Download Center C# 5.0 の言語仕様によれば、

7.8.3 Remainder operator

  • Floating-point remainder:
double operator %(double x, double y);

z is the result of x % y and is computed as x - n * y,

where n is the largest possible integer that is less than or equal to x / y.

とのことなので、n = Floor(x / y) のハズ...。でも実際は Truncate っぽい動作をする。

static void ReminderOperatorDoubleFloor()
{
    var x = -5.2;
    var y = 2.0;
    var n = System.Math.Floor(x / y);
    var z = x - n * y;
    Console.Out.WriteLine("FLOOR: x = {0}, y = {1}, n = {2}, z = {3}, x % y = {4}", x, y, n, z, x % y);
    // => FLOOR: x = -5.2, y = 2, n = -3, z = 0.8, x % y = -1.2
}

static void ReminderOperatorDoubleTruncate()
{
    var x = -5.2;
    var y = 2.0;
    var n = System.Math.Truncate(x / y);
    var z = x - n * y;
    Console.Out.WriteLine("TRUNCATE: x = {0}, y = {1}, n = {2}, z = {3}, x % y = {4}", x, y, n, z, x % y);
    // => TRUNCATE: x = -5.2, y = 2, n = -2, z = -1.2, x % y = -1.2
}

static void ReminderOperatorInt()
{
    var x = -52;
    var y = 20;
    var n = x / y;
    var z = x - (x / y) * y;
    Console.Out.WriteLine("INT: x = {0}, y = {1}, n = {2}, z = {3}, x % y = {4}", x, y, n, z, x % y);
    // => INT: x = -52, y = 20, n = -2, z = -12, x % y = -12
}

で、実際どんな式が使われてるの、というと Math.IEEERemainder Method (Double, Double) (System) の Remarks に書かれているが、Abs を使った上で Floor して符号は後から追加している。でも仕様には Abs 使うなんて書いてないじゃん!*1

# 蛇足ですが C++03 では double の % 演算定義されておらずコンパイルできない。

*1:7.8.2 Division operator の整数の / 演算子のところには "absolute value" うんぬんとの記述がみられるので、やはり % のほうの記述は書き忘れであるように思う

2013-10-08

C++11 の正規表現ライブラリの曖昧さ

libstdc++ の regex が実装されたそうです。

そこで、仕様曖昧な点(2点)を調査して纏めました。

GitHub Pages 機能を使ったことが無かったので、試しに使ってみようということで上記のところで公開してあります

gh-pages ブランチの中で symlink を作っても、GitHub Pages で公開されたページでは symlink は辿ってくれないようでした。そのため、ちょっとだけ修正が必要でした。

2013-07-02

正規表現で [a-[:alpha:]] の意味って?

C++11仕様に対する疑問

C++11正規表現 (std::regex_constants::ECMAScript 時) の仕様ECMA-262 の文法を次のように微妙に変更したものとなっています

ClassAtom ::
	-
	ClassAtomNoDash
	ClassAtomExClass
	ClassAtomCollatingElement
	ClassAtomEquivalence
ClassAtomExClass ::
	[: ClassName :]
ClassAtomCollatingElement ::
	[. ClassName .]
ClassAtomEquivalence ::
	[= ClassName =]
ClassName ::
	ClassNameCharacter
	ClassNameCharacter ClassName
ClassNameCharacter ::
	SourceCharacter but not one of "." "=" ":"
(ドラフト n3337.pdf より)

そして ECMA-262 の正規表現の文字クラス周りの文法はだいたい以下のような感じになっています

CharacterClass ::
	[ [lookahead ∉ {^}] ClassRanges ]
	[ ^ ClassRanges ]
ClassRanges ::
	[empty]
	NonemptyClassRanges
NonemptyClassRanges ::
	ClassAtom
	ClassAtom NonemptyClassRangesNoDash
	ClassAtom - ClassAtom ClassRanges
NonemptyClassRangesNoDash ::
	ClassAtom
	ClassAtomNoDash NonemptyClassRangesNoDash
	ClassAtomNoDash - ClassAtom ClassRanges
ClassAtom :: (ここは C++11仕様で変更される)
	-
	ClassAtomNoDash
ClassAtomNoDash ::
	SourceCharacter but not one of \ or ] or -
	\ ClassEscape
ClassEscape ::
	DecimalEscape
	b
	CharacterEscape
	CharacterClassEscape
(Standard ECMA-262 より)

ここで、強調した部分、つまり以下の部分

ClassAtom ::
	ClassAtomExClass
NonemptyClassRanges ::
	ClassAtom - ClassAtom ClassRanges
NonemptyClassRangesNoDash ::
	ClassAtomNoDash - ClassAtom ClassRanges

を素直に解釈すると、例えば次のような正規表現は文法上正しいということになります

[a-[:alpha:]]
[[:alpha:]-a]
[[:alpha:]-[:alpha:]]

文法上は正しいといっても、何を表現しているのか意味がよくわかりません。

現実の実装では?

例えば、Boost C++ Libraries ではテストケース (test_sets.cpp) 内で、以下のようなテストをしており、

   TEST_INVALID_REGEX("[a-[:alpha:]]", boost::regex::extended);

問題となる正規表現記述できないことを確かめています

また、OS X Mountain Lionclang-425.0.28 では、

#include <regex>
#include <iostream>

int main() {
	std::locale::global(std::locale("C"));
	std::regex re("[a-[:alpha:]]");
	std::cout << std::boolalpha << regex_match("a", re) << std::endl;
	std::cout << std::boolalpha << regex_match("b", re) << std::endl;
	return 0;
}

上記のソースを -std=c++11 -stdlib=libc++ でコンパイルして実行すると

true
false

が出力されます。なにが起こったのかよくわかりません。

また、Visual Studio 2012 Express では上記のソースを実行すると std::regexコンストラクタ内で std::regex_error 例外が .code() == std::regex_constants::error_range で throw されます

まとめ

というわけで、この問題は C++11仕様の間違いとして解釈するのが良いと思います

2013-05-14

zshのデフォルトの補完の定義を使わないことにした

zshで以下のように設定しておくと

autoload -Uz compinit
compinit

様々な補完がデフォルト定義されますが、ほとんどの定義自分には不要であることが最近分かってきました。

むしろ

make ファイル名

と実行したいのにファイル名を補完できないなど、不便な点のほうが目立ちます。

compinit を行わなければデフォルトの補完も定義されないので上記のような不便はないのですが、その代わり補完候補に色が付かなくなってしまうのでそれはそれで不便です。

そこで、compinit を実行した上で不要定義をばっさり削除することにしました。

autoload -Uz compinit
compinit

# ほとんどの補完の定義を削除する。
# special contexts の定義のみ残す (see: man zshcompsys)
fix_comp_assoc() {
	local var=$1
	shift
	for key in "$argv[@]"; do
		case $key in
		-redirect-,\<,*) unset "${var}[$key]";;
		-redirect-,\>,*) unset "${var}[$key]";;
		-value-,-*) ;;
		-value-,*) unset "${var}[$key]";;
		-*) ;;
		*) unset "${var}[$key]";;
		esac
	done
}
fix_comp_assoc _comps        "${(k)_comps[@]}"
fix_comp_assoc _services     "${(k)_services[@]}"
fix_comp_assoc _patcomps     "${(k)_patcomps[@]}"
fix_comp_assoc _postpatcomps "${(k)_postpatcomps[@]}"

compinit では、補完する時にどのようなコンテキストでどのコマンドを利用するという一覧は _comps, _services, _patcomps, _postpatcomps という連想配列に格納されるようです*1。そこで、それらの定義の中から special contexts の定義以外をばっさり削るようにしました。

これで

make ファイル名

も実行可能になり、快適zshライフを送ることができそうです。

# しかし、もっと良いやりかたがありそうなものですが…

*1:これらの変数デフォルトの内容は ~/.zcompdump へダンプされているのでそこで確認するのが楽です

2012-02-28

Storyboardsを使っている時のUITableViewのdequeueReusableCellWithIdentifier:の挙動

この情報に行き当たるのに苦労したのでメモ

https://developer.apple.com/library/ios/#releasenotes/Miscellaneous/RN-AdoptingStoryboards/_index.html#//apple_ref/doc/uid/TP40011297-CH1-DontLinkElementID_5