D隐式转换Vector(T)类型

时间:2012-01-09 22:46:41

标签: benchmarking d dmd microbenchmark

比较代码片段A:

struct Vector2(T) {
    // ...

    auto opCast(U)() {
        return U(x, y);
    }

    void opOpAssign(string op)(Vector2 vector) {
        mixin ("x" ~ op ~ "= vector.x;");
        mixin ("y" ~ op ~ "= vector.y;");
    }
}

void main() {
    auto fVec = Vector2!float(1.5, 1.5);
    auto dVec = Vector2!double(1.5, 1.5);

    // Benchmark: Loop following 10 million times.
    fVec += cast(Vector2!float)  dVec;
    dVec -= cast(Vector2!double) fVec;
}

与B:

struct Vector2(T) {
    // ...

    void opOpAssign(string op, U)(Vector2!U vector) {
        mixin ("x" ~ op ~ "= vector.x;");
        mixin ("y" ~ op ~ "= vector.y;");
    }
}

void main() {
    auto fVec = Vector2!float(1.5, 1.5);
    auto dVec = Vector2!double(1.5, 1.5);

    // Benchmark: Same as A.
    fVec += dVec;
    dVec -= fVec;
}

在我的基准测试(DMD,Win7)中,A比B快约50ms。这是什么原因?如果A更快我想使用它,但我不能得到Vector2!double来隐式地转换为Vector2!float无论我尝试什么。关于如何隐式投射这些类型的任何想法?或者是否有一些争论为什么我不应该隐含地施放它们?

我正在设置GDC和LDC来与这些编译器进行此基准测试,但有人知道这是否只是DMD优化问题?

2 个答案:

答案 0 :(得分:3)

就编译器而言,同一模板的两个不同实例没有比两个完全独立的类型更多的共同点。你可以声明

struct VectorFloat
{
    ...
}

struct VectorDouble
{
    ...
}

而不是模板化Vector2,它没有任何区别。 Vector2!floatVector!double是完全不同的类型。对于您声明的任何类型,如果您想要在它们之间进行转换,您将必须声明它们 - 无论是opCastalias this,构造函数还是其他任何类型。我相信,你将隐式转换工作的唯一方法是使用alias this,尽管ratchet freak指出,隐式转换浮点数和双精度数是 D通常如何运作,可以说是一个坏主意。

至于为什么A比B快,我不知道。我本来希望它是另一种方式。但是,根据编译器究竟在做什么,它可能会在以后发生变化,并且它可能很容易因编译器而异。而且由于你只看到超过 1000万次迭代的50ms差异,我会从API的角度来看更合理的版本(无论你认为是什么)。我会争论第一个,因为我不认为在float和double之间隐式转换是个好主意,但这取决于你,因为它是你的代码。

顺便说一下,如果需要,可以使用std.conv.to而不是直接调用opCast。这种方式不那么容易出错,因为如果你搞砸定义opCast它就会大喊大叫,而编译器更有可能只是这样做,因为演员是一个非常钝的工具。

答案 1 :(得分:1)

你不应该隐式地将double强制转换为单个精度float点,就像你不能隐式地从long转换为{{1}因为你会失去精确度。

大多数语言要求您在转换时想要丢失精确度时明确说明。并且最好是遵循语言中的现有约定而不是强制执行自己的约定。