Different results using same function from different libraries - c++

Here is some code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long long int a, b;
long long int c;
cin >> a >> b;
c = abs(a) + abs(b);
cout << c;
cout << endl;
}
Which supposed to return 1000000000000000002 when I input 1000000000000000000 and 2.
If I try to do it with cmath it will return 1000000000000000000, but if I use cstdlib it will return 1000000000000000002. Why is that even happening?
Also considering that I'm using cmath, shouldn't it work even more proper?
I'm using Linux Mint 18.2 64bit, Eclipse Platform.

The cmath version is a float one. So when you only have that one, you actually do the computation on floats and convert back into a long long at the end. Float precision not being enough to hold 18 digits, the +2 simply gets lost.
The cstdlib version is a integer one. Which gives the expected result.
As pointed out in the comments, in C++11, cmath also defines a version of abs that takes integers. However, “these overloads effectively cast x to a double before calculations (defined for T being any integral type)”.
I believe your compiler should give you a warning for the conversions if you use -Wall -Wextra or similar flags while only inclulding cmath.

If you are using g++, try to compile both versions with -Wconversion (or -Wfloat-conversion).
Note that the <cmath> version generates a warning:
main.cpp:14:7: warning: conversion to ‘long long int’ from ‘__gnu_cxx::__enable_if::__type {aka double}’ may alter its value [-Wfloat-conversion]
c = abs(a) + abs(b);
While the <cstdlib>version compiles without warnings.
That is because, in <cmath>, abs() is defined as1:
float abs(float);
double abs(double);
long double abs(long double);
While in <cstdlib> it is defined as1:
int abs(int);
long abs(long);
long long abs(long long);
1The integer versions of abs() are defined in <cmath> since C++17.

Related

Cannot overload std::abs() for GCC 128 bit integer

I'm getting compiler errors when I call abs() with GCC's 128 bit type. My line looks like:
__extension__ using int128_t = __int128;
int128_t mantissa_;
// Other code
using namespace std;
int128_t temp = abs(mantissa_);
The error I'm getting locally is:
error: call of overloaded ‘abs(const int128_t&)’ is ambiguous
int128_t temp = abs(mantissa_);
/usr/include/stdlib.h:840:12: note: candidate: ‘int abs(int)’
840 | extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
/usr/include/c++/11/bits/std_abs.h:56:3: note: candidate: ‘long int std::abs(long int)’
56 | abs(long __i) { return __builtin_labs(__i); }
| ^~~
/usr/include/c++/11/bits/std_abs.h:61:3: note: candidate: ‘long long int std::abs(long long int)’
61 | abs(long long __x) { return __builtin_llabs (__x); }
| ^~~
/usr/include/c++/11/bits/std_abs.h:71:3: note: candidate: ‘constexpr double std::abs(double)’
71 | abs(double __x)
| ^~~
/usr/include/c++/11/bits/std_abs.h:75:3: note: candidate: ‘constexpr float std::abs(float)’
75 | abs(float __x)
| ^~~
/usr/include/c++/11/bits/std_abs.h:79:3: note: candidate: ‘constexpr long double std::abs(long double)’
79 | abs(long double __x)
so it's not considering my overload (below) as a candidate?
namespace std
{
__extension__ using int128_t = __int128;
int128_t abs(int128_t x)
{
return x < 0 ? x * -1 : x; // Not ideal but no builtin for 128
}
}
Is the overload correct?
However, when I mock an example in Godbolt, even without overloading abs(), it compiles fine:
https://godbolt.org/z/P8T1fGxcK
#include <iostream>
__extension__ using int128_t = __int128;
struct Decimal
{
Decimal(int128_t q) : mantissa_(q)
{
volatile int128_t x = abs(mantissa_); // How is this compiling?
std::cout << "ctor" << std::endl;
}
int128_t mantissa_;
};
int main()
{
Decimal dec(-6);
}
Are Godbolt using a library like Abseil, they're providing a function and that's why it is compiling?
1. How to get std::abs working for __int128
The following only applies for gcc version >= 7.
For __int128 gcc provides an overload of std::abs with the following code snippet:
libstdc++-v3/include/bits/std_abs.h
#if defined(__GLIBCXX_TYPE_INT_N_0)
__extension__ inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_0
abs(__GLIBCXX_TYPE_INT_N_0 __x) { return __x >= 0 ? __x : -__x; }
#endif
(or one of the following 3 similar functions using __GLIBCXX_TYPE_INT_N_1, __GLIBCXX_TYPE_INT_N_2, etc...)
To get those macros defined you need to compile with gnu extensions enabled (i.e. not strict c++)
For this you need to build with -std=gnu++20 instead of -std=c++20 (or -std=gnu++17, -std=gnu++14, etc... depending on the c++ version you want to target)
(if no -std= option is given at all then gcc will default to std=gnu++xx (c++ version depending on compiler version))
When compiling with gnu extensions gcc will define those macros automatically for __int128 (assuming gcc supports 128-bit ints for your target platform):
godbolt
#define __GLIBCXX_BITSIZE_INT_N_0 128
#define __GLIBCXX_TYPE_INT_N_0 __int128
Unfortunately the c abs function-family (and the gcc builtin for it - __builtin_abs) do not support __int128 at all, and calling them would result in truncation of the result value.
Example: (compiled with -std=gnu++20 -Wconversion):
godbolt
#include <cmath>
__extension__ using int128_t = __int128;
int128_t mantissa_;
int main() {
{
using namespace std;
// OK - calls std::abs(__int128)
int128_t foo = abs(mantissa_);
}
// OK - calls std::abs(__int128)
int128_t bar = std::abs(mantissa_);
// WARNING: calls abs(int) --> truncation
int128_t baz = abs(mantissa_);
// WARNING: calls abs(int) --> truncation
int128_t foobar = __builtin_abs(mantissa_);
}
2. Why the godbolt compiles
The godbolt you provided compiles due to it calling the c function int abs(int)
(the code does not include using namespace std;, so std::abs is not visible)
The c abs-family of functions have different names for the possible types, so a call to abs() with __int128 as argument will not be ambigous (but will result in truncation to int):
int abs ( int n );
long labs ( long n );
long long llabs( long long n );
/* floating-point versions would be fabs, ... */
The c++-variant of abs - std::abs - is implemented with overloads instead, so a call to std::abs with __int128 will be ambigous, assuming there is no overload for __int128 defined.
(__int128 -> long long, __int128 -> long, __int128 -> int, etc... would be Integral conversions; __int128 -> double, __int128 -> float, etc.. would be Floating-integral conversions. Both Integral conversions and Floating-integral conversions and have the same rank (Conversion), so none of those overloads would be a better match than any other -> ambigous)
namespace std {
int abs( int n );
long abs( long n );
long long abs( long long n );
/* more overloads of abs for floating-point types */
}
3. Manually adding the std::abs function
Note that adding declarations to std is generally undefined behaviour (with a few exceptions), so i would not recommend this.
Here's a comparison of the gcc version vs your version:
// version provided by gcc (when compiling with gnu extensions)
// (macros substituted for better readability)
namespace std {
__extension__ inline constexpr __int128 abs(__int128 __x) {
return __x >= 0 ? __x : -__x;
}
}
// your version
namespace std {
__extension__ using int128_t = __int128;
int128_t abs(int128_t x)
{
return x < 0 ? x * -1 : x; // Not ideal but no builtin for 128
}
}
They're functionally identical, the ternary condition is just inverted and you're multiplying by negative one whereas gcc uses the unary minus operator.
godbolt example

