<Functional>: plus<long>() on integers gives unexpected result - c++

I don’t understand why I do not get the same results in these two cases:
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<int> v;
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0, plus<long long>());
cout << r << endl;
return 0;
}
Anyone any ideas?
EDIT: as correctly pointed out below, this is due to the sign bit in int I wasn't counting on. 0x7FFFFFFF would obviously be better for testing. Also, I erroneously expected that the return type of plus() would be the same as for accumulate(), which is not the case: it is based on the third argument.

There are two problems here:
The number 0xFFFFFFFF won't fit in an int (assuming 32-bit ints), so the value stored in the vector is actually -1 on most implementations. Using vector<unsigned int> or vector<long long> should fix this.
The type returned by accumulate is the type deduced from the third parameter. Since you passed in 0, this will be int. You should pass in 0LL instead so that it returns long long.
This program with both fixes will return the correct result:
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<long long> v; //or vector<unsigned int>
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0LL, plus<long long>());
cout << r << endl;
return 0;
}

Because your vector contains type int and 0xFFFFFFFF doesn't fit into it. Try to change it to long long.
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <functional> // for plus()
using namespace std;
int main() {
long long i = (long long) 0xFFFFFFFF + 2;
cout << i << endl;
vector<long long> v;
v.push_back(0xFFFFFFFF);
v.push_back(2);
long long r = accumulate(v.begin(), v.end(), 0LL, plus<long long>());
cout << r << endl;
return 0;
}
EDIT:
Also, as pointed by interjay, third parameter should have type long long since accumulate uses it to deduce resulting type.

Your vector stores type int which is probably a 32 bit type. From 4.7/3 we learn:
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.
In other words, your value 0xFFFFFFFF can't be represented in the destination signed type so the results are implementation defined. In this case, it most likely took the obvious twos-comp result and stored a -1 in the vector. Then when you do the accumulate, it adds -1 (because it doesn't change the stored -1) and 2, resulting in the 1 being printed.
Most likely you wanted to store long long in the vector (since you're summing values larger than a 32 bit can hold), and as noted in other answers you would also need to pass 0LL to accumulate to force it to infer the correct return type.

Related

How to make small signed integer literals that take into account 2s complement?

I've been trying to make signed literal short hands for <cstdint> types, for example, u8, u16, etc...
I developed a function like this:
constexpr std::int8_t operator "" _i8(unsigned long long int value){
unsigned long long int mask = 0xEF;
if(value && mask == value){
return static_cast<std::int8_t>(value);
}else{
throw std::out_of_range("");
}
}
I then looked up and found that - is actually not part of the literal. What this means for me is that the above code( if it included 128, right now it doesn't) wouldn't actually work correctly for -128.
When I try this out in godbolt
#include <type_traits>
#include <iostream>
#include <cstdint>
#include <bitset>
int main(){
std::cout << std::bitset<8>(static_cast<std::int8_t>(128)) << std::endl;
std::cout << static_cast<std::int32_t>(static_cast<std::int8_t>(128)) << std::endl;
std::cout << static_cast<std::int32_t>(static_cast<std::int8_t>(-128)) << std::endl;
std::cout << static_cast<std::int32_t>(-static_cast<std::int8_t>(128)) << std::endl;
return 0;
}
I get 10000000, -128, -128, and 128
Technically using 128 could work in the above example, it would just force the value to be -128 on the output, but when they (correctly) add a negative, it will turn into 128, and not be a int8_t. I'd like errors on 128 with no negative, and no errors on 128 with negative.
I thought about making some sort of temporary object with - overloaded for it, and implicitly converting, but even with that, it won't work properly in template functions, so the unary - operator would have to return the base type, and I would somehow have to return the base type switched on if the value is 128 or not, but I don't think that's possible.
I basically want the following to work:
template<typename T>
foo(const T& bar, const T& baz);
foo(127_i8, std::int8_t(32));
foo(-128_i8, std::int8_t(32));
and this to not work:
foo(128_i8, std::int8_t(32));

Purpose of using (int) in the code below?

n=b.size()
n = max(n,(int)a.size());
where a and b are some user-Input strings and n is an integer. would anybody tell me why we use (int)a.size() and what is the purpose of using (int).
I am assuming that n is of type int, and your program will be something like this :
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string a ("Test string");
string b ("Test two");
int n = b.size() ;
n = max(n,(int)a.size());
cout << "n : " << n ;
return 0;
}
Now if you see the documentation for the .size() method of the string class, you will see it returns value of type : size_t
size_t is an unsigned integral type (the same as member type
string::size_type)
: as per documentation
Now when we look at the documentation for max() you can see it uses templating (you can read more about templating here) what it essentially means is that you can use any type as parameter (int, float, etc..) but both the parameters need to be the same type.
Now since n was declared as an int when calling max(n,x);, x needs to be type of n which basically means int in our case.
Now this is the reason for using (int) before a.size(). What we are doing here is type casting, since a.size() returns in type size_t which is different from int (You can read more about this here), we need to typecast the return value to int which can be done by (int)a.size().
SIDE NOTE
int n = max(b.size(),a.size());
cout << "n : " << n << " \n";
would also work, since both are same type so no need to do type casting.

C++ auto on int16_t casts to integer

I am pretty new to C++17 and am attempting to understand the decltype keyword and how it pairs with auto.
Below is a snippet of code that produces an unexpected result.
#include <typeinfo>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int16_t mid = 4;
auto low = mid - static_cast<int16_t>(2);
auto hi = mid + static_cast<int16_t>(2);
int16_t val;
cin >> val;
val = std::clamp(val,low,hi);
return 0;
}
Surprisingly, the compiler tells me there is a mismatch in clamp and that low and high are int. If I change auto to int16_t all is good in the world and all the types are int16_t as expected.
The question I'm posing is, why does auto cast low and hi to int when all of the types are int16_t? Is this a good use case for decltype?
Even after reading cppreference.com, I don't fully understand how decltype works, so excuse my ignorance.
The problem isn't with auto here. When you subtract two int16_t values, the result is an int. We can demonstrate it with this code here:
#include <iostream>
#include <cstdint>
using namespace std;
template<class T>
void print_type(T) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main() {
int16_t a = 10;
int16_t b = 20;
print_type(a);
print_type(b);
print_type(a - b);
return 0;
}
a and b are both short ints, but when you add or subtract them it produces a regular int. This is to help prevent overflow / and is also for backwards compatibility.
This phenomenon is called the usual arithmetic conversions. It is defined in the C and C++ standards and (roughly said) converts anything smaller than an int to an int. It converts larger types as well. Take some time and read about it, you'll need it quite often.

