在编译时评估表达式
evaluate expression at compile time
我知道这个问题被问了很多,但仅限于 C/C++ 和 Java。
问题与使用常量表达式的性能优势有关:
当我调用仅使用常量作为参数的静态函数时,有没有办法告诉编译器它应该在编译时评估调用并用结果替换调用?
示例:
const double pi = Math.PI; //works as Math.PI is a constant
const double spi = Math.Sin(Math.PI); //compiler error, because expression must be constant
是否没有指令(更好:属性)明确地告诉编译器像 Math.Sin() 这样的静态方法不会在内部修改或读取任何数据,因此在技术上可以评估调用在编译时?
哦,请不要像 "just do const double spi = 0
" :) 那样回答,因为我的示例只是我遇到的问题的简化版本:在保持最佳性能的同时提高代码可维护性。
感谢您的帮助 - 非常感谢!
没有副作用的方法有 [Pure] 属性。但是,这仅用于代码分析,而不是由编译器(目前)使用。但是,这可能会在未来发生变化。
JetBrains ReSharper 提供了类似的 [Pure] 属性用于相同的目的(代码分析)。
因此,目前,您需要一个解决方法,例如您预先计算的值,最好附上评论,让其他人知道该值的来源:
const double spi = 0.0; // Math.Sin(Math.PI)
或
static readonly double spi = Math.Sin(Math.PI);
这当然会计算运行时的值,这是您不想要的。
对于数字常量,我看到两个选项:
方案一:使用static readonly(启动时计算一次):
class MyCalc
{
private static readonly double spi = Math.Sin(Math.PI);
private static readonly double pi = Math.PI;
public void Execute()
{
// .. whatever
}
}
选项二:使用袖珍计算器进行计算并对这些常量进行硬编码:
class MyCalc
{
// Math.Sin(Math.Pi)
private const double spi = 0;
// Math.Pi
private const double pi = 3.141592653589793;
public void Execute()
{
// .. whatever
}
}
我不确定,如果编译器可以在计算中完全优化选项一,但它应该是最可读和可维护的方式。
如果您希望在编译时做尽可能多的事情,事情就会变得更难。在 C++ 下你有模板。我发现它们写起来很麻烦,但人们得到 amazing things done with it. It seems it got easier with compile time functions but I haven't tried them yet. D have CTFE 这真的很强大。但 D 是一个小众市场,我会避免在其中编写任何严肃的代码。我不知道其他语言有相当多的显式预编译评估,但我确信有一些。
如今的编译器非常聪明。编译器很有可能会看到机会在没有提示的情况下内联优化函数调用。在 DotNet 4.5 中,我们得到了 AggressiveInlining-attribute so we might to be able to force the compiler into the right direction. C/C++ have something similar and there had been problems。我这边的一般建议是避免inline
,直到你完全知道自己在做什么。
如果你真的不想从 C# 走这条路,在我看来最好的选择是使用提到的功能在 C++ 中编写你的功能,编写一个易于使用的 C 接口并通过 PInvoke。但是,如果真的值得,请先帮自己一个忙并衡量一下。永远不要忘记两个优化规则:
- 不要
- 还不知道(仅限专家)
我知道这个问题被问了很多,但仅限于 C/C++ 和 Java。 问题与使用常量表达式的性能优势有关:
当我调用仅使用常量作为参数的静态函数时,有没有办法告诉编译器它应该在编译时评估调用并用结果替换调用?
示例:
const double pi = Math.PI; //works as Math.PI is a constant
const double spi = Math.Sin(Math.PI); //compiler error, because expression must be constant
是否没有指令(更好:属性)明确地告诉编译器像 Math.Sin() 这样的静态方法不会在内部修改或读取任何数据,因此在技术上可以评估调用在编译时?
哦,请不要像 "just do const double spi = 0
" :) 那样回答,因为我的示例只是我遇到的问题的简化版本:在保持最佳性能的同时提高代码可维护性。
感谢您的帮助 - 非常感谢!
没有副作用的方法有 [Pure] 属性。但是,这仅用于代码分析,而不是由编译器(目前)使用。但是,这可能会在未来发生变化。
JetBrains ReSharper 提供了类似的 [Pure] 属性用于相同的目的(代码分析)。
因此,目前,您需要一个解决方法,例如您预先计算的值,最好附上评论,让其他人知道该值的来源:
const double spi = 0.0; // Math.Sin(Math.PI)
或
static readonly double spi = Math.Sin(Math.PI);
这当然会计算运行时的值,这是您不想要的。
对于数字常量,我看到两个选项:
方案一:使用static readonly(启动时计算一次):
class MyCalc
{
private static readonly double spi = Math.Sin(Math.PI);
private static readonly double pi = Math.PI;
public void Execute()
{
// .. whatever
}
}
选项二:使用袖珍计算器进行计算并对这些常量进行硬编码:
class MyCalc
{
// Math.Sin(Math.Pi)
private const double spi = 0;
// Math.Pi
private const double pi = 3.141592653589793;
public void Execute()
{
// .. whatever
}
}
我不确定,如果编译器可以在计算中完全优化选项一,但它应该是最可读和可维护的方式。
如果您希望在编译时做尽可能多的事情,事情就会变得更难。在 C++ 下你有模板。我发现它们写起来很麻烦,但人们得到 amazing things done with it. It seems it got easier with compile time functions but I haven't tried them yet. D have CTFE 这真的很强大。但 D 是一个小众市场,我会避免在其中编写任何严肃的代码。我不知道其他语言有相当多的显式预编译评估,但我确信有一些。
如今的编译器非常聪明。编译器很有可能会看到机会在没有提示的情况下内联优化函数调用。在 DotNet 4.5 中,我们得到了 AggressiveInlining-attribute so we might to be able to force the compiler into the right direction. C/C++ have something similar and there had been problems。我这边的一般建议是避免inline
,直到你完全知道自己在做什么。
如果你真的不想从 C# 走这条路,在我看来最好的选择是使用提到的功能在 C++ 中编写你的功能,编写一个易于使用的 C 接口并通过 PInvoke。但是,如果真的值得,请先帮自己一个忙并衡量一下。永远不要忘记两个优化规则:
- 不要
- 还不知道(仅限专家)