Why is std::abs(9484282305798401ull) = 9484282305798400?
First off, what you are doing doesn't really make sense out of context (getting the absolute value of an unsigned type). But I digress.
The code you have posted doesn't compile. At least not in the compiler I used (whichever one repl.it uses). Instead it complains of an ambiguous overload. Even if it did compile, it would cast the unsigned long long
to a different type which cannot support its actual value (in this case double
).
Changing abs
to llabs
like so:
std::cout << (unsigned long long)std::llabs(9484282305798401ull);
..both makes it compile and produces an accurate result. See the documentation of the different abs
functions for integer types here.
On the std::abs function
The correct overloads are guaranteed to be present in <cmath>
/<cstdlib>
:
C++11, [c.math]:
In addition to the
int
versions of certain math functions in<cstdlib>
, C++ addslong
andlong long
overloaded versions of these functions, with the same semantics.The added signatures are:
long abs(long); // labs()
long long abs(long long); // llabs()
[...]
In addition to the
double
versions of the math functions in<cmath>
, overloaded versions of these functions, with the same semantics.
C++ addsfloat
andlong double
overloaded versions of these functions, with the same semantics.float abs(float);
long double abs(long double);
So you should just make sure to include correctly <cstdlib>
(int
, long
, long long
overloads)/<cmath>
(double
, float
, long double
overloads).
Does abs(unsigned long) make any sense?
No, it doesn't make sense.
If you want the difference, use
c = (a > b) ? a - b : b - a;
or
c = max(a, b) - min(a, b);
Unsigned if go below zero would wrap back (effect is similar to adding 2sizeof (unsigned long) * CHAR_BIT)
If you are looking for difference between two numbers, you can write a small template as below
namespace MyUtils {
template<typename T>
T diff(const T&a, const T&b) {
return (a > b) ? (a - b) : (b - a);
}
}
Looking at the declaration of abs inherited from C
(Because you included stdlib.h
)
int abs( int n );
long abs( long n );
long long abs( long long n ); // (since C++11)
//Defined in header <cinttypes>
std::intmax_t abs( std::intmax_t n ); // (since C++11)
And abs in C++
(from cmath
)
float abs( float arg );
double abs( double arg );
long double abs( long double arg );
If you notice, both the argument and return type of each function are signed
. So if you pass an unsigned type to one of these function, implicit conversion unsigned T1 -> signed T2 -> unsigned T1
would take place (where T1
and T2
may be same and T1
is long
in your case). When you convert an unsigned integral to signed integral, the behavior is implementation dependendent if it can not be represented in a signed type.
From 4.7 Integral conversions [conv.integral]
- If the destination type is unsigned, the resulting value is the least
unsigned integer congruent to the source integer (modulo 2n where n is
the number of bits used to represent the unsigned type). [ Note: In a
two’s complement representation, this conversion is conceptual and
there is no change in the bit pattern (if there is no truncation). —
end note]- If the destination type is signed, the value is unchanged if it can be
represented in the destination type (and bit-field width); otherwise,
the value is implementation-defined.
std::abs for unsigned long long int data type
The check seem the only really good solution. Alternatives require type bigger than yours and nonstandard extension to use it.
You can go with solutions casting to signed long long if your range fits. I would hardly suggest that way, especially if the implementation is placed in a function that does only that.
Template version of std::abs
See LWG issue 2192. Currently, std::abs(x-y) < 2
fails if x
and y
are unsigned. This catches a subtle programming error. With the proposed change, it compiles but does entirely the wrong thing. abs(3u-4u)
would be much larger than 2, in fact it's UINT_MAX
.
What's the difference between abs and fabs?
In C++, std::abs
is overloaded for both signed integer and floating point types. std::fabs
only deals with floating point types (pre C++11). Note that the std::
is important; the C function ::abs
that is commonly available for legacy reasons will only handle int
!
The problem with
float f2= fabs(-9);
is not that there is no conversion from int
(the type of -9
) to double
, but that the compiler does not know which conversion to pick (int
-> float
, double
, long double
) since there is a std::fabs
for each of those three. Your workaround explicitly tells the compiler to use the int
-> double
conversion, so the ambiguity goes away.
C++11 solves this by adding double fabs( Integral arg );
which will return the abs
of any integer type converted to double
. Apparently, this overload is also available in C++98 mode with libstdc++ and libc++.
In general, just use std::abs
, it will do the right thing. (Interesting pitfall pointed out by @Shafik Yaghmour. Unsigned integer types do funny things in C++.)
cpp using abs() function with size_t
To understand what does abs
do, we must understand what's the difference between signed
and unsigned
type.
Consoder following statements:
a = 10
b = -20
c = a + b
does result of c
depends on whether a
,b
,c
is signed or unsigned ?
Surprisingly it doesn't. because computer handle numbers using two's complement, so if 2 numbers are separated by 2^N, they are considered the same number.
And not only add
,subtract
doesn't care about sign, multiplication
also doesn't care about sign:
x*(2^N - y) = x*2^N - x*(-y) = x*(-y) mod 2^N
Because of such affect, restriction between signed and unsigned numbers is loosen.
The more details can be find in the instruction set of X86 architecture. Actually X86 defines an uniform add, which handles both signed and unsigned add, the only difference between signed and unsigned add is the carrier bit (also be called overflow/underflow bit).
And there are operators that do care about sign. like
- print. people are surely prefer -1 than 4294967295, so printf has separated symbol for signed and unsigned "%u"
- compare. 4294967295 > 0, but -1 < 0
- abs function
- and more on ...
When using operators who care about sign, you'd better be more careful. That's why abs
is not allowed to take unsigned parameter.
Is stateful metaprogramming ill-formed (yet)?
This is CWG active issue 2118:
Defining a friend function in a template, then referencing that function later provides a means of capturing and retrieving metaprogramming state. This technique is arcane and should be made ill-formed.
Notes from the May, 2015 meeting:
CWG agreed that such techniques should be ill-formed, although the mechanism for prohibiting them is as yet undetermined.
It's still an active issue, nothing will change in C++17 at least for now. Though when such a prohibition mechanism is determined, this may be retroactively ruled as a DR.
Ambiguous call to abs
The issue is that libc++
is not entirely C++11 compliant with the integral overload for std::abs in cmath:
double fabs( Integral arg ); (7) (since C++11)
Including cstdlib solves your problem since that header has overloads specifically for integer types.
For reference the draft C++11 standard section 26.8
[c.math] paragraph 11
says:
Moreover, there shall be additional overloads sufficient to ensure:
and includes the following item:
- Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to
double parameters are effectively cast to double.
This is situation very likely to change due to LWG active issue 2192: Validity and return type of std::abs(0u) is unclear. I am guessing libc++
choose not to provide the overloads in cmath
due to the issue brought up in this defect report.
See Is std::abs(0u) ill-formed? for more details on this.
Related Topics
How to Truncate a File While It Is Open with Fstream
C++ - Decimal to Binary Converting
What Is a Good Oo C++ Wrapper for SQLite
How to Change the Variable to Which a C++ Reference Refers
Why Can't "Transform(S.Begin(),S.End(),S.Begin(),Tolower)" Be Complied Successfully
Reading Line from Text File and Putting the Strings into a Vector
What Does It Mean for a C++ Function to Be Inline
C++ Equivalent to Designated Initializers
Why am I Getting an Error Converting a 'Float**' to 'Const Float**'
Self-Initialization of a Static Constexpr Variable, Is It Well-Formed
Libpng, Palette Png with Alpha or Not
Is There Still a Use for Inline
How to Pretty-Print Stl Containers in Gdb
Initialise Eigen::Vector with Std::Vector
Converting Float Values from Big Endian to Little Endian
Reason for C++ Member Function Hiding
Is It Counter-Productive to Pass Primitive Types by Reference