decimal literal is more than LONG_LONG_MAX - c++

In the "C++ Primer" book it is said that decimal literals have the smallest type of int, long or long long in which the literal's value fits, and it is an error to use a literal that is too large to fit in the largest related type. So, i guess, that the max decimal literal is the max value long long can hold.
But I tried it: printed the max long long value, then a decimal literal higher. I thought it had to cause an error, but it was okay. I then tried to print a decimal literal higher than the unsigned long long max value - it wrapped around.
Here is my code:
#include <iostream>
#include <limits>
using namespace std;
int main() {
cout << LONG_LONG_MAX << endl;
cout << 9223372036854775808 << endl;
cout << ULONG_LONG_MAX << endl;
cout << 18446744073709551616 << endl;
}
Here is the output:
9223372036854775807
9223372036854775808
18446744073709551615
0
Explain please, why a decimal literal can be higher than the long long max value
UPD:
I noticed that there actually were warnings. I work under CodeBlocks, and on rebuilding and reruning your project it doesn't print warnings again, if the code isn't changed. So I just didn't notice. There were 3 warnings:
integer constant is so large that it is unsigned (8)
this decimal constant is unsigned only in ISO C90 (8)
integer constant is too large for its type (10)
But output was the same. Then I noticed that in debugger options I forgot to fill in the 'executable path' line, so I pasted there my gdb path. But I don't think it mattered.
Afterwards I noticed that I didn't choose the 'have g++ follow c++11' option in compiler settings. I did choose and compiler then printed both warnings and some errors. There wasn't the this decimal constant is unsigned only in ISO C90 warning, but was an ..\main.cpp|8|error: ambiguous overload for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and '<unnamed-signed:128>')| error. Also it didn't recognise limits with LONG_LONG_MAX and ULONG_LONG_MAX, but recognised climits with LLONG_MAX and ULLONG_MAX.
With c++98 there were warnings like in the first case (without any option chosen) and it didn't recognise limits, only climits. When I changed the header name, the output was like in the beginning.
The compiler is set to GNU GCC Compiler.
Maybe someone could explain why compiler supports limits if I don't specify standard, and then, I think, the question is closed.

According to the language specification, a decimal literal with no suffix has a signed type (the smallest type of int, long int, or long long int that can hold the value). Binary, octal, and hexadecimal constants can have unsigned types.
An implementation is allowed to support extended integer types. If your compiler has an integer type larger than a long long, then your decimal literal would be of that type. If it doesn't, then it is either a compiler bug or compiler extension since an unsuffixed decimal literal cannot be of type unsigned long long.

Please use header and constants defined by standard. http://en.cppreference.com/w/cpp/types/climits.
Upper limit for 64bit int (long long on most POSIX systems) is 9223372036854775807 (2^63-1).
Maximum value for an object of type unsigned long long int 18446744073709551615 (2^64-1).
<limits> may exists but it not necessary includes <climits>.
As your literal doesn't fit into signed value, the compiler must have to give you diagnostic (if you didn't disabled it), something like
main.c:8:13: warning: integer constant is so large that it is unsigned
cout << 9223372036854775808 << endl;
Apparently gcc\clang are liberal enough to consider that enough and can compile program assuming that value would be represented with unsigned type, and to truncate the second literal. It's an undetermined behavior and former would not be true, so you may get negative values in output, e.g.:
9223372036854775807
-9223372036854775808
18446744073709551615
0

Related

Can't Assign 64 Bit Number to 64 Bit Min in C++

I'm new to C++, so sorry if this sounds like a dumb question. I'm attempting to assign the 64 bit minimum (-9223372036854775808) to an int64_t (from cstdint), however I'm getting the current error message:
main.cpp:5:27: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
int64_t int_64_min = -9223372036854775808;
The code is as follows:
#include <iostream>
#include <cstdint>
int main() {
int64_t int_64_min = -9223372036854775808;
std::cout << int_64_min << std::endl;
std::cout << INT64_MIN << std::endl;
return 0;
}
Am I missing something obvious?
This is exactly why the INT_MIN family of macros are often defined like -INT_MAX - 1 on a 2's complement platform (virtually ubiquitous and compulsory from C++20).
There is no such thing as a negative literal in C++: just the unary negation of a positive number which produces a compile time evaluable constant expression.
9223372036854775808 is too big to fit into a 64 bit signed integral type, so the behavior of negating this and assigning to a signed 64 bit integral type is implementation defined.
Writing -9223372036854775807 - 1 is probably what your C++ standard library implementation does. If I were you, I'd use INT64_MIN directly or std::numeric_limits<std::int64_t>::min().
The problem is that -9223372036854775808 is not a literal. 9223372036854775808 is a literal, and -9223372036854775808 is an expression consisting of that literal with a unary - applied to it.
All unsuffixed decimal literals are of type int, long int, or long long int. Since 9223372036854775808 is 263, it's bigger than the maximum value of long long int (assuming long long int is 64 bits, which it almost certainly is).
The simplest solution is to use the INT64_MIN macro defined in <cstdint>.
Aside from that, the problem is that there are no literals for negative values. Another solution is to replace -9223372036854775808 by -9223372036854775807-1 -- or by (-9223372036854775807-1) to avoid ambiguity. (The <cstdint> header very likely does something similar).