Node size for unordered_map buckets

I have a program where I want to store kmers (substrings of size k) and the number of times they appear. For this particular application, I'm reading in a file with these values and if the number of times they appear is > 255, it is ok to round down to 255. I thought that if I store the key-value pairs as (string, unsigned char) that might save space compared to storing the key-value pairs as (string, int), but this did not seem to be the case when I checked the max resident size by running /usr/bin/time.
To confirm, I also tried running the following test program where I alternated the type of the value in the unordered_map:
#include <iostream>
#include <unordered_map>
#include <utility>
#include <string>
#include <fstream>
int main() {
std::unordered_map<std::string, unsigned char> kmap;
std::ifstream infile("kmers_from_reads");
std::string kmer;
int abun;
while(infile >> kmer >> abun) {
unsigned char abundance = (abun > 255) ? 255 : abun;
kmap[kmer] = abundance;
}
std::cout << sizeof(*kmap.begin(0)) << std::endl;
}
This did not seem to impact the size of the nodes in the bucket (on my machine it returned 40 for both unsigned char and int values).
I was wondering how the size of the nodes in each bucket is determined.
My understanding of unordered maps is that the c++ standard more or less requires separate chaining and each node in a bucket must have at least one pointer so that the elements are iterable and can be erased (http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html). However, I don't understand how the amount of space to store a value is determined, and it seems like it must also be flexible to accommodate larger values. I also tried looking at the gcc libstc++ unordered_map header (https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/unordered_map.h) but had a hard time understanding what was going on.
Compile and execute this code:
#include <iostream>
#include <unordered_map>
#include <utility>
#include <string>
#include <fstream>
class foo
{
std::string kmer;
unsigned char abun;
};
class bar
{
std::string kmer;
int abun;
};
int main() {
std::cout << sizeof(foo) << " " << sizeof(bar) << std::endl;
}
I get, and you probably will too, 40 40. This is because of alignment requirements. If, for example, std::string contains at least one pointer (which it almost certainly does), it has to be aligned on at least a 4-byte boundary.
Imagine if sizeof(foo) was 39 and you had code that did foo foos[2]. If the pointer in foos[0].kmer was properly aligned, the pointer in foos[1].kmer wouldn't be. That would be a disaster.

C++ Function supposed to return Long, returning Integer like value instead

While working on a fairly large project, I happened to notice that one of my functions that is supposed to return a Long value is either returning an Integer. I reproduced the error in a very small environment thinking that it would make the problem clear to me, but I'm still not seeing the issue. The input is 1.123, and the return value is 1. If I input any Long, for example; 123.456, it will only return 123. What am I not seeing?
Source1.cpp
#ifndef HEADER_H
#define HEADER_H
using namespace std;
class testClass
{
private:
long m_testLong = 0.0;
public:
long getTestLong();
void setTestLong(long sn);
};
#endif
Header.h
#include "Source1.cpp"
#include <string.h>
void testClass::setTestLong(long sn)
{
m_testLong = sn;
}
long testClass::getTestLong()
{
return m_testLong;
}
Source.cpp
#include <iostream>
#include "Source1.cpp"
#include "Header.h"
using namespace std;
int main(void)
{
testClass *myClass = new testClass;
cout << "Setting test long value using setTestLong function -- 1.123" << endl;
myClass->setTestLong(1.123);
long tempTestLong = 0.0;
tempTestLong = myClass->getTestLong();
cout << tempTestLong << endl;
system("Pause");
return 0;
}
OK, so the answer was painfully simple. I hadn't worked with longs before, but I thought I knew what they were. I didn't.
So longs and integers both are whole numbers, and having the type listed as long made me assume an integer wouldn't work, and I tested the function with a double because of my misunderstanding. Thanks for the help!
The long and int types are integral types, they can only hold whole numbers like 7 or 42.
You should be using float or double as a type, preferably the latter for increased range and precision. That will allow you to hold real numbers such as 3.141592653589 or 2.718281828459.
Long is an integer. Assigning a floating point value to integer causes rounding.
You want double or float.