強火で進め

このブログではプログラム関連の記事を中心に書いてます。

iPhoneで大きな整数の計算を行う

C99からの仕様である long long int 型がiPhoneの実機でもちゃんと使えるか確認してみました。

今回は以下のサイトを参照しつつテストしました。とてもシンプルにまとめて有り、とても読みやすかったです。

プログラミング言語 C の新機能
http://seclan.dll.jp/c99d/c99d05.htm

まずは変数の定義と sizeof() でチェック。

	unsigned long long int v1, v2;
	NSLog(@"sizeof() %d %d %d", sizeof(unsigned long long int), sizeof(long long int), sizeof(v1));

特にエラーとはならず sizeof() の結果はいずれも 8 。
ということでiPhoneでの long long int 型のサイズは 8byte = 64bit。

続いて値をそのままデバッグ出力。

	v1 = 0x0807060504030201LL;
	NSLog(@"%lld %qx", v1, v1);

こちらも以下の出力となり特に問題なし。

578437695752307201 807060504030201

#include を追加して最大値、最小値を確認。

	NSLog(@"LLONG_MIN %qx(%lld)", LLONG_MIN, LLONG_MIN);
	NSLog(@"LLONG_MAX %qx(%lld)", LLONG_MAX, LLONG_MAX);
	NSLog(@"ULLONG_MAX %qx(%llu)", ULLONG_MAX, ULLONG_MAX);
	
	long long lli = LLONG_MAX;
	unsigned long long ulli = ULLONG_MAX;
	NSLog(@"lli %qx(%lld)", lli, lli);
	NSLog(@"ulli %qx(%llu)", ulli, ulli);
	lli = LLONG_MIN;
	NSLog(@"lli %qx(%lld)", lli, lli);

当たり前と言えば当たり前ですが最初に紹介したサイトに記載されているとの同じ値が出力されました。後、ここで使った様に long long int と書く代わりに long long と記述する事も可能です。この辺りは long int が long と省略可能なのと同じルールですね。

LLONG_MIN 8000000000000000(-9223372036854775808)
LLONG_MAX 7fffffffffffffff(9223372036854775807)
ULLONG_MAX ffffffffffffffff(18446744073709551615)
lli 7fffffffffffffff(9223372036854775807)
ulli ffffffffffffffff(18446744073709551615)
lli 8000000000000000(-9223372036854775808)

ちなみに今回、出力時に使用したフォーマット指定子についての説明は以前解説したこちらを参照下さい。

String Format Specifiersの解説(フォーマット指定子の解説) - 強火で進め
http://d.hatena.ne.jp/nakamura001/20080912/1221229442

これはiPhoneでも long long int 型は問題なく使えそうですが念のため、加減乗除をテスト。

加算・減算

1byteなら0xFFの2桁。
2byteなら0xFFFFの4桁。
4byteなら0xFFFFFFFFの8桁。
8byteなら0xFFFFFFFFFFFFFFFFの16桁なので16桁フルに使う値でも正確に計算結果が出せているか確認。

	v1 = 0x2340000000000000LL;
	v2 = 0x1110000000000000LL;
	NSLog(@"%qx + %qx = %qx", v1, v2, v1 + v2);
	NSLog(@"%qx - %qx = %qx", v1, v2, v1 - v2);

結果はこちらいずれも問題無いですね。

2340000000000000 + 1110000000000000 = 3450000000000000
2340000000000000 - 1110000000000000 = 1230000000000000

乗算

32bit(=4byte=8桁)での最大値、2つを乗算。

	v1 = 0xFFFFFFFFLL;
	v2 = 0xFFFFFFFFLL;
	NSLog(@"%qx * %qx = %qx", v1, v2, v1 * v2);

もちろん、結果は64bit(=8byte=16桁)で表現可能な範囲に収まります。

ffffffff * ffffffff = fffffffe00000001

念のためPython(メモリが許す限り無限の桁数の計算が行える言語です)で計算して合ってるか確認。正しく計算出来ています。

>>> hex(0xFFFFFFFF * 0xFFFFFFFF)
'0xfffffffe00000001L'

除算

全ての桁をFで埋めた数を5で割る。この場合、全ての桁が15なので5で割ると3が並ぶはず。

	v1 = 0xFFFFFFFFFFFFFFFFLL;
	v2 = 0x5LL;
	NSLog(@"%qx / %qx = %qx", v1, v2, v1 / v2);

結果はこちら。

ffffffffffffffff / 5 = 3333333333333333

まとめ

iPhoneでもまったく問題なく long long int 型が使用可能。

-9,223,372,036,854,775,807〜9,223,372,036,854,775,807
(-922京3372兆0368億5477万5807〜922京3372兆0368億5477万5807)

または

0〜18,446,744,073,709,551,615
(0〜1844京6744兆0737億0955万1615)

までの数値が使用可能なので大きい数字を扱う場合も整数の場合は簡単に行えますね。

関連サイト

C99 - Wikipedia
http://ja.wikipedia.org/wiki/C99

Status of C99 features in GCC - GNU Project - Free Software Foundation (FSF)
http://gcc.gnu.org/c99status.html

C言語標準ライブラリ関数 ポケットリファレンス [ANSI C、ISO C99 対応] (POCKET REFERENCE)

C言語標準ライブラリ関数 ポケットリファレンス [ANSI C、ISO C99 対応] (POCKET REFERENCE)