Why does the most negative int value cause an error about ambiguous function overloads?

I'm learning about function overloading in C++ and came across this:
void display(int a)
{
cout << "int" << endl;
}
void display(unsigned a)
{
cout << "unsigned" << endl;
}
int main()
{
int i = -2147483648;
cout << i << endl; //will display -2147483648
display(-2147483648);
}
From what I understood, any value given in the int range (in my case int is 4 byte) will call display(int) and any value outside this range will be ambiguous (since the compiler cannot decide which function to call). It is valid for the complete range of int values except its min value i.e. -2147483648 where compilation fails with the error
call of overloaded display(long int) is ambiguous
But taking the same value to an int and printing the value gives 2147483648. I'm literally confused with this behavior.
Why is this behavior observed only when the most negative number is passed? (The behavior is the same if a short is used with -32768 - in fact, in any case where the negative number and positive number have the same binary representation)
Compiler used: g++ (GCC) 4.8.5
This is a very subtle error. What you are seeing is a consequence of there being no negative integer literals in C++. If we look at [lex.icon] we get that a integer-literal,
integer-literal
decimal-literal integer-suffixopt
[...]
can be a decimal-literal,
decimal-literal:
nonzero-digit
decimal-literal ’ opt digit
where digit is [0-9] and nonzero-digit is [1-9] and the suffix par can be one of u, U, l, L, ll, or LL. Nowhere in here does it include - as being part of the decimal literal.
In §2.13.2, we also have:
An integer literal is a sequence of digits that has no period or exponent part, with optional separating single quotes that are ignored when determining its value. An integer literal may have a prefix that specifies its base and a suffix that specifies its type. The lexically first digit of the sequence of digits is the most significant. A decimal integer literal (base ten) begins with a digit other than 0 and consists of a sequence of decimal digits.
(emphasis mine)
Which means the - in -2147483648 is the unary operator -. That means -2147483648 is actually treated as -1 * (2147483648). Since 2147483648 is one too many for your int it is promoted to a long int and the ambiguity comes from that not matching.
If you want to get the minimum or maximum value for a type in a portable manner you can use:
std::numeric_limits<type>::min(); // or max()
The expression -2147483648 is actually applying the - operator to the constant 2147483648. On your platform, int can't store 2147483648, it must be represented by a larger type. Therefore, the expression -2147483648 is not deduced to be signed int but a larger signed type, signed long int.
Since you do not provide an overload for long the compiler is forced to choose between two overloads that are both equally valid. Your compiler should issue a compiler error about ambiguous overloads.
Expanding on others' answers
To clarify why the OP is confused, first: consider the signed int binary representation of 2147483647, below.
Next, add one to this number: giving another signed int of -2147483648 (which the OP wishes to use)
Finally: we can see why the OP is confused when -2147483648 compiles to a long int instead of a signed int, since it clearly fits in 32 bits.
But, as the current answers mention, the unary operator (-) is applied after resolving 2147483648 which is a long int and does NOT fit in 32 bits.

Cast from unsigned long long to double and vice versa changes the value

When writing a C++ code I suddenly realised that my numbers are incorrectly casted from double to unsigned long long.
To be specific, I use the following code:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <limits>
using namespace std;
int main()
{
unsigned long long ull = numeric_limits<unsigned long long>::max();
double d = static_cast<double>(ull);
unsigned long long ull2 = static_cast<unsigned long long>(d);
cout << ull << endl << d << endl << ull2 << endl;
return 0;
}
Ideone live example.
When this code is executed on my computer, I have the following output:
18446744073709551615
1.84467e+019
9223372036854775808
Press any key to continue . . .
I expected the first and third numbers to be exactly the same (just like on Ideone) because I was sure that long double took 10 bytes, and stored the mantissa in 8 of them. I would understand if the third number were truncated compared to first one - just for the case I'm wrong with the floating-point numbers format. But here the values are twice different!
So, the main question is: why? And how can I predict such situations?
Some details: I use Visual Studio 2013 on Windows 7, compile for x86, and sizeof(long double) == 8 for my system.
18446744073709551615 is not exactly representible in double (in IEEE754). This is not unexpected, as a 64-bit floating point obviously cannot represent all integers that are representible in 64 bits.
According to the C++ Standard, it is implementation-defined whether the next-highest or next-lowest double value is used. Apparently on your system, it selects the next highest value, which seems to be 1.8446744073709552e19. You could confirm this by outputting the double with more digits of precision.
Note that this is larger than the original number.
When you convert this double to integer, the behaviour is covered by [conv.fpint]/1:
A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.
So this code potentially causes undefined behaviour. When undefined behaviour has occurred, anything can happen, including (but not limited to) bogus output.
The question was originally posted with long double, rather than double. On my gcc, the long double case behaves correctly, but on OP's MSVC it gave the same error. This could be explained by gcc using 80-bit long double, but MSVC using 64-bit long double.
It's due to double approximation to long long. Its precision means ~100 units error at 10^19; as you try to convert values around the upper limit of long long range, it overflows. Try to convert 10000 lower value instead :)
BTW, at Cygwin, the third printed value is zero
The problem is surprisingly simple. This is what is happening in your case:
18446744073709551615 when converted to a double is round up to the nearest number that the floating point can represent. (The closest representable number is larger).
When that's converted back to an unsigned long long, it's larger than max(). Formally, the behaviour of converting this back to an unsigned long long is undefined but what appears to be happening in your case is a wrap around.
The observed significantly smaller number is the result of this.

