Language detail: D

Coverage: 52.28%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

自分自身を表示する (Nested Flatten)

こうかな

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import std.stdio;

char c = 34;
auto s ="import std.stdio;

char c = 34;
auto s =%s%s%s;

void main() {
  writef(s, c, s, c);
}";

void main() {
  writef(s, c, s, c);
}
シードを固定した乱数 (Nested Flatten)

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;
        }
    }
}
バイナリクロック (Nested Flatten)
 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));
}
漢数字で九九の表 (Nested Flatten)

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();
    }
}
リングノードベンチマーク (Nested Flatten)
ファイバを用いました。

N = 1000, M = 1000: 719 ms
N = 10000, M = 1000: 11521 ms
N = 1000, M = 10000: 11079 ms
N = 10000, M = 10000: 114837 ms
 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);
}
16進数から10進数の変換 (Nested Flatten)
苦肉の策です(笑) 全く、リテラルは2進数までサポートしているくせに…
1
2
3
4
5
6
import std.stdio;

void main() {
    long x = mixin("0x12437308CCB6");
    writeln(x); // 20080902065334
}
急勾配の判定 (Nested Flatten)

与えられた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;
    }
}
loan patternのサンプル (Nested Flatten)
BOOST_SCOPE_EXITでも紹介しようかなと思いましたが、本家っぽい感じがしたD言語で書いてみました。いずれにせよ、スコープを抜けるときに対象の文を実行するというものという点では同じです。
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;
}
IPv4アドレスのマスクの変換 (Nested Flatten)
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");
}
ファイルサイズの取得 (Nested Flatten)

コマンドライン引数で与えたパスを順にチェックします

 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);
        }
    }
}
16進数から10進数の変換 (Nested Flatten)

言語組み込みで扱える最大整数は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
}
複素数 (Nested Flatten)
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));
}
行列式の計算 (Nested Flatten)

メタプログラミングしてみました。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));
}
漢数字で九九の表 (Nested Flatten)

修正.

 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();
    }
}
疑似並行処理 (Nested Flatten)

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;
}
2^i * 3^j * 5^k なる整数 (Nested Flatten)

因数分解する方針で。

 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);
    }
}
不動点演算子 (Nested Flatten)

テンプレート引数の推論を使って型無しラムダっぽく。

 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));
}
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)

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!"); // コンパイル終了
文字列型日時ののN秒後時間取得 (Nested Flatten)

使用例も書かないとダメですね。

 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
next >>

Index

Feed

Other

Link

Pathtraq

loading...