Hatena::Grouptopcoder

cafelier@SRM

cafelier のSRM参加記録です。コンテスト中に考えてたことを執拗に全部書き残すとどうなるだろうかという試み本番中にこういうコードが書きたかったなあ、という後で書いた反省コードを書き残す試み

スパムが来たのでしばらくコメント欄をはてなユーザ限定にしています、すみません、

 | 

2012-04-16

majiangmajiang2012/04/17 07:58除算/剰余の挙動は Python と同じですか?

cafeliercafelier2012/04/17 08:38Good question! 負の数を割った場合のお話だと思うのですが、結論ですが、Python と違います。残念ながら、使いにくい方の挙動です (^^;

D言語(余りの符号は割られる数に合わせる):
-10 / 3 == -3
-10 % 3 == -1

Python(余りは割る数の符号に合わせる):
-10 / 3 == -4
-10 % 3 == 2

仕様で未定義ということもなくて、この動作をする、と明記されている感じです。

komiyamkomiyam2012/04/17 13:37C++での int& のような参照変数を使うことはできますか?

cafeliercafelier2012/04/17 14:01完全に同じものはないです。関数の引数と、関数の返り値と、foreachのループに使う変数は、"ref" をつけると参照になります。それ以外の場所では使えません。

void set_value(ref int x) { x = 6502; }
int hoge; set_value(hoge); // hoge == 6502

class Foo {
ref int foo() { return x; }
int x;
}
(new Foo()).foo() = 8086;

int[] arr = [1,2,3];
foreach(ref x; arr) x = x*x;
// arr == [1,4,9]

http://dlang.org/function.html#parameters
http://dlang.org/function.html#ref-functions

onote2onote22012/04/17 15:15整理されていて分かりやすかったです。ありがとうございます。
ところで、連想配列の箇所で誤記かと。
KeyType[ValueType] → ValueType[KeyType]

cafeliercafelier2012/04/17 15:30直しました。ありがとうございます!

majiangmajiang2012/04/17 22:14それでは int を継承して除算の挙動を変えたいのですが、どうやればよいでしょうか?

cafeliercafelier2012/04/17 23:42Dでは組み込み型の継承はできないです。そもそも、あまり継承は使わないで、intをラップしてintを模した別の型を定義するスタイルが主流です。これをサポートする std.typecons の Proxy というライブラリがあって、

import std.conv;
import std.stdio;
import std.typecons;

// 除算の別の挙動の定義
int my_div(int x, int y) { int q = x/y; return q*y > x ? q-1 : q; }
int my_mod(int x, int y) { return x - my_div(x,y)*y; }

// 除算だけ変えたintっぽい型
struct modint
{
// コンストラクタ
this(int v){this.val = v;}
private int val;

// ほとんどの処理はintに転送
mixin Proxy!val;

// modint/int, modint%int の挙動を変更
auto opBinary(string op:"/", T)(T y) { return modint(my_div(val, cast(int)y)); }
auto opBinary(string op:"%", T)(T y) { return modint(my_mod(val, cast(int)y)); }

// int/modint, int%modint の挙動を変更
auto opBinaryRight(string op:"/", T:int)(T y) { return modint(my_div(cast(int)y, val)); }
auto opBinaryRight(string op:"%", T:int)(T y) { return modint(my_mod(cast(int)y, val)); }

// +-* なども、挙動変更後の型を返すように置き換え
auto opBinary(string op, T)(T y) { return modint(mixin("val"~op~"cast(int)y")); }
auto opBinaryRight(string op, T:int)(T y) { return modint(mixin("cast(int)y"~op~"val")); }
}

void main()
{
modint x = -10;
writeln(x / 3); // -4
writeln(x % 3); // 2
writeln(x*x*x % (1-x) > 0); // -1000 % 11 = 1 > 0 : true
}

こんな感じになります。詳しくはこちら:
http://dlang.org/phobos/std_typecons.html#Proxy
http://dlang.org/operatoroverloading.html

majiangmajiang2012/04/20 09:20ありがとうございます。試してみます!

majiangmajiang2012/04/21 01:46試してみました。ご提示されたコードの除算は少し私の意図と異なるので変更しました。それから任意の (実際には符号ありのみで十分) 整数型を拡張できるように変更しようと思っていじっていますが、どうすればよいでしょうか。

まず proper_div, proper_mod という名前で正しい挙動を定義し、任意の型で動くように変更することはできました。(型パラメータTに演算が入っていない場合は実行時エラーになるのでしょうか? コンパイルエラー出してくれるのですか?)

auto proper_div(T)(T x, T y)
{
T q = x / y;
if ((0 < y && x < q*y) || (y < 0 && q*y < x))
{
q -= 1;
}
return q;
}

auto proper_mod(T)(T x, T y)
{
return x - proper_div(x, y)*y;
}

上の方法で int を拡張したものを pint としていますが、proper(int) のような記法で任意の型へ変更を加えることはできるでしょうか。

また、少し話題が変わりますが、数値型のうち cent だけエラーになってしまいます。128ビット整数を使うには特別な操作が必要ですか?

質問ばかりですみません。

majiangmajiang2012/04/21 02:01現在のコード: https://gist.github.com/2430277/7710792eb33809b3289943a9db461af53179b629

cafeliercafelier2012/04/21 09:21> (型パラメータTに演算が入っていない場合は実行時エラーになるのでしょうか? コンパイルエラー出してくれるのですか?)

コンパイルエラーです。もうお試しになられたかとも思いますが、proper_div("string", "mojiretsu"); などとするとコンパイル時にひっかかります。

> proper(int) のような記法

できます。gistのコードでほぼOKです。class proper(T) ではなく struct proper(T) にするとうまく行くと思います。

D言語で解説した記事がとっさに思い出せなかったのでC#の記事ですが、classが参照型でstructが値型という違いがあります。http://ufcpp.net/study/csharp/oo_reference.html
class にする場合は proper!long(4) ではなく new proper!long(4) で値を作ることになります。

> 数値型のうち cent だけエラーになってしまいます。128ビット整数を使うには特別な操作が必要ですか?

残念なことに、centはキーワードだけ予約されていて、実装はまだされていません(^^;。現状、組み込みの整数型ではlongの64ビットが最大で、それ以上はstd.bigint.BigIntを使うことになります。

bicycle1885bicycle18852013/11/15 11:08素数のカウントのプログラムですが、
> bool[] is_prime = new bool[N];
がfalseで初期化されるので、その直後に
> is_prime[] = true;
などとtrueを突っ込む必要があると思います。

トラックバック - https://topcoder-g-hatena-ne-jp.jag-icpc.org/cafelier/20120416
 | 

presented by cafelier/k.inaba under CC0