Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

evaluate expression at compile time

I know this has been asked a lot, but only for C/C++ and Java. The question is related to the performance benefits of using constant expressions:

When I call a static function with only constants as arguments, is there a way to tell the compiler that it should evaluate the call already at compile time and replace the call by the result?

Example:

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  

Are there no directives (better: Attributes) to tell the compiler explicitely that a static method like Math.Sin() is not modifying nor reading any data internally, so that it was technically possible to evaluate the call at compile time?

Oh, and please don't answer like "just do const double spi = 0" :), because my example is just a simplified version of the problem I have: Improving code maintainability while keeping maximum performance.

Thanks for any help - it is really appreciated!

like image 438
Reinski Avatar asked Nov 04 '15 09:11

Reinski


People also ask

What is compile time evaluation?

In computing, compile-time function execution (or compile time function evaluation, or general constant expressions) is the ability of a compiler, that would normally compile a function to machine code and execute it at run time, to execute the function at compile time.

How do you calculate compile time?

Hence taking the difference of starts and ends will give you execution time of test_case() in second multiplied by CLOCKS_PER_SEC . CLOCKS_PER_SEC is the number of clock ticks per second. Compile time calculation can be done using template metaprogramming.

Is constant expressions are evaluated at compile time?

A constant expression gets evaluated at compile time, not run time, and can be used in any place that a constant can be used. The constant expression must evaluate to a constant that is in the range of representable values for that type.

What is known at compile time?

In computer science, compile time (or compile-time) describes the time window during which a computer program is compiled.


2 Answers

For numerical constants I see two options:

Option one: use static readonly (calculated once at startup):

class MyCalc
{
    private static readonly double spi = Math.Sin(Math.PI);
    private static readonly double pi = Math.PI;

    public void Execute()
    {
        // .. whatever
    }
}

Option two: perform calculations with your pocket calculator and hardcode those constants:

class MyCalc
{
    // Math.Sin(Math.Pi)
    private const double spi = 0;
    // Math.Pi
    private const double pi = 3.141592653589793;

    public void Execute()
    {
        // .. whatever
    }
}

I'm not sure, if the compiler can completely optimize away option one in a calculation but it should be the most readable and maintainable way.

If you are looking for doing as much at compile-time as possible, things get harder. Under C++ you have templates. I find them cumbersome to write but people get amazing things done with it. It seems it got easier with compile time functions but I haven't tried them yet. D have CTFE which is really powerful. But D is a niche and I would avoid to write any serious code in it. I am not aware of other languages with a considerable explicit precompilation evaluation but I'm sure there are some.

Compilers are quite smart these days. Chances are good that a compiler might see an opportunity to inline an optimize a function call without an hint. With DotNet 4.5, we've got the 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. General advice from my side would be to avoid inline until you exactly know what you are doing.

If you really wan't to go this way from C#, the best option in my eyes would be to write your functionality in C++ using the mentioned features, write an easy to use C-interface and call it by PInvoke. But do yourself a favor and measure before if it is really worth it. Never forget the two rules of optimization:

  1. Don't
  2. Don't yet (experts only)
like image 115
Peter Schneider Avatar answered Sep 30 '22 15:09

Peter Schneider


There is the [Pure] attribute for methods which have no side effects. However, this is only used for code analysis and not by the compiler (at the moment). However, this might change in the future.

JetBrains ReSharper provides a similar [Pure] attribute for the same purpose (code analysis).

So, for the moment, you need a workaround like a value pre-calculated by you, best with a comment for someone else to know the source of the value:

const double spi = 0.0; // Math.Sin(Math.PI)

or

static readonly double spi = Math.Sin(Math.PI);

which of course calculates the value to runtime, which you don't want.

like image 37
Thomas Weller Avatar answered Sep 30 '22 14:09

Thomas Weller