How to use the C++ max function with boost 128 bit integer

If I have the following code:
#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision
int main()
{
int128_t a = Func_a()
int128_t b = Func_b()
std::cout << std::max(a, b) << std::endl;
return 0;
}
And if I compile using g++ on Ubuntu, I get the following error:
error: cannot convert ‘const boost::multiprecision::number >’ to ‘int64 {aka long long int}’ in assignment
What is the proper way to compare two int128_t numbers to see which one is greater?
EDIT: I am using std::max.
Your code (except for missing semicolons) compiles and runs without error.
However, according to your compiler message, I'm suspecting that in
int128_t a = Func_a(); // are you really sure it is int128_t?
the left-hand side is not a boost::multiprecision::int128_t, since the compiler says it is a int64.

C++ Type Check in Functions ignored (required double, provided int)

I have the following code
#include <iostream>
using namespace std;
int dmult(int a, int b){
return 2*a*b;
}
int main(void)
{
double a = 3.3;
double b = 2;
int c = dmult(a,b);
cout << c << endl;
return 0;
}
It compiles with MinGW without problems. The result is (as I thought) false. Is it a problem of the compiler that there is no warning, that a function expecting integers, but fed with doubles, can compile without warning even if the input type is wrong? Does it mean that C++ ignores the input type of a function? Shouldn't it realize that the function arguments have the wrong type?
double's are implicitly convertible to ints (and truncated), and the compiler is not forced by the standard to emit a warning (it tries its best to perform the conversion whenever possible). Compile with -Wconversion
g++ -Wconversion program.cpp
and you'll get your warning:
warning: conversion to 'int' from 'double' may alter its value [-Wfloat-conversion]
The typical warning flags -Wall -Wextra don't catch it since many times it is the programmer's intention to truncate double's to int's.
Live example here.
c++ automatically casts floats and doubles to integer literals by truncating them. so 3.3 becomes 3 when you call dmult(3.3,2)

