Ahmed_Hussein_Karam's blog

By Ahmed_Hussein_Karam, history, 5 months ago, In English

One lesson I have learned on last Div #3 contest is "avoid using pow() function in C++, it is can lead to Wrong Answer".

I am sharing this with a practical example:

This submission works only if you replace long long p = pow(n1, 3) + pow(mid, 3);

with long long p = n1 * n1 * n1 + mid * mid * mid;

I feel like it is useful to sare it !

 
 
 
 
  • Vote: I like it
  • +34
  • Vote: I do not like it

»
5 months ago, # |
  Vote: I like it 0 Vote: I do not like it

Do you know why this happens?

  • »
    »
    5 months ago, # ^ |
      Vote: I like it +26 Vote: I do not like it

    https://en.cppreference.com/w/cpp/numeric/math/pow

    Because it shouldn't be used for integers.

  • »
    »
    5 months ago, # ^ |
      Vote: I like it +82 Vote: I do not like it

    I have a blog explaining about why this stuff happens Explanation to weird/strange floating point behaviour in C++.

    The explanation is not simply that pow is based on floating point numbers! The real culprit is the weird floating point behaviour of 32 bit g++. For example submitting the code under C++17(64 bit) gets AC 107846368. I can also get AC 107868857 in C++11(32 bit) by turning off most of the weird floating point behaviour with a pragma.

    Floating point numbers are a lot more safe than what people give them credit for. To be honest, people just don't know what they are talking about. Fundamentally doubles can be used for exact integer calculations up to 2^53. For example I often use doubles for integer calculations in Python for some extra speed, and I've never gotten WA from it. It is just 32bit g++ that handles floating point numbers in a fucked up way.

    • »
      »
      »
      5 months ago, # ^ |
        Vote: I like it +2 Vote: I do not like it

      Beautiful reply from a person from beautiful country!

      Canadian duck is cool too!

    • »
      »
      »
      5 months ago, # ^ |
        Vote: I like it +43 Vote: I do not like it

      The following is a fun example of how fucked up floating point numbers are in 32 bit g++ using a small modification of his code. In it I've added the seemingly useless line

      fmod(mid3,1);
      

      calculating mid3 % 1 and not even storing the result. Clearly doing this should have no effect, right?

      With the "useless" line:

      Spoiler

      Without the "useless" line:

      Spoiler
»
5 months ago, # |
Rev. 2   Vote: I like it +3 Vote: I do not like it

It is mainly because pow function returns double and when we convert it to integer , sometimes it gives wrong answer due to ignoring the decimal part. For eg suppose if the returned value is 99.999999 then it will give answer as 99 whereas if the answer is 100.00001 it will be 100.For avoiding this I use this as it always gives correct answer:-

Code
»
5 months ago, # |
Rev. 2   Vote: I like it +19 Vote: I do not like it
»
5 months ago, # |
  Vote: I like it +21 Vote: I do not like it

I never understand why people are amused by this 'problem' so much and even write blogs. It's simple — floating point functions, all of them, like pow and log or literally anything else, are not exact and shouldn't be used in integer tasks. Write your own algorithms like binary exponention or a for loop yourself.

  • »
    »
    5 months ago, # ^ |
      Vote: I like it -17 Vote: I do not like it

    Thanks imachug for completing the information for us. I agree with you, it is just usual that people "especially those not so knowledgeable" can forget about it and get Wrong Answers as a result. Just like what happened with me.

  • »
    »
    5 months ago, # ^ |
      Vote: I like it -10 Vote: I do not like it

    It's a common mistake. People may not know pow uses floating point in the first place. Or that floating points have precision issues. Some IDEs tell you, but not all and it can be easy to miss anyway.

    I don't know why some people forget or ignore what it is like not to know.

    And yes, you should write a binary exponentiation or a for loop when you want to get powers, because of that.

»
5 months ago, # |
Rev. 2   Vote: I like it -31 Vote: I do not like it

abs() is bad before C++11

»
5 months ago, # |
  Vote: I like it 0 Vote: I do not like it

I modified one line from your code(long long p = (long long)(pow(n1, 3) + 0.5) + (long long)(pow(mid, 3) + 0.5)) and it gave AC(my code). I read about this, here.

»
5 months ago, # |
  Vote: I like it +6 Vote: I do not like it

lol, just realized that there is a function called cbrt() which is short for cubic root.

So I was today years old when I learned that sqrt() has it's funny name because it calculates the square root.