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?
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.
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.
long and long int are identical. So are long long and long long int . In both cases, the int is optional.
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 .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With