Language detail: D
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
- 文字列で+を表示する (Nested Flatten)
- 年賀はがきの当せん番号 (Nested Flatten)
- 箱詰めパズルの判定 (Nested Flatten)
- 関数やメソッドのソースの平均行数 (Nested Flatten)
- コレクションの実装 (Nested Flatten)
codes
D 2.031で。 Mt19937インスタンスは一種の無限リストで、frontメソッドで先頭要素を読み出し (除去はしない)、popFrontで除去します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import std.random;
static const uint COUNT = 16;
static const uint SEED = 1337;
static const uint NUM_TRIALS = 42;
void main()
{
uint[COUNT] randomNumbers;
Mt19937 gen; // 2^19937周期のMersenne Twister
// シードを設定し、COUNT個の乱数を憶えておく
gen.seed(SEED);
foreach (i; 0 .. COUNT) {
randomNumbers[i] = gen.front;
gen.popFront;
}
foreach (i; 0 .. NUM_TRIALS) {
// 同じシードを再設定し、出てくるCOUNT個の乱数が
// 最初のと同じであることを確認
gen.seed(SEED);
foreach (j; 0 .. COUNT) {
assert(randomNumbers[j] == gen.front);
gen.popFront;
}
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 | private import std.stdio, std.date, std.string;
void main() {
void output(uint n) {
writeln(format("%06b", n).replace("0", "□").replace("1", "■"));
}
localTZA = 9 * ticksPerHour; // JST
auto t = UTCtoLocalTime(getUTCtime());
output(hourFromTime(t));
output(minFromTime(t));
output(secFromTime(t));
}
|
D2.031で標準ライブラリに、リフレクションを用いて列挙体の値を文字列に変換する機能が追加され、若干綺麗に書けるようになったので書き直します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | private import std.stdio : write, writeln;
private import std.string : repeat;
private import std.conv : to;
enum 数 : uint {
〇, 一, 二, 三, 四, 五, 六, 七, 八, 九, 十
}
enum 空白 = " ";
dstring 文字列化(数 かず) {
dstring もじれつ;
while(かず) {
もじれつ = to!dstring(かず % 数.十) ~ もじれつ;
かず /= 数.十;
}
return もじれつ;
}
void main() {
foreach(い; 数.一 .. 数.十) {
foreach(ろ; 数.一 .. 数.十) {
auto もじれつ = 文字列化(い * ろ);
write(空白.repeat(数.三 - もじれつ.length), もじれつ);
}
writeln();
}
}
|
ファイバを用いました。 N = 1000, M = 1000: 719 ms N = 10000, M = 1000: 11521 ms N = 1000, M = 10000: 11079 ms N = 10000, M = 10000: 114837 ms
see: core.thread - D Programming Language - Digital Mars
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | module ringnode;
import core.thread, std.range, std.stdio, std.perf;
class Node: Fiber {
private Message[] _msgs;
private Node _next;
this() {
super(&process);
}
void nextNode(Node value) {
_next = value;
}
void post(Message msg) {
_msgs ~= msg;
}
private void process() {
for(;;) {
if(!_msgs.empty) {
auto msg = _msgs.front;
_msgs.popFront;
debug writefln("Node[%s] received message '%s' (hopLimit: %s)", cast(void*)this, msg.text, msg.hopLimit);
msg.hopLimit--;
if(!msg.hopLimit) {
yieldAndThrow(new Completed(msg));
}
_next.post(msg);
}
yield;
}
}
}
class Ring {
Node[] _nodes;
this(uint n) {
_nodes.length = n;
foreach(i, ref node; _nodes) node = new Node;
foreach(i, _; _nodes) _nodes[i].nextNode = _nodes[(i + 1) % $];
}
auto nodes() {
return cycle(_nodes);
}
alias nodes this;
}
class Message {
uint hopLimit;
string text;
this(uint hopLimit, string text) {
this.hopLimit = hopLimit;
this.text = text;
}
}
class Completed: Throwable {
this(Message msg) {
super("completed: '" ~ msg.text ~ "'");
}
}
void benchmark(uint N, uint M)() {
auto ring = new Ring(N);
ring.front.post(new Message(N * M, "hello"));
auto pc = new PerformanceCounter;
pc.start;
try {
foreach(node; ring.nodes) {
node.call;
}
} catch(Completed c) {
debug writeln(c.msg);
}
pc.stop;
writefln("N = %s, M = %s: %s ms", N, M, pc.milliseconds);
}
void main() {
benchmark!(1000, 1000);
benchmark!(10000, 1000);
benchmark!(1000, 10000);
benchmark!(10000, 10000);
}
|
1 2 3 4 5 6 | import std.stdio;
void main() {
long x = mixin("0x12437308CCB6");
writeln(x); // 20080902065334
}
|
与えられたrangeの急勾配性を判定します.
rangeが後ろから手繰れる場合はO(n) time, O(1) space,そうでない場合はO(n) time, O(n) spaceです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | module doukaku248;
import std.algorithm, std.array, std.range, std.traits;
bool isSteep(Range)(Range r) if(isInputRange!(Range)) {
static if(isInfinite!(Range)) {
static assert(false, "steepness of infinite ranges cannot be determined.");
} else static if(isBidirectionalRange!(Range)) {
if(!r.empty) {
auto sum = r.back;
r.popBack;
foreach_reverse(e; r) {
if(e <= sum)
return false;
sum += e;
}
}
return true;
} else {
return isSteep(toArray(r));
}
}
ElementType!(Range)[] toArray(Range)(Range r) if(isInputRange!(Range)) {
static if(isImplicitlyConvertible!(Range, typeof(return))) {
return r;
} else static if(isInfinite!(Range)) {
static assert(false, "infinite ranges cannot be converted to arrays.");
} else {
typeof(return) a;
static if(isForwardRange!(Range)) {
a.length = walkLength(r);
size_t i = 0;
foreach(e; r) {
a[i++] = e;
}
} else {
foreach(e; r) {
a ~= e;
}
}
return a;
}
}
|
1 2 3 4 5 6 7 8 9 | import std.c.stdio;
int main()
{
FILE* fp = fopen("hoge.txt", "w");
scope(exit) fclose(fp);
fputs("hello, world", fp);
return 0;
}
|
x86のBSF命令 (下から数えて何ビット目が立っているか) を使ってみました。 また、uintは4バイト固定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import std.intrinsic: bsf; // x86's BSF instruction
import std.socket;
immutable ushort DUMMY_PORT = 0;
uint mask2bits(in string mask)
{
uint addr = (new InternetAddress(mask, DUMMY_PORT)).addr;
return 32 - bsf(addr);
}
string bits2mask(in uint bits)
{
uint addr = 0xFFFF_FFFF << (32 - bits);
return (new InternetAddress(addr, DUMMY_PORT)).toAddrString;
}
void main()
{
assert (mask2bits("255.255.255.0") == 24);
assert (mask2bits("255.255.255.128") == 25);
assert (mask2bits("255.255.255.255") == 32);
assert (bits2mask(24) == "255.255.255.0");
assert (bits2mask(25) == "255.255.255.128");
assert (bits2mask(32) == "255.255.255.255");
}
|
コマンドライン引数で与えたパスを順にチェックします
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import std.file: exists, isfile, getSize;
import std.stdio;
void main(string[] args) {
foreach(file; args[1..$]) {
if(file.exists) {
if(file.isfile) {
writefln("'%s' has the size of %s byte(s).", file, file.getSize);
} else {
writefln("'%s' is not a file.", file);
}
} else {
writefln("'%s' does not exist.", file);
}
}
}
|
言語組み込みで扱える最大整数は64bitのlongです。なぜか標準ライブラリに16進文字列から整数に変換する関数がないのでC99からstrtollを借ります。
標準ライブラリに多倍長整数はあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import core.stdc.stdlib: strtoll;
import std.bigint: BigInt;
import std.stdio;
void main() {
// longは64bit
long x = strtoll("0x12437308CCB6", null, 16);
writeln(x); // 20080902065334
// BigIntは多倍長整数
BigInt y = "0x2C9C1227FC6520B";
writeln(y); // 200904012311450123
}
|
D言語で。複素数は組込みなので楽ちん。2.029で動作確認しました。 実行結果: 7+0i 3+-15i 1+55i 1.13333+-0.4i 3.60555
1 2 3 4 5 6 7 8 9 10 11 | import std.stdio;
import std.math; // for abs
void main()
{
writefln("%s", (3 + 1i) + (4 - 1i));
writefln("%s", (5 - 9i) - (2 + 6i));
writefln("%s", (5 + 3i) * (5 + 8i));
writefln("%s", (9 - 7i) / (9 - 3i));
writefln("%s", abs(2 + 3i));
}
|
メタプログラミングしてみました。determinant_helper1!(2, "matrix") は "matrix[0][0] * (matrix[1][1]) + -matrix[0][1] * (matrix[1][0]) + 0" という文字列に評価されます。
コンパイル時に式の展開を行うので、定数畳込みが可能で、determinant!(2)([[1, 2], [3, 4]]) のような式はコンパイル時定数として扱えます。
8x8の行列式を計算するだけでコードサイズ2.5MBくらいなりますが :-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import std.stdio : writeln;
import std.metastrings : ToString;
template tuple(T...) {
alias T tuple;
}
template range(int lwr, int upr) {
static if(lwr > upr) {
alias tuple!() range;
} else {
alias tuple!(lwr, range!(lwr + 1, upr)) range;
}
}
template determinant_helper1(int n, string matrix) {
alias determinant_helper2!(n, matrix, range!(0, n - 1)) determinant_helper1;
}
template determinant_helper2(int n, string matrix, x...) {
static if(x.length == 1) {
invariant determinant_helper2 = matrix ~ "[" ~ ToString!(n - x.length) ~ "][" ~ ToString!(x[0]) ~ "]";
} else {
alias determinant_helper3!(n, matrix, 0, x) determinant_helper2;
}
}
template determinant_helper3(int n, string matrix, int idx, x...) {
static if(idx < x.length) {
invariant determinant_helper3 = (idx % 2 ? "-" : "") ~
matrix ~ "[" ~ ToString!(n - x.length) ~ "][" ~ ToString!(x[idx]) ~ "] * " ~
"(" ~ determinant_helper2!(n, matrix, tuple!(x[0 .. idx], x[idx + 1 .. $])) ~ ") + " ~
determinant_helper3!(n, matrix, idx + 1, x);
} else {
invariant determinant_helper3 = "0";
}
}
auto determinant(int n, T)(T[][] matrix) if(n > 0) {
return mixin(determinant_helper1!(n, (matrix.stringof)));
}
void main() {
real[][] m2 = [[1, 2],
[3, 4]];
real[][] m4 = [[1, 2, 3, 4],
[2, 3, 4, 1],
[3, 4, 1, 2],
[4, 1, 2, 3]];
writeln(determinant!(2)(m2));
writeln(determinant!(4)(m4));
}
|
修正.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private import std.stdio : write, writeln;
private import std.string : repeat;
private import std.typecons : defineEnum;
mixin(defineEnum!("数", uint, "〇", "一", "二", "三", "四", "五",
"六", "七", "八", "九", "十"));
enum 空白 = " ";
dstring toDString(string s) {
dstring ds;
foreach(dchar dc; s) ds ~= dc;
return ds;
}
dstring 文字列化(数 かず) {
string もじれつ;
while(かず) {
もじれつ = enumToString(かず % 数.十) ~ もじれつ;
かず /= 数.十;
}
return もじれつ.toDString;
}
void main() {
foreach(い; 数.一 .. 数.十) {
foreach(ろ; 数.一 .. 数.十) {
auto もじれつ = 文字列化(い * ろ);
write(空白.repeat(数.三 - もじれつ.length), もじれつ);
}
writeln();
}
}
|
defineEnumは列挙型と、列挙型<=>文字列を相互変換する関数を定義するテンプレートです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private import std.stdio : write, writeln;
private import std.string : repeat;
private import std.typecons : defineEnum;
private import std.utf : toUTF32;
mixin(defineEnum!("数", uint, "〇", "一", "二", "三", "四", "五",
"六", "七", "八", "九", "十"));
enum 空白 = " ";
dstring 文字列化(数 かず) {
string もじれつ;
while(かず) {
もじれつ = enumToString(かず % 数.十) ~ もじれつ;
かず /= 数.十;
}
return もじれつ.toUTF32;
}
void main() {
foreach(い; 数.一 .. 数.十) {
foreach(ろ; 数.一 .. 数.十) {
auto もじれつ = 文字列化(い * ろ);
write(空白.repeat(3 - もじれつ.length), もじれつ);
}
writeln();
}
}
|
D2.020から言語コアと標準ライブラリが分離されました。 なぜか言語コアのほうに含まれているThreadGroupなるユーティリティクラスを使ってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private import core.thread, std.stdio;
void main() {
auto threads = new ThreadGroup;
threads.create({
foreach(x; "0123456789") {
write(x);
Thread.yield;
}
});
threads.create({
foreach(x; "abcdefghij") {
write(x);
Thread.yield;
}
});
threads.joinAll;
}
|
因数分解する方針で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | import std.stdio;
struct HammingNumbers {
static bool isHammingNumber(uint n) {
static bool[uint] memo;
if(n == 1) return true;
if(auto p = n in memo) return *p;
if(n % 2 == 0)
return memo[n] = isHammingNumber(n / 2);
if(n % 3 == 0)
return memo[n] = isHammingNumber(n / 3);
if(n % 5 == 0)
return memo[n] = isHammingNumber(n / 5);
return memo[n] = false;
}
static int opApply(int delegate(ref const(size_t), ref const(uint)) dg) {
size_t i = 0;
uint n = 1;
while(true) {
if(isHammingNumber(n)) {
if(auto result = dg(i, n))
return result;
i++;
}
n++;
}
}
}
void main(){
foreach(i, n; HammingNumbers) {
if(i == 100) break;
writeln(i, ": ", n);
}
}
|
テンプレート引数の推論を使って型無しラムダっぽく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import std.stdio;
void main() {
auto Y = new class {
auto opCall(_)(_ f) {
return (new class {
auto opCall(_)(_ g) {
return new class {
auto opCall(_)(_ x) {
return f(g(g))(x);
}
};
}
})(new class {
auto opCall(_)(_ g) {
return new class {
auto opCall(_)(_ x) {
return f(g(g))(x);
}
};
}
});
};
};
auto F = new class {
auto opCall(_)(_ f) {
return new class {
auto opCall(_)(_ x) {
if (x == 0) {
return cast(_)1;
} else {
return x * f(x - 1);
}
}
};
}
};
auto factorial = Y(F);
writeln("fact(5) = ", factorial(10));
writeln("fact(5) = ", factorial(20L));
}
|
C++のを真似ようと思ったのですが、なんだか普通になってしまいました。 入力はリテラル、出力はコンパイラメッセージで。
出力:
123 234.5k 345.6M 456.7G 567.8T d202.d(39): static assert "done!"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | static import std.metastrings;
struct None { enum Symbol = "", Base = 1; }
struct Kilo { enum Symbol = "k", Base = 1e+3; }
struct Mega { enum Symbol = "M", Base = 1e+6; }
struct Giga { enum Symbol = "G", Base = 1e+9; }
struct Tera { enum Symbol = "T", Base = 1e12; }
template SIPrefix(long n) {
static if(n < Kilo.Base)
alias None SIPrefix;
else static if(n < Mega.Base)
alias Kilo SIPrefix;
else static if(n < Giga.Base)
alias Mega SIPrefix;
else static if(n < Tera.Base)
alias Giga SIPrefix;
else
alias Tera SIPrefix;
}
template SIFormat(long n) {
enum SIFormat = ToString!(n / SIPrefix!(n).Base) ~ SIPrefix!(n).Symbol;
}
private template ToString(real x) {
enum ToString = ToString!(cast(long)x) ~ "." ~ ToString!(cast(long)(x * 10))[$ - 1];
}
private template ToString(long x) {
enum ToString = std.metastrings.ToString!(x);
}
pragma(msg, SIFormat!(123));
pragma(msg, SIFormat!(234567));
pragma(msg, SIFormat!(345678901));
pragma(msg, SIFormat!(456789012345));
pragma(msg, SIFormat!(567890123456789));
static assert(false, "done!"); // コンパイル終了
|
使用例も書かないとダメですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import std.conv;
import std.date;
import std.stdio;
string DateEx(string datetime, int tdelta_in_secs)
{
d_time t = std.date.parse(datetime);
d_time new_datetime = t + tdelta_in_secs * std.date.TicksPerSecond;
return std.date.toString(new_datetime);
}
unittest {
assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", -3600) ==
"Mon Sep 01 12:00:00 GMT+0900 2008");
assert(DateEx("Mon Sep 01 13:00:00 GMT+0900 2008", 3600) ==
"Mon Sep 01 14:00:00 GMT+0900 2008");
}
void main(string[] args)
{
string datetime;
int tdelta_in_secs;
if (args.length == 3) {
datetime = args[1];
tdelta_in_secs = toInt(args[2]);
}
else {
d_time now = std.date.getUTCtime;
datetime = std.date.toString(now);
tdelta_in_secs = toInt(args[1]);
}
writefln("%s", DateEx(datetime, tdelta_in_secs));
}
// eof
|





匿名
#9719()
[
D
]
Rating0/0=0.00
こうかな
Rating0/0=0.00-0+
[ reply ]