D 隐式转换 Vector(T) 类型

发布于 2024-12-26 00:03:09 字数 1174 浏览 1 评论 0 原文

比较代码片段 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 快约 50 毫秒。为什么会这样?如果 A 更快,我想使用它,但无论我如何尝试,我都无法让 Vector2!double 隐式转换为 Vector2!float。关于如何隐式转换这些类型有什么想法吗?或者是否有一些争论为什么我不应该隐式地投射它们?

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

Compare code fragments 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;
}

with 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;
}

In my benchmarks (DMD, Win7), A is ~50ms faster than B. Any reason why this is? If A is faster I would like to use it, but I can't get Vector2!double to implicitly cast to a Vector2!float no matter what I try. Any idea on how I can implicitly cast these types? Or is there some argument to why I shouldn't implicitly cast them?

I'm setting up GDC and LDC to do this benchmark with those compilers, but does anyone know offhand if this is a DMD only optimization issue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

染火枫林 2025-01-02 00:03:09

就编译器而言,同一模板的两个不同实例没有什么共同点,只不过是两个完全独立的类型。您可以声明

struct VectorFloat
{
    ...
}

struct VectorDouble
{
    ...
}

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

至于为什么A比B快,我不知道。我实际上预计情况会是相反的。但根据编译器到底在做什么,它可能会在以后发生变化,并且它很容易因编译器的不同而有所不同。由于您在 1000 万 次迭代中只看到了 50 毫秒的差异,因此我会选择从 API 角度来看更有意义的版本(无论您认为是哪一个)。不过,我反对使用第一个,只是因为我认为在 float 和 double 之间隐式转换不是一个好主意,但这取决于您,因为这是您的代码。

顺便说一句,如果您愿意,您可以使用 std.conv.to 而不是直接调用 opCast 。这样就不太容易出错,因为如果你搞砸了 opCast 的定义,它会大喊大叫,而编译器更可能无论如何都会这样做,因为强制转换是一种非常生硬的工具。

Two different instantiations of the same template have nothing more in common than two completely separate types as far as the compiler is concerned. You could declare

struct VectorFloat
{
    ...
}

struct VectorDouble
{
    ...
}

instead of templatizing Vector2, and it would make no difference. Vector2!float and Vector!double are completely different types. And with any types that you declare, if you want ways to convert between them, you're going to have to declare them - be they opCast, alias this, constructors, or whatever. I believe that the only way that you're ever going to get implicit conversion to work is with alias this, though as ratchet freak points out, implicitly converting between floats and doubles is not how D normally works and is arguably a bad idea.

As to why A is faster than B, I don't know. I would have actually expected it to be the other way around. But depending on what exactly the compiler is doing, it could change later, and it could easily vary from compiler to compiler. And since you're only seeing a 50ms difference over 10 million iterations, I'd go with the version that makes more sense from an API perspective (whichever you think that is). I'd argue going with the first one though, simply because I don't think that it's a good idea to implicitly convert between float and double, but that's up to you, since it's your code.

By the way, you can use std.conv.to instead of calling opCast directly if you want. It's less error-prone that way, since then it'll yell if you screw up defining opCast, whereas the compiler is more likely to just do it anyway, since cast is very much a blunt instrument.

心是晴朗的。 2025-01-02 00:03:09

您不应该将 double 隐式转换为 single 精度浮​​点,就像您不能从 long 隐式转换一样code> 到 int 因为你会失去精度。

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

You shouldn't implicitly cast double to single precision floating point, just like you can't implicitly convert from long to int because you'll lose precision.

Most languages require you to make it clear when you want to lose precision when converting. and it is best if you follow the existing conventions in the language instead of enforcing your own.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文