Compilation error while using to_string in c++ program

To get precision and scale of a number i am using this simple program. But while converting number into string it is giving compilation error.
g++ precision.cpp
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: ‘to_string’ was not declared in this scope
When I compile with the -std=c++0x switch I get
g++ precision.cpp -std=c++0x
precision.cpp: In function ‘int main()’:
precision.cpp:6: error: call of overloaded ‘to_string(int)’ is ambiguous
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2604: note: candidates are: std::string std::to_string(long long int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2610: note: std::string std::to_string(long long unsigned int)
/usr/lib/gcc/i686-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/basic_string.h:2616: note: std::string std::to_string(long double)
The source code looks like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string value = to_string(static_cast<int>(1234));
int precision = value.length();
int scale = value.length()-value.find('.')-1;
cout << precision << " " << scale;
return 0;
}
What is causing this error?
The first error is because std::to_string is a C++11 feature, and GCC by default compiles in C++03 mode.
The second error, when you are using the correct flag, is probably because the support for C++11 in GCC 4.4 (which you seem to be using) is quite minimal. As you can see by the error messages, the compiler shows you the alternatives it have.
By the way, you don't need to cast integer literals to int, they are of type int by default. You might want to cast it to long double though, as that's one of the valid overloads and you seems to want to find the decimal point (the code will not work as expected if there is no decimal point in the string, like when converting an integer).
I recommend to use boost::lexical_cast instead.

G++ abs() on a short int appears to turn it into a double?

The following code does not compile if std::abs(angle) is present. The type of angle is in this case a short int.
template <class T>
typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t &angle) {
const int B = (sizeof(typename T::storage_t::single_t)*8) - 2;
return (angle<<1) - ((angle*(std::abs(angle)))>>B);
}
A close look at the messages can verify that angle is in fact a short int. However, if I am reading the error correctly, GCC turns it into a double.
math.hpp: In function ‘typename T::storage_t::single_t FastSin(const typename T::storage_t::double_t&) [with T = Fixed<_t<signed char, short int> >, typename T::storage_t::single_t = signed char, typename T::storage_t::double_t = short int]’:
vector.hpp:106:30: instantiated from ‘void Vector2<T>::FastRotate(const single_t&) [with T = Fixed<_t<signed char, short int> >, Vector2<T>::single_t = signed char]’
test.cpp:9:18: instantiated from here
math.hpp:11:52: error: invalid operands of types ‘__gnu_cxx::__enable_if<true, double>::__type {aka double}’ and ‘const int’ to binary ‘operator>>’
What is going on here? Even return (angle<<1) - ((angle*(std::abs<int>(angle)))>>B); does the same.
I am using gcc version 4.6.1. The only external headers included are <cmath> and <cstdint>. The compilation flags are -std=c++0x -Wall.
abs() is not a template, but a set of overload functions. According to the standard, the overload for int, long, float, double, long double should exist. But the overload for short does not exist. But as the conversion sequence from short to int is only a promotion, and the conversion sequence form short to the other overloaded types are all conversions, the overload for int should be selected.
But in g++ (version 4.5.2 for me), a non-standard template is added to cmath:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
This template would take all built-in integral types other than int and long and give a return value of double.
As a matter of fact, using type unsigned int also produces this error in g++:
#include <cstdlib>
#include <cmath>
int main() {
unsigned int i,j;
i=0;
j=std::abs(i)>>2;
return 0;
}
Explicitly casting it to int (std::abs((int)i);) should solve this problem.
The std::abs() function isn't a template in C++; there are just several overloads provided for different types. The ones for the integral types are in the header <cstdlib>. See http://www.cplusplus.com/reference/clibrary/cstdlib/abs/ and http://www.cplusplus.com/reference/clibrary/cmath/abs/ for more info.
I know that this post is already answered long ago, but i just want to give another perspective which should help someone else. My problem was with QT and mingw, always when i build with boost or some other libraries which use cmath and cstdlib i got this error. After some time i was pretty annoyed with this error, and i decided to do a little research about those two files.
I totally agree with fefe and his answer but that can only solve problems if you use it in you program or library ,and you know from a start what is a problem, and that wasn't my problem.
If you really need to include both files in same time (you need system, malloc... and all math functions) quick and dirty fix is to open header and on 106 line (on my computer) you will see something like this:
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::div_t;
using ::ldiv_t;
using ::abort;
//using ::abs;
using ::atexit;
using ::atof;
using ::atoi;
using ::atol;
using ::bsearch;
using ::calloc;
.
.
.
From code above you can see that cstdlib have function abs in std namespace and you need to comment that line in order to enable use of cmath abs function and to get rid of that nasty error.
I hope that this will help someone, and i am sorry for such a long post.