Thread: Optimization Level 2 produces error

  1. #1
    Registered User
    Join Date
    Sep 2009
    Posts
    7

    Optimization Level 2 produces error

    I've written this little sample program to illustrate the problem:
    Code:
     
      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 int main()
      5 {
      6    double a = 2.3492e8,b;
      7    extern double test(double);
      8 
      9    b = test(a);
     10 
     11    printf("%e\n",b);
     12 
     13 }
     14 
     15 double test(double a)
     16 {
     17    long tmp;
     18    double ret;
     19 
     20    tmp = *(long*)&a;      // copy ieee-754 representation of "a" to "tmp"
     21    tmp = tmp >> 5;
     22    tmp = tmp << 5;
     23    ret = *(double*)&tmp;
     24    
     25    return ret;
     26 }
    It is supposed to shift the bit-representation of "a" to the right and to the left again, which works when compiling without optimization or with level 1 optimization (-O switch for gcc). But with level 2 optimization (-O2) the program outputs zero. My problem is also that I can't really debug with optimization, somehow the instructions are mixed or seem to be skipped.
    Does anybody have an idea why this is? I really need to use second level optimization.

    My system is Debian squeeze x86-64 with gcc 4.3.3

  2. #2
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    Why are you using extern with the declaration?
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  3. #3
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Tried it and work fine for me

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I had the same result as the OP, gcc 4.3.2

    It's because of this line:
    Code:
    tmp = *(long*)&a;
    if you change it to:
    Code:
    tmp = (long)a;
    It works...however, this does not yield the same value .

    Here is a very weird thing. I tried:
    Code:
    memcpy(&tmp,&a,sizeof(long));
    instead of the tmp assignment. Compiled without -O2, this gives the correct result (2.349200e+08). Compiled with -O2, it gives 2.072910e-317 -- which is the exact same if you compile the "tmp = (long)a" version optimized (unoptimized, that one is 1.160659e-315).

    Go figure.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Is long 32 bits or 64 bits? If it's 32, then it's not big enough to hold the bit pattern of a double. Now, consider this line:

    Code:
    ret = *(double*)&tmp;
    This will actually read past the end of tmp, because tmp is shorter than a double. What you find beyond the end of tmp is undefined, and can easily change with compiler settings.

    This piece of code is absolutely horrific. I'm glad it's failing.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    Registered User
    Join Date
    Sep 2009
    Posts
    7
    Quote Originally Posted by BEN10 View Post
    Why are you using extern with the declaration?
    I'm a beginner to C. Is it correct to just cross out the extern?

    to brewbuck:
    long is 64 bits, could you please help me to improve this piece of code?

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Nb. I am on 64-bit so they are the same length.

    I didn't consider that if gcc -O2 didn't like the first zany assignment it won't like the second!

    Anyway, this works -02:
    Code:
       tmp = (long)a;
       tmp = tmp >> 5;
       tmp = tmp << 5;
       ret = (double)tmp;
    But that still depends on long and double being the same size.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    DESTINY BEN10's Avatar
    Join Date
    Jul 2008
    Location
    in front of my computer
    Posts
    804
    Quote Originally Posted by 0xa4 View Post
    I'm a beginner to C. Is it correct to just cross out the extern?
    In your case, extern is redundant, so you can remove it.
    HOPE YOU UNDERSTAND.......

    By associating with wise people you will become wise yourself
    It's fine to celebrate success but it is more important to heed the lessons of failure
    We've got to put a lot of money into changing behavior


    PC specifications- 512MB RAM, Windows XP sp3, 2.79 GHz pentium D.
    IDE- Microsoft Visual Studio 2008 Express Edition

  9. #9
    Registered User
    Join Date
    Sep 2009
    Posts
    7
    I'm sorry, I didn't clearly explain what I want to achieve. I want to want to manipulate the bit representation of a double, not cast the actual value to a long integer. I will now look into this memcopy function, maybe this is what I need (though I still don't see why my code would work with optimization level 1 but not with level 2...)

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by 0xa4 View Post
    I'm sorry, I didn't clearly explain what I want to achieve. I want to want to manipulate the bit representation of a double, not cast the actual value to a long integer. I will now look into this memcopy function, maybe this is what I need (though I still don't see why my code would work with optimization level 1 but not with level 2...)
    The normal way of doing this is "type punning."

    Code:
    union DoubleBits
    {
        double d;
        unsigned long a; /* unsigned long must be same size as double */
    };
    First you store the double value in the d element, then access its bits in the a element. This is getting into undefined territory (it's technically not defined to read one union element after writing some different element), but then again, your original approach is undefined as well. In practice it works.
    Last edited by brewbuck; 12-02-2009 at 01:02 PM.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by 0xa4 View Post
    I'm sorry, I didn't clearly explain what I want to achieve. I want to want to manipulate the bit representation of a double, not cast the actual value to a long integer.
    Well you might as well do this then:
    Code:
    double a = 2.3492e8;
    a = (int)a << 5;
    though I still don't see why my code would work with optimization level 1 but not with level 2...)
    Probably because *(cast*)&x is implicitly redundant.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MK27 View Post
    Code:
    double a = 2.3492e8;
    a = (int)a << 5;
    That does not have the intended effect. The intention is to alter the bits in the double value without regard to their numerical meaning. The code above just casts the value to an integer with truncation. The results aren't even remotely the same.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  13. #13
    Registered User
    Join Date
    Sep 2009
    Posts
    7
    thanks a lot for the help, the union finally worked. However i couldn't get it to work with your syntax, it kept giving me 'x' undeclared, first use in this function errors, but I found another syntax with a typedef keyword that worked here.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Linking to shlwapi.lib in C, MSVC CMD.
    By Joerge in forum Windows Programming
    Replies: 4
    Last Post: 08-07-2009, 05:18 PM
  2. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  3. Making C DLL using MSVC++ 2005
    By chico1st in forum C Programming
    Replies: 26
    Last Post: 05-28-2008, 01:17 PM
  4. We Got _DEBUG Errors
    By Tonto in forum Windows Programming
    Replies: 5
    Last Post: 12-22-2006, 05:45 PM
  5. Couple C questions :)
    By Divx in forum C Programming
    Replies: 5
    Last Post: 01-28-2003, 01:10 AM