Reputation:
I came across this: Simplest way to check if two integers have same sign?
How can this be extended to more than two numbers (not necessarily integers)? Say, check if 4 numbers have the same sign (+ve or -ve).
I don't want to use bit operations as far as possible ... only logical conditions.
Thanks.
Upvotes: 3
Views: 8921
Reputation: 4476
Here's an example for multiple values. You just need make a connected graph of same sign comparisons from the two-value case:
(a<0) == (b<0) && (b<0) == (c<0) && (c<0) == (d<0) && ...
By connected, I mean "a" is checked with "b", then "b" with "c", etc.
Upvotes: 1
Reputation: 503913
This is a generic implementation. This will check if the elements of a container all share the same property.
One version returns an iterator to the first mismatched element, the concise version only returns true or false.
Because it's generic, you can also check if they are all even numbers, for example:
// shared_property.hpp
#ifndef SHARED_PROPERTY_HPP
#define SHARED_PROPERTY_HPP
// checks if all elements share a single property
// if one element does not share a property,
// it returns an iterator to that element
template <typename Iter, typename Func>
Iter share_property(Iter first, Iter last, Func func)
{
for(; first != last; ++first)
{
if (!func(*first))
{
// differs
break;
}
}
return first;
}
// only indicates if all elements share a property
template <typename Iter, typename Func>
bool share_property_concise(Iter first, Iter last, Func func)
{
return share_property(first, last, func) == last;
}
#endif
Example program:
#include "shared_property.hpp"
#include <functional>
#include <iostream>
#include <vector>
typedef std::vector<int> container;
void negative_test(void)
{
container negatives;
negatives.push_back(-1);
negatives.push_back(-2);
negatives.push_back(-3);
if (share_property_concise(negatives.begin(), negatives.end(),
std::bind2nd(std::less<int>(), 0)))
{
std::cout << "All elements are less than 0." << std::endl;
}
else
{
std::cout << "Not all elements are less than 0." << std::endl;
}
}
bool is_even(int i)
{
return i % 2 == 0;
}
void even_test(void)
{
container evens;
evens.push_back(2);
evens.push_back(4);
evens.push_back(10);
if (share_property_concise(evens.begin(), evens.end(),
is_even))
{
std::cout << "All elements are even." << std::endl;
}
else
{
std::cout << "Not all elements are even." << std::endl;
}
}
int main(void)
{
negative_test();
even_test();
}
It also works well for filtering containers based off a property:
#include "shared_property.hpp"
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
typedef std::vector<int> container;
template <typename Iter, typename OutIter, typename Func>
Func filter_container(Iter first, Iter last, OutIter out, Func func)
{
first = share_property(first, last, func);
while (first != last)
{
*out++ = *first++;
first = share_property(first, last, func);
}
return func;
};
int make_number(void)
{
return std::rand() % 20 - 10;
}
void find_negatives(void)
{
container numbers;
std::generate_n(std::back_inserter(numbers), 20, make_number);
container negatives;
filter_container(numbers.begin(), numbers.end(), std::back_inserter(negatives),
std::bind2nd(std::greater<int>(), 0));
std::cout << "List: " << std::endl;
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<int>(std::cout, "\n"));
std::cout << std::endl;
std::cout << "Negatives:" << std::endl;
std::copy(negatives.begin(), negatives.end(),
std::ostream_iterator<int>(std::cout, "\n"));
}
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
find_negatives();
}
This algorithm will test a set for consistency:
// consistent_property.hpp
#ifndef CONSISTENT_PROPERTY_HPP
#define CONSISTENT_PROPERTY_HPP
#include <boost/logic/tribool.hpp>
// checks if all elements consistently pass/fail a property
// if it returns indeterminate, then the results are mixed,
// otherwise all results pass or failed as indicated
template <typename Iter, typename Func>
boost::logic::tribool consistent_property(Iter first, Iter last, Func func)
{
bool result = func(*first++);
for(; first != last; ++first)
{
if (func(*first) != result)
{
// differs
return boost::logic::indeterminate;
}
}
return result;
}
#endif
This will check if a property is consistent throughout a container, not if it just holds true. That is, it will return false if all the elements do not pass the property, true if they all do (same result as share_property_concise
), and indeterminate if the result is mixed.
Here is an example:
#include "consistent_property.hpp"
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
typedef std::vector<int> container;
void check_sign(void)
{
container positives;
positives.push_back(1);
positives.push_back(2);
positives.push_back(3);
boost::logic::tribool result =
consistent_property(positives.begin(), positives.end(),
std::bind2nd(std::greater<int>(), 0));
if (boost::logic::indeterminate(result))
{
std::cout << "Mixed signs." << std::endl;
}
else if (result)
{
std::cout << "All positive." << std::endl;
}
else
{
std::cout << "All negative." << std::endl;
}
}
int main(void)
{
check_sign();
}
Lastly, I provide a functor that can get a less specific result to consistency. While the above will tell if the consistency failed, passed, or was mixed, using this functor with share_property
will only determine if the set is consistent, or mixed. You cannot deduce in which way it was consistent.
This is probably the simplest solution to the original problem. To have the same sign, without the need to know what that sign is, can be done this way, giving a quick & simple result; either they are all the same sign or not.
Add the following to consistent_property.hpp
:
// the functor to determine if the property that all elements
// in a set share, is the property that they all pass or fail
// a secondary property. there is no way to deduce what the
// status was (if they all passed or all failed), only if
// all the elements were consistent. true indicates consistency,
// false indicates lack thereof
template <typename T, typename Func>
class consistent_shared_property_binder
{
public:
consistent_shared_property_binder(const Func& func) :
_func(func)
{
}
bool operator()(const T& t)
{
bool result = _func(t);
static bool status = result; // only initialized first run
return status == result;
}
private:
Func _func;
};
// bind a function to the functor
template <typename T, typename Func>
consistent_shared_property_binder<T, Func> consistent_property(Func func)
{
return consistent_shared_property_binder<T, Func>(func);
}
And the example program:
#include "consistent_property.hpp"
#include "shared_property.hpp"
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
typedef std::vector<int> container;
bool is_positive(int i)
{
return i > 0;
}
void check_sign_anonymous(void)
{
container positives;
positives.push_back(-1);
positives.push_back(-2);
positives.push_back(-3);
if (share_property_concise(positives.begin(), positives.end(),
consistent_property<int>(is_positive)))
{
std::cout << "All the same sign." << std::endl;
}
else
{
std::cout << "Mixed signs." << std::endl;
}
}
int main(void)
{
check_sign_anonymous();
}
And I think I'm done. :P
(Note: If anyone sees a better way to do something, or a bug, please tell me!)
Upvotes: 2
Reputation: 27119
Let's say numbers are passed into a vector<int>
.
Iterate through the array, check if the two consequent number have the same sign, if not return false at the first non-equal-sign couple.
Upvotes: 7
Reputation:
Unless I misunderstand the question, the following should do the job for a vector of numbers:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> int Sign( T t ) {
return t < 0 ? -1 : 1;
}
template <typename T> bool SameSign( std::vector <T> & v ) {
if ( v.size() == 0 ) {
throw "invalid size";
}
int sign = Sign( v[0] );
for ( int i = 1; i < v.size(); i++ ) {
if ( Sign( v[i]) != sign ) {
return false;
}
}
return true;
}
int main() {
std::vector <int> v;
v.push_back(1);
v.push_back(1);
v.push_back(-1);
bool same = SameSign( v );
std::cout << (same ? "same" : "not same") <<"\n";
}
Upvotes: 2
Reputation: 27874
signof()
will return -1 for any negative, 0 for 0 and 1 for any positive number.
Edit:
In case of signof()
or signbit()
are not present, you may try using a bitwise operation to determine that. (number >> 31)
shall return 1
for negative 32-bits integers.
Upvotes: 1
Reputation: 43120
Something like this?
if ( n1 > 0 && n2 > 0 ... && nN > 0 )
// all positives
else if ( n1 < 0 && n2 < 0 ... && nN < 0 )
// all negatives
else
// mixed signs
Due to short-circuit evaluation it will be fast.
Upvotes: 2