Блог пользователя raghav_19

Автор raghav_19, история, 6 лет назад, По-английски

In this problem, i was using fft to solve it but found very strange behaviour between two case. submission1 in which my fft code and its function are written are written normally which gave me TLE in mostly all cases but in submission2 when I put all fft function into struct and my code get AC.

struct is the only change between two submission. Can someone explain the reason behind this.

  • Проголосовать: нравится
  • +57
  • Проголосовать: не нравится

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +45 Проголосовать: не нравится

The difference is that the compiler deduced that mod was in fact a constant when it was in struct scope, and avoided using the expensive idiv instruction. ll mod=M; is a very bad idea, a single const would speed your code up a lot without relying on the compiler being that smart.

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +11 Проголосовать: не нравится

    Thanks for the help, You are right I just checked again by adding const and it speed up the code by around 4 times. but I have 2 doubt here.

    1. why compiler deduced mod as constant in struct scope. I mean mod value can be changed, right?

    2. Either mod is const or not , how it is effecting the runtime?.

    I tried to search both question but couldn't find anything. If you have anything to read can you please share it.

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +6 Проголосовать: не нравится

      For (2), you can try to use godbolt to try to see the assembly output of mod a constant or not. You can see the compiler will optimize and not use the idiv mentioned above.

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +22 Проголосовать: не нравится

      It can be deduced because it's a member variable of a struct, and there isn't any code which modifies it. Interestingly, just having a function in that struct returning a non-const pointer to mod will break the assumption and your program will be slower. You may ask the question why the same can't be said for the global variable? It has to do with the concept of linkage. Global variables by default have external linkage, meaning that, in theory, some other code (for example, in another cpp file) can access it and modify it while the program is running, and that's why the compiler can't assume its value won't change, and therefore has to emit the slower idiv.

      As I said, if you don't know the modulo in advance, you must use the expensive idiv, but if you do, there are some tricks that allow you to compute the modulo faster. As a trivial example, if you want to compute modulo $$$2$$$, you just look at the last binary digit. What's cool is that similar tricks exist for all modulos.

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    I dont underestand very well, in few words, initialize a variable like mod is faster if i declare as const?

    • »
      »
      »
      6 лет назад, скрыть # ^ |
       
      Проголосовать: нравится +5 Проголосовать: не нравится

      No, it's not faster. What's faster is division by a constant compared to division by a variable. That is why:

      const int MOD = 1000000009;
      ...
      a % MOD
      

      and

      a % 1000000009
      

      are both much faster than

      int MOD = 1000000009;
      ...
      a % MOD
      

      That is because when MOD is constant, the compiler can optimize division to a multiplication and a shift. If it's not a constant, this optimization can't be done. (in theory it can be done, but calculating how much to shift and what to multiply by is slower than just performing a division)