Why is my arithmetic with a long long int behaving this way?Why is “using namespace std” considered bad practice?Why isnt int pow(int base, int exponent) in the standard C++ libraries?How do I parse a string to a float or int in Python?Why can templates only be implemented in the header file?What is the difference between const int*, const int * const, and int const *?Why is “using namespace std” considered bad practice?Why not use Double or Float to represent currency?Easiest way to convert int to string in C++Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?Why are elementwise additions much faster in separate loops than in a combined loop?Why does changing 0.1f to 0 slow down performance by 10x?Why is it faster to process a sorted array than an unsorted array?
the grammar about `adv adv` as 'too quickly'
Why are BJTs common in output stages of power amplifiers?
Why do the lights go out when someone enters the dining room on this ship?
Did galley captains put corks in the mouths of slave rowers to keep them quiet?
Acronyms in HDD specification
What dog breeds survive the apocalypse for generations?
Can only the master initiate communication in SPI whereas in I2C the slave can also initiate the communication?
Will a coyote attack my dog on a leash while I'm on a hiking trail?
Find the unknown area, x
Is there an academic word that means "to split hairs over"?
Developers demotivated due to working on same project for more than 2 years
Do Grothendieck universes matter for an algebraic geometer?
Is it safe to use two single-pole breakers for a 240 V circuit?
Why didn't the Avengers use this object earlier?
How might a landlocked lake become a complete ecosystem?
"The van's really booking"
Unexpected Netflix account registered to my Gmail address - any way it could be a hack attempt?
Is 95% of what you read in the financial press “either wrong or irrelevant?”
How can we allow remote players to effectively interact with a physical tabletop battle-map?
How can I add a .pem private key fingerprint entry to known_hosts before connecting with ssh?
How to describe a building set which is like LEGO without using the "LEGO" word?
Filter a data-frame and add a new column according to the given condition
How can a layman easily get the consensus view of what academia *thinks* about a subject?
Why did the soldiers of the North disobey Jon?
Why is my arithmetic with a long long int behaving this way?
Why is “using namespace std” considered bad practice?Why isnt int pow(int base, int exponent) in the standard C++ libraries?How do I parse a string to a float or int in Python?Why can templates only be implemented in the header file?What is the difference between const int*, const int * const, and int const *?Why is “using namespace std” considered bad practice?Why not use Double or Float to represent currency?Easiest way to convert int to string in C++Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?Why are elementwise additions much faster in separate loops than in a combined loop?Why does changing 0.1f to 0 slow down performance by 10x?Why is it faster to process a sorted array than an unsorted array?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
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?
c++ floating-point precision long-long
|
show 5 more comments
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?
c++ floating-point precision long-long
25
I'm curious where you picked up#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?
– François Andrieux
May 3 at 13:54
12
using namespace std;
is considered bad practice.
– L. F.
May 3 at 13:55
22
@Lucas butusing LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there
– Guillaume Racicot
May 3 at 14:04
21
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken byusing namespace std;
– Mooing Duck
May 3 at 16:56
10
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers likegcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.
– mtraceur
May 3 at 21:13
|
show 5 more comments
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?
c++ floating-point precision long-long
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?
c++ floating-point precision long-long
c++ floating-point precision long-long
edited May 10 at 23:07
oldherl
179211
179211
asked May 3 at 13:42
Edvin KEdvin K
13925
13925
25
I'm curious where you picked up#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?
– François Andrieux
May 3 at 13:54
12
using namespace std;
is considered bad practice.
– L. F.
May 3 at 13:55
22
@Lucas butusing LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there
– Guillaume Racicot
May 3 at 14:04
21
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken byusing namespace std;
– Mooing Duck
May 3 at 16:56
10
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers likegcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.
– mtraceur
May 3 at 21:13
|
show 5 more comments
25
I'm curious where you picked up#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?
– François Andrieux
May 3 at 13:54
12
using namespace std;
is considered bad practice.
– L. F.
May 3 at 13:55
22
@Lucas butusing LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there
– Guillaume Racicot
May 3 at 14:04
21
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken byusing namespace std;
– Mooing Duck
May 3 at 16:56
10
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers likegcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.
– mtraceur
May 3 at 21:13
25
25
I'm curious where you picked up
#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?– François Andrieux
May 3 at 13:54
I'm curious where you picked up
#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?– François Andrieux
May 3 at 13:54
12
12
using namespace std;
is considered bad practice.– L. F.
May 3 at 13:55
using namespace std;
is considered bad practice.– L. F.
May 3 at 13:55
22
22
@Lucas but
using LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there– Guillaume Racicot
May 3 at 14:04
@Lucas but
using LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there– Guillaume Racicot
May 3 at 14:04
21
21
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken by
using namespace std;
– Mooing Duck
May 3 at 16:56
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken by
using namespace std;
– Mooing Duck
May 3 at 16:56
10
10
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers like
gcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.– mtraceur
May 3 at 21:13
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers like
gcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.– mtraceur
May 3 at 21:13
|
show 5 more comments
3 Answers
3
active
oldest
votes
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
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.
10
For the OP: You should use bit shifting instead ofpow()
function. Something like(1 << (n + 1))
.
– Thomas Matthews
May 3 at 14:17
1
@StackDanny The problem is atpow(2, 54)
, notpow(2, 53)
– NathanOliver
May 3 at 14:24
5
Good answer but you should probably mention that the reason it works in the second example is thatpow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.
– pipe
May 3 at 14:55
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
@ThomasMatthews you'll need1ULL << (n + 1)
to shift more than 31 bits
– phuclv
May 4 at 4:25
|
show 5 more comments
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.
add a comment |
The pow
function returns a value of type double
, which only has 53 bits of precision. While the returned value will fit in a double
even if n
is greater than 53, subtracting 2 results in a value of type double
that requires more than 53 bits of precision so the result of the subtraction is rounded to the nearest representable value.
The reason breaking out the subtraction works is because the double
value returned from pow
is assigned to a long long
, then you subtract an int
from a long long
.
Since you're not dealing with floating point numbers and you're only raising 2 to a power, you can replace the call to pow
with a simple left shift:
LL m = (1LL << (n + 1)) - 2;
This keeps all intermediate values at type long long
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55971072%2fwhy-is-my-arithmetic-with-a-long-long-int-behaving-this-way%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
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
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.
10
For the OP: You should use bit shifting instead ofpow()
function. Something like(1 << (n + 1))
.
– Thomas Matthews
May 3 at 14:17
1
@StackDanny The problem is atpow(2, 54)
, notpow(2, 53)
– NathanOliver
May 3 at 14:24
5
Good answer but you should probably mention that the reason it works in the second example is thatpow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.
– pipe
May 3 at 14:55
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
@ThomasMatthews you'll need1ULL << (n + 1)
to shift more than 31 bits
– phuclv
May 4 at 4:25
|
show 5 more comments
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
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.
10
For the OP: You should use bit shifting instead ofpow()
function. Something like(1 << (n + 1))
.
– Thomas Matthews
May 3 at 14:17
1
@StackDanny The problem is atpow(2, 54)
, notpow(2, 53)
– NathanOliver
May 3 at 14:24
5
Good answer but you should probably mention that the reason it works in the second example is thatpow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.
– pipe
May 3 at 14:55
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
@ThomasMatthews you'll need1ULL << (n + 1)
to shift more than 31 bits
– phuclv
May 4 at 4:25
|
show 5 more comments
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
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.
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
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.
edited May 3 at 14:48
Medinoc
5,9291230
5,9291230
answered May 3 at 13:47
NathanOliverNathanOliver
102k17145227
102k17145227
10
For the OP: You should use bit shifting instead ofpow()
function. Something like(1 << (n + 1))
.
– Thomas Matthews
May 3 at 14:17
1
@StackDanny The problem is atpow(2, 54)
, notpow(2, 53)
– NathanOliver
May 3 at 14:24
5
Good answer but you should probably mention that the reason it works in the second example is thatpow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.
– pipe
May 3 at 14:55
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
@ThomasMatthews you'll need1ULL << (n + 1)
to shift more than 31 bits
– phuclv
May 4 at 4:25
|
show 5 more comments
10
For the OP: You should use bit shifting instead ofpow()
function. Something like(1 << (n + 1))
.
– Thomas Matthews
May 3 at 14:17
1
@StackDanny The problem is atpow(2, 54)
, notpow(2, 53)
– NathanOliver
May 3 at 14:24
5
Good answer but you should probably mention that the reason it works in the second example is thatpow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.
– pipe
May 3 at 14:55
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
@ThomasMatthews you'll need1ULL << (n + 1)
to shift more than 31 bits
– phuclv
May 4 at 4:25
10
10
For the OP: You should use bit shifting instead of
pow()
function. Something like (1 << (n + 1))
.– Thomas Matthews
May 3 at 14:17
For the OP: You should use bit shifting instead of
pow()
function. Something like (1 << (n + 1))
.– Thomas Matthews
May 3 at 14:17
1
1
@StackDanny The problem is at
pow(2, 54)
, not pow(2, 53)
– NathanOliver
May 3 at 14:24
@StackDanny The problem is at
pow(2, 54)
, not pow(2, 53)
– NathanOliver
May 3 at 14:24
5
5
Good answer but you should probably mention that the reason it works in the second example is that
pow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.– pipe
May 3 at 14:55
Good answer but you should probably mention that the reason it works in the second example is that
pow(2,n)
"accidentally" fits exactly in the most commonly used floating point representation, even for very large results, so there is never a round-off error involved.– pipe
May 3 at 14:55
2
2
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
@pipe, for powers of two and binary computers, it's not an "accident" in any way.
– ilkkachu
May 3 at 18:32
2
2
@ThomasMatthews you'll need
1ULL << (n + 1)
to shift more than 31 bits– phuclv
May 4 at 4:25
@ThomasMatthews you'll need
1ULL << (n + 1)
to shift more than 31 bits– phuclv
May 4 at 4:25
|
show 5 more comments
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.
add a comment |
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.
add a comment |
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.
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.
edited May 3 at 14:26
answered May 3 at 14:17
SlavaSlava
33.4k12968
33.4k12968
add a comment |
add a comment |
The pow
function returns a value of type double
, which only has 53 bits of precision. While the returned value will fit in a double
even if n
is greater than 53, subtracting 2 results in a value of type double
that requires more than 53 bits of precision so the result of the subtraction is rounded to the nearest representable value.
The reason breaking out the subtraction works is because the double
value returned from pow
is assigned to a long long
, then you subtract an int
from a long long
.
Since you're not dealing with floating point numbers and you're only raising 2 to a power, you can replace the call to pow
with a simple left shift:
LL m = (1LL << (n + 1)) - 2;
This keeps all intermediate values at type long long
.
add a comment |
The pow
function returns a value of type double
, which only has 53 bits of precision. While the returned value will fit in a double
even if n
is greater than 53, subtracting 2 results in a value of type double
that requires more than 53 bits of precision so the result of the subtraction is rounded to the nearest representable value.
The reason breaking out the subtraction works is because the double
value returned from pow
is assigned to a long long
, then you subtract an int
from a long long
.
Since you're not dealing with floating point numbers and you're only raising 2 to a power, you can replace the call to pow
with a simple left shift:
LL m = (1LL << (n + 1)) - 2;
This keeps all intermediate values at type long long
.
add a comment |
The pow
function returns a value of type double
, which only has 53 bits of precision. While the returned value will fit in a double
even if n
is greater than 53, subtracting 2 results in a value of type double
that requires more than 53 bits of precision so the result of the subtraction is rounded to the nearest representable value.
The reason breaking out the subtraction works is because the double
value returned from pow
is assigned to a long long
, then you subtract an int
from a long long
.
Since you're not dealing with floating point numbers and you're only raising 2 to a power, you can replace the call to pow
with a simple left shift:
LL m = (1LL << (n + 1)) - 2;
This keeps all intermediate values at type long long
.
The pow
function returns a value of type double
, which only has 53 bits of precision. While the returned value will fit in a double
even if n
is greater than 53, subtracting 2 results in a value of type double
that requires more than 53 bits of precision so the result of the subtraction is rounded to the nearest representable value.
The reason breaking out the subtraction works is because the double
value returned from pow
is assigned to a long long
, then you subtract an int
from a long long
.
Since you're not dealing with floating point numbers and you're only raising 2 to a power, you can replace the call to pow
with a simple left shift:
LL m = (1LL << (n + 1)) - 2;
This keeps all intermediate values at type long long
.
answered May 3 at 15:33
dbushdbush
106k15111151
106k15111151
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55971072%2fwhy-is-my-arithmetic-with-a-long-long-int-behaving-this-way%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
25
I'm curious where you picked up
#define LL long long
. I see it pretty often on this site, but I'm not aware of who or what is propagating it. Edit : Is it another one of those code golf habits?– François Andrieux
May 3 at 13:54
12
using namespace std;
is considered bad practice.– L. F.
May 3 at 13:55
22
@Lucas but
using LL = long long
is also compile time, same size to type, and better. There is no reason to use a macro there– Guillaume Racicot
May 3 at 14:04
21
@pipe: We understand perfectly well why. We don't want to promote bad practices just because you think it's "magically fine" for code examples. There are plenty of code examples on this site that were broken by
using namespace std;
– Mooing Duck
May 3 at 16:56
10
@ThomasMatthews when you're telling people to prefer bit-shift for signed integer types, please alert them that for signed integer types overflow is undefined behavior, that this is not just theoretical undefined behavior but can create actual bugs on common compilers like
gcc
, and that the numerical result can be surprising and unexpected if you don't consciously think about overflow even when it is compiled to behave exactly as expected for a fixed-width integer type.– mtraceur
May 3 at 21:13