Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different results using same function from different libraries

Tags:

c++

cmath

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.

like image 946
Tuğberk Kaan Duman Avatar asked Aug 12 '17 15:08

Tuğberk Kaan Duman


2 Answers

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.

like image 88
spectras Avatar answered Sep 30 '22 14:09

spectras


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.

like image 25
sergej Avatar answered Sep 30 '22 16:09

sergej