I am working on a programming assignment. The assignment is to create a class for complex numbers, representing the numbers as two variables of type double. I am supposed to overload the +, -, *, <<, and >> symbols. I am struggling with this assignment. My code is all over the place, and each change I make increases the number of compiler errors. As many recommendations on what I am doing wrong and ways to improve as possible would be appreciated. Thank you in advance. My discombobulated code is below:
class Complex
{
public:
Complex();
Complex(double& realNumber, double& imaginaryNumber);
Complex(double realPart);
void input();
void output();
double getReal() const;
double getImaginary() const;
friend const Complex operator +(const Complex& num1, const Complex& num2);
friend const Complex operator -(const Complex& num1, const Complex& num2);
const Complex operator *(const Complex& num1, const Complex& num2);
bool Complex operator ==(const Complex& num1, const Complex& num2);
private:
double real, imaginary;
const Complex i(0, 1);
};
Complex::Complex(double& realPart);
Complex::Complex(double& realNumber, double& imaginaryNumber) : 0(realNumber),0*i(imaginaryNumber)
const Complex operator +(const Complex& num1, const Complex& num2);
const Complex operator -(const Complex& num1, const Complex& num2);
const Complex operator *(const Complex& num1, const Complex& num2);
bool Complex operator ==(const Complex& num1, const Complex& num2);
//------------------------------------------------
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;
int main()
{
Complex number1, number2, number3;
const double i = sqrt(-1);
Complex::Complex(double& realPart) : realPart(realPart + 0*i)
Complex::Complex(double& realNumber, double& imaginaryNumber) : 0(realNumber),0*i(imaginaryNumber)
const Complex operator +(const Complex& num1, const Complex& num2)
{
Complex num3;
num3.real = num1.getReal() + num2.getReal();
num3.imaginary = (num1.getImaginary() + num2.getImaginary());
return number3;
}
const Complex operator -(const Complex& num1, const Complex& num2)
{
Complex num3;
num3.real = num1.getReal() - num2.getReal();
num3.imaginary = (num1.getImaginary() - num2.getImaginary());
return number3;
}
const Complex operator *(const Complex& num1, const Complex& num2)
{
complex num3;
num3.real =(num1.getReal * num2.getReal() - num1.getImaginary() * num2.getImaginary()) ;
num3.imaginary = (num1.getReal() * num2.getImaginary() + num1.getImaginary() *num2.getReal);
return number3;
}
bool Complex operator ==(const Complex& num1, const Complex& num2)
{
return ( (num1.getReal() == num2.getReal() ) && (num1.getImaginary() == num2.getImaginary() ));
}
number1.input();
cout<<"Now please repeat with the second imaginary number: \n"<<endl;
number2.input();
if (number1 == number2)
{
cout<<number1<<" is equal to "<<number2<<endl;
}
else if (number1 > number2)
{
cout<<number1<<"is greater than "<<number2<<endl;
}
else
{
cout<<number1<<"is less than "<<number2<<endl;
};
cout<<number1<<" + "<<number2<<" = "<<number1+number2<<endl;
cout<<number1<<" - "<<number2<<" = "<<number1 - number2<<endl;
cout<<number1<<" * "<<number2<<" = "<<number1*number2<<endl;
};
//----------------------------------------
void Complex::input()
{
cout<<"Enter the real number of your complex number: "<<endl;
cin>>real;
cout<<"Enter the imaginary number (the numeral before the 'i') of your complex number" <<endl;
cin>>imaginary;
};
//void Complex::output()
temp.cpp:20:70: error: ‘const Complex Complex::operator*(const Complex&, const Complex&)’ must take either zero or one argument
const Complex operator *(const Complex& num1, const Complex& num2);
that's pretty unambiguous as far as errors go: the 'binary' (or two argument) operators are not class members - and you declare the 'binary' operators correctly as friends and again correctly define them in global scope later on in the code;
the 'unary' versions must be class members and the "other" object involved in the operation is 'this', as in, add 'this' complex number and the given one and return the result.
the '*' operator is special in the sense that it has a no-arguments version that is used for something else (...)
I know compiler errors can be overwhelming; so comment out code (like, all but your class declaration) and work your way through each error; then uncomment a bit more etc. Compile early, compile often. C++ freaking out over a misplaced semi-colon is easier to catch that way.
Related
C++14 introduces Compare::is_transparent for equivalent find operations in associative containers.
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
Finds an element with key that compares equivalent to the value x.
This overload only participates in overload resolution if the
qualified-id Compare::is_transparent is valid and denotes a type. It
allows calling this function without constructing an instance of Key
Since there is no longer temporary instance of Key constructed, these can be more efficient.
There does not seem to be an equivalent for unordered containers.
Why is there no Compare::key_equal / Compare::hash_equal?
I imagine it would be relatively simple to allow efficiently looking up of, eg, string literals in unordered containers?
template<>
struct hash<string>
{
std::size_t operator()(const string& s) const
{
return ...;
}
// hash_equal=true allows hashing string literals
std::size_t operator()(const char* s) const
{
return ...;
}
};
Keys that compare equal should produce the same hash value. Decoupling the hash function and the predicate, and at the same time making one or both heterogeneous, could be too much error prone.
Recent paper, P0919r2, brings up the following example:
std::hash<long>{}(-1L) == 18446744073709551615ULL
std::hash<double>{}(-1.0) == 11078049357879903929ULL
Although -1L and -1.0 compare equal, some heterogeneous hash function, not in line with the selected equality comparison logic, could produce different values. The paper adds heterogeneous lookup-enabled function templates --
find, count, equal_range, and contains -- but makes them available when the below requirements are met [unord.req]/p17:
If the qualified-id Hash::transparent_key_equal is valid and denotes a type ([temp.deduct]), then the program is ill-formed if either:
qualified-id Hash::transparent_key_equal::is_transparent is not valid or does not denote a type, or
Pred is a different type than equal_to<Key> or Hash::transparent_key_equal.
The member function templates find, count, equal_range, and contains shall not participate in overload resolution unless the qualified-id Hash::transparent_key_equal is valid and denotes a type ([temp.deduct]).
In such a case, Hash::transparent_key_equal overwrites the default predicate (std::equal_to<Key>) and is used for (transparent) equality checking, together with Hash itself for (transparent) hashing.
Under these conditions, the below transparent function objects could be used to enable heterogeneous lookup:
struct string_equal
{
using is_transparent = void;
bool operator()(const std::string& l, const std::string& r) const
{
return l.compare(r) == 0;
}
bool operator()(const std::string& l, const char* r) const
{
return l.compare(r) == 0;
}
bool operator()(const char* l, const std::string& r) const
{
return r.compare(l) == 0;
}
};
struct string_hash
{
using transparent_key_equal = string_equal; // or std::equal_to<>
std::size_t operator()(const std::string& s) const
{
return s.size();
}
std::size_t operator()(const char* s) const
{
return std::strlen(s);
}
};
Both -- string_equal and std::equal_to<> -- are transparent comparators and can be used as transparent_key_equal for string_hash.
Having this type alias (or a type definition itself) within the hash function class definition makes it clear that it is a valid predicate that works fine with that particular hashing logic and the two can't diverge. Such an unordered set can be declared as:
std::unordered_set<std::string, string_hash> u;
or:
std::unordered_set<std::string, string_hash, string_hash::transparent_key_equal> u;
Either will use string_hash and string_equal.
If you watch the Grill the committee video from CppCon, they explain why stuff like this happens: nobody fought for it.
C++ is standardized by committee but that committee requires input from the community. Someone has to write papers, respond to criticism, go to the meetings, etc... Then the feature can be voted on. The committee doesn't just sit there inventing language and library features. It only discusses and votes on those that are brought forward to it.
The following example (derived from the accepted answer) compiles on Apple clang version 13.1.6. Note that I had to put is_transparent both in NodeHash and NodeEq.
#include <unordered_set>
struct Node {
int id;
int count;
};
struct NodeEq {
using is_transparent = void;
bool operator() (Node const& a, Node const& b) const { return a.id == b.id; };
bool operator() (Node const& n, int const i) const { return n.id == i; };
bool operator() (int const i, Node const& n) const { return n.id == i; };
};
struct NodeHash {
using is_transparent = void;
using transparent_key_equal = NodeEq;
std::size_t operator() (Node const& n) const noexcept { return n.id; };
std::size_t operator() (int n) const noexcept { return n; };
};
using nodes_t = std::unordered_set< Node, NodeHash, NodeHash::transparent_key_equal >;
int main() {
nodes_t nodes;
nodes.find(1);
}
I am using Thrust 1.8 and I get two compiler errors when I try to compile the below code :
#include <thrust/device_vector.h>
#include <thrust/functional.h>
int main(int argc, char* argv[])
{
thrust::device_vector<bool> condition(100);
thrust::device_vector<int> input(100);
thrust::device_vector<float> result(100);
float mean = 10.4f;
thrust::transform(condition.begin(),condition.end(),input.begin(),result.begin(), ( (thrust::placeholders::_1 ) ? ( thrust::placeholders::_2) : (mean) ) );
}
When I try to compile, I get the following compiler time errors :
(for placeholders::_1)
Error : Expression must be of bool type (or convertible to bool)
(for placeholders::_2)
Error : operand types are incompatible ("const thrust::detail::functional::actor < thrust::detail::functional::argument<1U>>" and "float")
How to correct this?
You cannot use the placeholders like you tried to, i.e. in combination with a ternary operator.
Instead, you could create your own functor:
struct my_fun : public thrust::binary_function<bool,float,float>
{
float mean;
my_fun(float mean) : mean(mean) {}
__host__ __device__
float operator()(bool condition, float input) const
{
float result = mean;
if (condition)
{
result = input;
}
return result;
}
};
...
thrust::transform(condition.begin(),
condition.end(),
input.begin(),
result.begin(),
my_fun(mean));
My problem is in the following code:
The filter function compiles, and runs as it should when the source is not constant (the iterators are adjusted accordingly). However when I change the source to const, the compiler gives me the following error for the first two variables of the copy_if statement:
"the object has type qualifiers that are not compatible with the member function".
I believe there is a const to not const conversion error somewhere but frankly I have no idea where. Any help would be appreciated.
#include "thrust\device_vector.h"
#include "thrust\copy.h"
typedef thrust::device_vector<float>::const_iterator Dc_FloatIterator;
typedef thrust::device_vector<float>::iterator D_FloatIterator;
typedef thrust::device_vector<int>::const_iterator Dc_IntIterator;
typedef thrust::device_vector<int>::iterator D_IntIterator;
typedef thrust::tuple< Dc_IntIterator, Dc_IntIterator, Dc_FloatIterator> Dc_ListIteratorTuple;
typedef thrust::zip_iterator<Dc_ListIteratorTuple> Dc_ListIterator;//type of the class const iterator
typedef thrust::tuple< D_IntIterator, D_IntIterator, D_FloatIterator > D_ListIteratorTuple;
typedef thrust::zip_iterator<D_ListIteratorTuple> D_ListIterator;//type of the class iterator
struct selector{//selector functor for the copy if call
const int val;
selector(int _val) : val(_val) {}
__host__ __device__
bool operator()(const int& x ) {
return ( x == val );
}
};
class Foo{
public:
thrust::device_vector<int> ivec1;
thrust::device_vector<int> ivec2;
thrust::device_vector<float> fvec1;
Foo(){;}
~Foo(){;}
D_ListIterator begin(){//cast of begin iterator
return D_ListIterator(D_ListIteratorTuple( ivec1.begin(), ivec2.begin(), fvec1.begin() ));
}
D_ListIterator end(){//cast of end iterator
return D_ListIterator(D_ListIteratorTuple( ivec1.end(), ivec2.end(), fvec1.end() ));
}
Dc_ListIterator cbegin(){//cast of const begin iterator
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cbegin(), ivec2.cbegin(), fvec1.cbegin() ));
}
Dc_ListIterator cend(){//cast of const end iterator
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cend(), ivec2.cend(), fvec1.cend() ));
}
void const_filter( const Foo& TheOther, const int& target ){//doesnt work
//This function should copy those member of the vectors where
//the ivec2[i] == target is true
thrust::copy_if(
TheOther.cbegin(),
TheOther.cend(),
TheOther.ivec2.cbegin(),
this->begin(),
selector(target) );
}
void filter( Foo& TheOther, const int& target ){//works
//This function should copy those member of the vectors where
//the ivec2[i] == target is true
thrust::copy_if(
TheOther.begin(),
TheOther.end(),
TheOther.ivec2.cbegin(),
this->begin(),
selector(target) );
}
void insert(const int& one, const int& two,const float& three ){
ivec1.push_back(one);
ivec2.push_back(two);
fvec1.push_back(three);
}
int size(){
return ivec1.size();
}
};
bool CheckIfSublistIsConnected(const Foo& list,const int& sublist_num){
Foo tmp;
tmp.const_filter( list, sublist_num );
return (bool)tmp.size();//for symplicity, othervise here is a function that check if
//the edge list represents a connected graph
}
int main(void){
Foo list;
bool connected;
list.insert(10,2,1.0);
list.insert(11,2,1.0);
list.insert(12,2,1.0);
list.insert(10,3,1.0);
list.insert(10,3,1.0);
connected=CheckIfSublistIsConnected(list,2);
if( connected ) return 0;
else return -1;
}
I've found that replacing TheOther.cbegin() / .cend() with the folowing the compiler accepts it. This means I messed up somewhere in the typedef section, but where?
thrust::make_zip_iterator(
thrust::make_tuple(
TheOther.ivec1.cbegin(),
TheOther.ivec2.cbegin(),
TheOther.fvec1.cbegin() ))
As it comes out I've frogotten to add the const magic word at the definition of cend/cbegin.
Dc_ListIterator cbegin() const {
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cbegin(), ivec2.cbegin(), fvec1.cbegin() ));
}
Dc_ListIterator cend() const {
return Dc_ListIterator(Dc_ListIteratorTuple( ivec1.cend(), ivec2.cend(), fvec1.cend() ));
}
I have the following class functor in CUDA
class forSecondMax{
private:
int toExclude;
public:
__device__ void setToExclude(int val){
toExclude = val;
}
__device__ bool operator ()
(const DereferencedIteratorTuple& lhs, const DereferencedIteratorTuple& rhs)
{
using thrust::get;
//if you do <=, returns last occurence of largest element. < returns first
if (get<0>(lhs)== get<2>(lhs) /*&& get<0>(rhs) == get<2>(rhs)*/ && get<0>(lhs) != toExclude/* && get<0>(rhs)!= toExclude */) return get<1>(lhs) < get<1>(rhs); else
return true ;
}
};
is there a way to set the value of toExclude from the host?
All you need to do to solve achieve this is to define a constructor for the functor which sets the data member from an argument. So your class would look something like this:
class forSecondMax{
private:
int toExclude;
public:
__device__ __host__ forSecondMax(int x) : toExclude(x) {};
__device__ __host__ bool operator ()
(const DereferencedIteratorTuple& lhs,
const DereferencedIteratorTuple& rhs)
{
using thrust::get;
if (get<0>(lhs)== get<2>(lhs) && get<0>(lhs) != toExclude)
return get<1>(lhs) < get<1>(rhs);
else
return true ;
}
};
[disclaimer: written in browser, never tested or compiled, use at own risk]
To set the value prior to passing the functor to a thrust algorithm, create and instance of the functor and pass it to the thrust call, for example:
forSecondMax op(10);
thrust::remove_if(A.begin(), A.end(), op);
which would set the data member toExclude to a value of 10 in a new instance of the class, and use the instance in the stream compaction call.
I'm attempting to reduce the min and max of an array of values using Thrust and I seem to be stuck. Given an array of floats what I would like is to reduce their min and max values in one pass, but using thrust's reduce method I instead get the mother (or at least auntie) of all template compile errors.
My original code contains 5 lists of values spread over 2 float4 arrays that I want reduced, but I've boiled it down to this short example.
struct ReduceMinMax {
__host__ __device__
float2 operator()(float lhs, float rhs) {
return make_float2(Min(lhs, rhs), Max(lhs, rhs));
}
};
int main(int argc, char *argv[]){
thrust::device_vector<float> hat(4);
hat[0] = 3;
hat[1] = 5;
hat[2] = 6;
hat[3] = 1;
ReduceMinMax binary_op_of_dooooom;
thrust::reduce(hat.begin(), hat.end(), 4.0f, binary_op_of_dooooom);
}
If I split it into 2 reductions instead it of course works. My question is then: Is it possible to reduce both the min and max in one pass with thrust and how? If not then what is the most efficient way of achieving said reduction? Will a transform iterator help me (and if so, will the reduction then be a one pass reduction?)
Some additional info:
I'm using Thrust 1.5 (as supplied by CUDA 4.2.7)
My actual code is using reduce_by_key, not just reduce.
I found transform_reduce while writing this question, but that one doesn't take keys into account.
As talonmies notes, your reduction does not compile because thrust::reduce expects the binary operator's argument types to match its result type, but ReduceMinMax's argument type is float, while its result type is float2.
thrust::minmax_element implements this operation directly, but if necessary you could instead implement your reduction with thrust::inner_product, which generalizes thrust::reduce:
#include <thrust/inner_product.h>
#include <thrust/device_vector.h>
#include <thrust/extrema.h>
#include <cassert>
struct minmax_float
{
__host__ __device__
float2 operator()(float lhs, float rhs)
{
return make_float2(thrust::min(lhs, rhs), thrust::max(lhs, rhs));
}
};
struct minmax_float2
{
__host__ __device__
float2 operator()(float2 lhs, float2 rhs)
{
return make_float2(thrust::min(lhs.x, rhs.x), thrust::max(lhs.y, rhs.y));
}
};
float2 minmax1(const thrust::device_vector<float> &x)
{
return thrust::inner_product(x.begin(), x.end(), x.begin(), make_float2(4.0, 4.0f), minmax_float2(), minmax_float());
}
float2 minmax2(const thrust::device_vector<float> &x)
{
using namespace thrust;
pair<device_vector<float>::const_iterator, device_vector<float>::const_iterator> ptr_to_result;
ptr_to_result = minmax_element(x.begin(), x.end());
return make_float2(*ptr_to_result.first, *ptr_to_result.second);
}
int main()
{
thrust::device_vector<float> hat(4);
hat[0] = 3;
hat[1] = 5;
hat[2] = 6;
hat[3] = 1;
float2 result1 = minmax1(hat);
float2 result2 = minmax2(hat);
assert(result1.x == result2.x);
assert(result1.y == result2.y);
}