I have an std::map<mpz_class,int> (for those unfamiliar, mpz_class is a class container for a very large integer number, defined by GMP, Gnu Multiprecision Library). I use a custom Comparator which uses GMP's cmp() function. In the map, I have inserted several std::pair<mpz_class,int> with correct values (they are reasonable when I print them).
However, I noticed map::find was not working correctly, so I printed what the Comparator is comparing. It turns out the second element (key) is always a very wild value integer value, like 128957236027369832796823768439267, way out of scale of the integers I'm working with.
Is there some sort of memory corruption going on that I'm unawares of? Perhaps mpz_class cannot be used in this fashion? How would I work around this problem? I haven't had this problem with other containers so far.
#include <map>
#include <gmpxx.h>
#include <iostream>
struct Equaler {
inline bool operator()(const mpz_class a, const mpz_class b) const {
std::cout << " about to return " << a << "," << b << "," << cmp(a,b) << "\n";
return cmp(a, b);
}
};
int main() {
mpz_class x("38268");
std::map<mpz_class,int,Equaler> map;
map.insert(std::pair<mpz_class,int>(x,42));
map.find(x);
return 0;
}
Output:
about to return 38268,812462232382732367817613904064203084469901797507,-2
The problem is your comparator. std::map expects a comparator which returns true if the first operand should be considered less than the second, and false otherwise. But cmp works differently. It doesn't return a boolean, it returns an integer, in one of three possible states:
negative : lhs < rhs
0 : lhs == rhs
positive : lhs > rhs
However, a negative and a positive integer, in a boolean context, both evaluate to true, so the results of cmp do not convert correctly to what std::map expects. Change this:
return cmp(a, b);
to this:
return cmp(a, b) < 0;
Related
This question already has answers here:
Good C++ solutions to the "Bring all the zeros to the back of the array" interview challenge
(3 answers)
Closed 4 years ago.
I am working on this question:
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.
I know how to answer this question by just doing in-place swapping, but I also would want to see if it is possible to solve it with std::sort.
According to cplusplus.com:
the comparator function for the sort function is a Binary function that accepts two elements in the range as arguments, and returns a value convertible to bool. The value returned indicates whether the element passed as first argument is considered to go before the second in the specific strict weak ordering it defines.
The function shall not modify any of its arguments.
This can either be a function pointer or a function object.
//comments below are based on my understanding
static bool comp(int a, int b){
//lambda function evaluates to true - no swap,
//evaluates to false -swap
if(a==0) return false;
if(b==0) return true;
//if neither a nor b is 0 them do not swap
return true;
}
void moveZeroes(vector<int>& nums) {
sort(nums.begin(),nums.end(),comp);
}
the given test case is [0,1,0,3,12]
my output is [12,3,1,0,0]
You almost had it right. In your comparator function, you have to return false to not swap them. Also, change std::sort to std::stable_sort to keep the values in original order.
static bool comp(int a, int b)
{
//lambda function evaluates to true - no swap,
//evaluates to false -swap
if(a==0) return false;
if(b==0) return true;
//if neither a nor b is 0 them do not swap
return false;
}
void moveZeros(std::vector<int>& nums)
{
std::stable_sort(nums.begin(),nums.end(),comp);
}
LIVE DEMO
As Drew Dormann pointed out stable partition is the proper algorithm. Here is the code:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> data { 0, 1, 0, 3, 12 };
std::stable_partition(
data.begin(), data.end(), [](int n) { return n != 0; });
for (auto i : data)
cout << i << ' ';
cout << endl;
}
The output is 1 3 12 0 0
The sort order you want to use is simply that zeros are "greater" than all non-zero values, and equal to other zeros. All other non-zero values are "less" than zero, and are equivalent to any other non-zero value.
Construct the comparison function properly, then you can use it in a call to std::stable_sort to achieve what you're trying to do.
I wrote a function for vector comparison.
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector;
using std::cout;
bool mycomp(const vector<int>& vi_a, const vector<int>& vi_b){
for(auto x:vi_a) cout << x;
cout << '\n';
return true;
}
int main(){
vector<int> vi1{2,9,8};
vector<int> vi2{3,5,6};
vector<int> vi = min(vi1, vi2, mycomp);
for(auto x:vi) cout << x;
cout << '\n';
}
Output:
356
356
What's weird is that the output is 356, instead of 298. It seems that the two vectors are switched when calling mycomp.
p.s. I'd rather not use lambda here, because mycomp contains more than one line of code, which is more readable this way.
If you take a look at the cppreference documentation for std::min() you will see in the possible implementation that the second element is used as the first element in the comparator.
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp)
{
return (comp(b, a)) ? b : a;
}
And when you call min() with the arguments vi2 and vi1, the second argument is passed to the comparator (which in your case is vi2), upon which the comparator returns true (implying that vi2 is the minimum of the two). While doing this the comparator also prints out 356 because that is the first element passed to the comparator according to the possible implementation above.
After that happens you take the presumably smaller of the two vectors, which is the first one passed to the comparator according to the possible implementation above (which is vi2). And you print that out. Therefore you get 356 again.
Note that the reason b is passed as the first argument to std::min is because in the case where the two compare equal the algorithm is required to return a. At the same time it is required to call the comparator only once. Combining these two requirements gives the possible implementation above.
Mainly as an exercise I am implementing a conversion from base B to base 10:
unsigned fromBaseB(std::vector<unsigned> x,unsigned b){
unsigned out = 0;
unsigned pow = 1;
for (size_t i=0;i<x.size();i++){
out += pow * x[i];
pow *= b;
}
return out;
}
int main() {
auto z = std::vector<unsigned>(9,0);
z[3] = 1;
std::cout << fromBaseB(z,3) << std::endl;
}
Now I would like to write this using algorithms. E.g. using accumulate I could write
unsigned fromBaseB2(std::vector<unsigned> x,unsigned b){
unsigned pow = 1;
return std::accumulate(x.begin(),
x.end(),0u,
[pow,b](unsigned sum,unsigned v) mutable {
unsigned out = pow*v;
pow *= b;
return out+sum;
});
}
However, imho thats not nicer code at all. Actually it would be more natural to write it as an inner product, because thats just what we have to calculate to make the basis transformation. But to use inner_product I need an iterator:
template <typename T> struct pow_iterator{
typedef T value_type;
pow_iterator(T base) : base(base),value(1) {}
T base,value;
pow_iterator& operator++(){ value *= base;return *this; }
T operator*() {return value; }
bool operator==(const pow_iterator& other) const { return value == other.value;}
};
unsigned fromBaseB3(std::vector<unsigned> x,unsigned b){
return std::inner_product(x.begin(),x.end(),pow_iterator<unsigned>(b),0u);
}
Using that iterator, now calling the algorithm is nice an clean, but I had to write a lot of boilerplate code for the iterator. Maybe it is just my misunderstanding of how algorithms and iterators are supposed to be used... Actually this is just an example of a general problem I am facing sometimes: I have a sequence of numbers that is calculated based on a simple pattern and I would like to have a iterator that when dereferenced returns the corresponding number from that sequence. When the sequence is stored in a container I simply use the iterators provided by the container, but I would like to do the same, also when there is no container where the values are stored. I could of course try to write my own generic iterator that does the job, but isnt there something existing in the standard library that can help here?
To me it feels a bit strange, that I can use a lambda to cheat accumulate into calculating an inner product, but to use inner_product directly I have to do something extra (either precalculate the powers and store them in a container, or write an iterator ie. a seperate class).
tl;dr: Is there a easy way to reduce the boilerplate for the pow_iterator above?
the more general (but maybe too broad) question: Is it "ok" to use an iterator for a sequence of values that is not stored in a container, but that is calculated only if the iterator is dereferenced? Is there a "C++ way" of implementing it?
As Richard Hodges wrote in the comments, you can look at boost::iterator. Alternatively, there is range-v3. If you go with boost, there are a few possible ways to go. The following shows how to do so with boost::iterator::counting_iterator and boost::iterator::transform_iterator (C++ 11):
#include <iostream>
#include <cmath>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
int main() {
const std::size_t base = 2;
auto make_it = [](std::size_t i) {
return boost::make_transform_iterator(
boost::make_counting_iterator(i),
[](std::size_t j){return std::pow(base, j);});};
for(auto b = make_it(0); b != make_it(10); ++b)
std::cout << *b << std::endl;
}
Here's the output:
$ ./a.out
1
2
4
8
16
32
64
128
256
512
I'm having some problems with std set. I know that it does not allows you to insert repeated elements and (I think that) my code is not trying to insert repeated elements. But it seems like the set is not inserting both elements. What is the problem? Is the collection considering both elements equal? Why?
#include <bits/stdc++.h>
using namespace std;
struct sam{
double a,b, tam;
sam(){
}
sam(double a1, double b1){
a = a1;
b = b1;
tam = b - a;
}
bool operator<(const sam &p) const{
return tam > p.tam;
}
};
set<sam> ssw;
int main(void){
ssw.insert(sam(0,2));
ssw.insert(sam(4,6));
cout<<ssw.size()<<"\n"; // prints "1"
return 0;
}
For both objects, the value of tam is 2.0. Since the operator< function works with that value, the two objects are considered to be equal.
BTW, using a floating point number to compare two objects is not a good idea. You can get unexpected results due to the imprecise nature of how floating points are represented.
In std::set
In imprecise terms, two objects a and b are considered equivalent (not
unique) if neither compares less than the other: !comp(a, b) &&
!comp(b, a)
In your case bool operator< not satisfy the above condition hence set treats them not unique.
Currently your comparator returns same values for both the inserts. Hence, only one item is successfully inserted. The other is just a duplicate, and is hence, ignored.
Maybe you meant this:
bool operator<(const sam &p) const{
return ( (a > p.a) || (b > p.b) || (tam > p.tam) );
}
So, I was trying to come up with a solution for When does x==x+2 in C++ on codegolf, and came up with this snippet only to realize that I don't know how it works. I'm not sure why both of these conditions evaluate to true.
Does anyone know if the line labeled line: is true because x==&x or because x+2 is evaluated before the left-hand side of ==?
#include <iostream>
#include <vector>
std::vector<int>& operator+ ( std::vector<int> &v, int val )
{
v.push_back(val);
return v;
}
int main()
{
std::vector<int> x;
std::vector<int> y = x + 2; // y is a copy of x, and x is [2]
// how are both of these are true?
std::cout << (x==y) << "\n"; // value comparison [2]==[2]
line:
std::cout << (x==x+2) << "\n"; // reference comparison? &x == &(x+2)
// not sure if this is relevant
std::cout << (x+2==x) << "\n"; // also true
return 0;
}
It seems--since vectors appear to be compared by value--that if x were evaluated before x+2, then x wouldn't be equal to x+2 (by value). I'm probably missing something obvious. Thanks in advance.
For the standard containers, operator== is overloaded as std::equal. This in turn works on iterators and applies comparison by dereferncing, as in *it1 == *it2. Therefore, no copies are required.
The expression x == x + 2 is the same as operator==(x, x + 2). Both operands are evaluated before the function call, and since x + 2 modifies x, both operands are the same. Thus the equality holds.
The surprise is the result of your unconventional design choice in overloading the +-operator. This is generally poor practice and a taboo in any collaborative project. If you absolutely must overload operators, then only if they behave as expected, follow established semantics and are not surprising. The usual behaviour of the +-operator is to return a new object, by value, and leave the operand unaffected. Like so:
std::vector<int> operator+(std::vector<int> v, int n)
{
v.push_back(n);
return v;
}
std::vector's equality comparison performs a lexicographical compare that checks that the size of lhs and rhs are the same, and then compares element by element.
The problem with your code is that you are assigning x+2 to y, and your addition operator is modifying the lhs, acting like a += operator.
Here:
std::vector<int> y = x + 2;
this modifies x, and copy assigns y from x. A well behaved operator+ would be something like
std::vector<int> operator+ ( std::vector<int> v, int val )
{
v.push_back(val);
return v;
}
The confusion arises from the unconventional definition of +. Normally, it would return a modified copy of its argument, leaving the argument itself unchanged. Since the operator acts more like +=, modifying its argument and returning a reference to it, this is roughly equivalent to:
x.push_back(2), x == x
comparing the modified vector to itself.
C++ always compares values, never references; if you want a reference comparison, then you must explicitly compare addresses, &x == &y.
std::vector::operator==() is (usually?) a function, and this is a sequence point in C++03, which means that it needs to fully evaluate all of it's parameters before it can be called.
Both parameters resolve to the same reference (vector x), so it is only natural that it would evaluate to true.
This is because that operator+ never creates a new object, it just modifies one.
It is, in fact, equivalent to this code:
std::vector<int> x;
x.push_back(2);
std::cout << (x==x) << "\n"; // this is no surprise