Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my arithmetic with a long long int behaving this way?

I'm trying to calculate large integers with the long long datatype but when it gets large enough (2^55), the arithmetic behavior is unpredictable. I am working in Microsoft Visual Studio 2017.

In this first case, I am subtracting 2 from the long long variable m in the initialization. This works fine for all n until I try 54, then m will simply not be subtracted by 2.

#include <iostream> #include <string> #include <algorithm> #include <vector> #include <map> #include <set>  using namespace std;  #define LL long long  int main() {     LL n;     cin >> n;     LL m = pow(2, n + 1) - 2;     cout << m;     return 0; } 

However, using this code m does get subtracted by 2 and is working as I would expect.

#include <iostream> #include <string> #include <algorithm> #include <vector> #include <map> #include <set>  using namespace std;  #define LL long long  int main() {     LL n;     cin >> n;     LL m = pow(2, n + 1);     m -= 2;     cout << m;     return 0; } 

I expect both codes to be equivalent, why is this not the case?

like image 410
Edvin K Avatar asked May 03 '19 13:05

Edvin K


People also ask

What does long long int do?

A long integer is a data type in computer science whose range is greater (sometimes even double) than that of the standard data type integer. Depending on the programming language and the computer machine processor, the size of the long integer will vary.

Why do we use long long int in C?

long int. A long int typically uses twice as many bits as a regular int, allowing it to hold much larger numbers. printf and scanf replace %d or %i with %ld or %li to indicate the use of a long int. long int may also be specified as just long.

Is long long int valid?

long and long int are identical. So are long long and long long int . In both cases, the int is optional.

How do you declare long long int?

If we need to store a large integer (in the range -2147483647 to 2147483647), we can use the type specifier long . For example, // large integer long b = 123456; Note: long is equivalent to long int .


Video Answer


2 Answers

The issue with

LL m = pow(2, n + 1) - 2; 

is that pow(2, n + 1) is not a long long. It has the type double (refer to cppreference) and because the value is so large, subtracting 2 from it will not change its value. That means that m will not have the correct value. As you have already found, you need to assign the result first and then do the subtraction. Another alternative is to write your own pow that will return a integer type when given an integer type so you can do the raising to the power and subtraction at the same time.

like image 72
NathanOliver Avatar answered Oct 13 '22 11:10

NathanOliver


I expect both codes to be equivalent, why is this not the case?

Your expectation is wrong. Your second code would be equivalent to this:

auto m = static_cast<LL>( pow(2, n + 1) ) - 2; 

as due to conversion rule for arithmetic operators and the fact that std::pow() returns double in this case:

For the binary operators (except shifts), if the promoted operands have different types, additional set of implicit conversions is applied, known as usual arithmetic conversions with the goal to produce the common type (also accessible via the std::common_type type trait). If, prior to any integral promotion, one operand is of enumeration type and the other operand is of a floating-point type or a different enumeration type, this behavior is deprecated. (since C++20)

If either operand has scoped enumeration type, no conversion is performed: the other operand and the return type must have the same type

Otherwise, if either operand is long double, the other operand is converted to long double

Otherwise, if either operand is double, the other operand is converted to double

Otherwise, if either operand is float, the other operand is converted to float

...

(emphasis is mine) your original expression would lead to double - double instead of long long int - long long int as you do in the second case hence the difference.

like image 20
Slava Avatar answered Oct 13 '22 12:10

Slava