U suffix in the variable declaration

I know that if the number is followed with U suffix it is treated as unsigned. But why following program prints correct value of variable i even though it is initialized with negative value. (Compiled with gcc 4.9.2, 4.8.2, & 4.7.1)
Program1.cpp
#include <iostream>
int main()
{
int i=-5U;
std::cout<<i; // prints -5 on gcc 4.9.2, 4.8.2, & 4.7.1
}
Program2.cpp
#include <iostream>
int main()
{
auto i=-5U;
std::cout<<i; // prints large positive number as output
}
But If I use auto keyword (The type deducer new C++0x feature) it gives me large positive number as expected.
Please correct me If I am understanding incorrect something.
-5U is not -5 U. It is -(5U). The minus sign is a negation operator operating on 5U, not the first character of an integer literal.
When you negate an unsigned number, it is equivalent to subtracting the current value from 2^n, where n is the number of bits in the integer type. So that explains the second program. As for the first, when you cast an unsigned integer to a signed integer (as you are doing by assigning it to an int), if the value is out of range the result is undefined behavior but in general* will result in the value being reinterpreted as an unsigned integer-- and since unsigned negation just so happens to have the same behavior as two's complement signed negation, the result is the same as if the negation happened in a signed context.
.* Note: This is NOT one of those "undefined behavior" situations that is only of academic concern to language wonks. Compilers can and do assume that casting an unsigned number to signed will not result in overflow (particularly when the resulting integer is then used in a loop), and there are known instances of this assumption turning carelessly written code into buggy programs.

Smallest values for int8_t and int64_t

With regard to to those definitions found in stdint.h, I wish to test a function for converting vectors of int8_t or vectors of int64_t to vectors of std::string.
Here are my tests:
TEST(TestAlgorithms, toStringForInt8)
{
std::vector<int8_t> input = boost::assign::list_of(-128)(0)(127);
Container container(input);
EXPECT_TRUE(boost::apply_visitor(ToString(),container) == boost::assign::list_of("-128")("0")("127"));
}
TEST(TestAlgorithms, toStringForInt64)
{
std::vector<int64_t> input = boost::assign::list_of(-9223372036854775808)(0)(9223372036854775807);
Container container(input);
EXPECT_TRUE(boost::apply_visitor(ToString(),container) == boost::assign::list_of("-9223372036854775808")("0")("9223372036854775807"));
}
However, I am getting a warning in visual studio for the line:
std::vector<int64_t> input = boost::assign::list_of(-9223372036854775808)(0)(9223372036854775807);
as follows:
warning C4146: unary minus operator applied to unsigned type, result still unsigned
If I change -9223372036854775808 to -9223372036854775807, the warning disappears.
What is the issue here? With regard to my original code, the test is passing.
It's like the compiler says, -9223372036854775808 is not a valid number because the - and the digits are treated separately.
You could try -9223372036854775807 - 1 or use std::numeric_limits<int64_t>::min() instead.
The issue is that integer literals are not negative; so -42 is not a literal with a negative value, but rather the - operator applied to the literal 42.
In this case, 9223372036854775808 is out of the range of int64_t, so it will be given an unsigned type. Due to the magic of modular arithmetic, you can still negate it, assign it to int64_t, and end up with the result you expect; but the compiler will warn you about the unsigned negation (if you tell it to) since that can often be the result of an error.
You could avoid the warning (and make the code more obviously correct) by using std::numeric_limits<int64_t>::min() instead.
Change -9223372036854775808 to -9223372036854775807-1.
The issue is that -9223372036854775808 isn't -9223372036854775808 but rather -(9223372036854775808) and 9223372036854775808 cannot fit into a signed 64-bit type (decimal integer constants by default are a signed type), so it instead becomes unsigned. Applying negation with - to an unsigned type is suspicious, hence the warning.