Is there a good and fast way in C/C++ to test if multiple variables contains either all positive or all negative values?
Say there a 5 variables to test:
Variant 1
int test(int a[5]) {
if (a[0] < 0 && a[1] < 0 && a[2] < 0 && a[3] < 0 && a[4] < 0) {
return -1;
} else if (a[0] > 0 && a[1] > 0 && a[2] > 0 && a[3] > 0 && a[4] > 0) {
return 1;
} else {
return 0;
}
}
Variant 2
int test(int a[5]) {
unsigned int mask = 0;
mask |= (a[0] >> numeric_limits<int>::digits) << 1;
mask |= (a[1] >> numeric_limits<int>::digits) << 2;
mask |= (a[2] >> numeric_limits<int>::digits) << 3;
mask |= (a[3] >> numeric_limits<int>::digits) << 4;
mask |= (a[4] >> numeric_limits<int>::digits) << 5;
if (mask == 0) {
return 1;
} else if (mask == (1 << 5) - 1) {
return -1;
} else {
return 0;
}
}
Variant 2a
int test(int a[5]) {
unsigned int mask = 0;
for (int i = 0; i < 5; i++) {
mask <<= 1;
mask |= a[i] >> numeric_limits<int>::digits;
}
if (mask == 0) {
return 1;
} else if (mask == (1 << 5) - 1) {
return -1;
} else {
return 0;
}
}
What Version should I prefer? Is there any adavantage using variant 2/2a over 1? Or is there a better/faster/cleaner way?
I think your question and what you're looking for don't agree. You asked how to detect if they're signed or unsigned, but it looks like you mean how to test if they're positive or negative.
A quick test for all negative:
if ((a[0]&a[1]&a[2]&a[3]&a[4])<0)
and all non-negative (>=0):
if ((a[0]|a[1]|a[2]|a[3]|a[4])>=0)
I can't think of a good way to test that they're all strictly positive (not zero) right off, but there should be one.
Note that these tests are correct and portable for twos complement systems (anything in the real world you would care about), but they're slightly wrong for ones complement or sign-magnitude. They might can be fixed if you really care.
I guess you mean negative/positive, (un)signed means whether a sign exists at all. This one works for any iterable (this assumes you count 0 as positive):
template <class T>
bool allpos(const T start, const T end) {
T it;
for (it = start; it != end; it++) {
if (*it < 0) return false;
}
return true;
}
// usage
int a[5] = {-5, 3, 1, 0, 4};
bool ispos = allpos(a, a + 5);
Note: This is a good and fast way
This may not be the absolutely extremely superduperfastest way to do it, but it certainly is readable and really fast. Optimizing this is just not worth it.
Variant 1 is the only readable one.
However, you could make it nicer using a loop:
int test(int *a, int n) {
int neg = 0;
for(int i = 0; i < n; i++) {
if(a[i] < 0) neg++;
}
if(neg == 0) return 1;
else if(neg == n) return -1;
else return 0;
}
I agree with previous posters that loops are simpler. The following solution combines Nightcracker's template and ThiefMaster's full solution, with early-outing if a sign-change is detected while looping over the variables (early-outing). And it works for floating point values.
template<typename T>
int testConsistentSigns(const T* i_begin, const T* i_end)
{
bool is_positive = !(*i_begin < 0);
for(const T* it = i_begin + 1; it < i_end; ++it)
{
if((*it < 0) && is_positive)
return 0;
}
if(is_positive)
return 1;
return -1;
}
In terms of speed, I suggest you profile each of your example in turn to discover which is the fastest on your particular platform.
In terms of ease of understanding, I'd say that the first example is the most obvious, though that's just my opinion.
Of course, the first version is a maintenance nightmare if you have more than 5 variables. The second and third variants are better for this, but obviously have a limit of 32 variables. To make them fully flexible, I would suggest keeping counters of the number of positive and negative variables, in a loop. After the end of the loop, just check that one or other counter is zero.
First off, create a method\procedure. That'll boost readability by a whole lot (no matter how you implement it, it'll be cleaner then all the options above).
Second, I think that the function:
bool isNeg(int x) { return x < 0;}
s cleaner then using bit masks, so I'll go with option 1, and when it comes to speed, let the compiler work that out for you in such low-level cases.
The final code should look something like:
int test(int a[5]) {
bool allNeg = true;
bool allPos = true;
for (i = 0; i < 5; i++){
if (isNeg(a[i]) allPos = false;
if (isPos(a[i]) allNeg = false;
}
if (allNeg) return -1;
if (allPos) return 1;
return 0;
}
You could find maximum element, if it is negative then all elements are negative:
template<typename T>
bool all_negative( const T* first, const T* last )
{
const T* max_el = std::max_element( first, last );
if ( *max_el < T(0) ) return true;
else return false;
}
You could use boost::minmax_element to find if all elements are negative/positive in one loop:
template<typename T>
int positive_negative( const T* first, const T* last )
{
std::pair<const T*,const T*> min_max_el = boost::minmax_element( first, last );
if ( *min_max_el.second < T(0) ) return -1;
else if ( *min_max_el.first > T(0) ) return 1;
else return 0;
}
If the sequence is non-empty, the function minmax_element performs at most 3 * (last - first - 1) / 2 comparisons.
If you only need to know less/greater than zero one at a time, or can be content with < and >= you can do it easily with find_if like this:
#include <iostream>
template <class Iter>
int all_neg(Iter begin, Iter end)
{
return std::find_if(begin, end, std::bind2nd(std::greater_equal<int>(), 0)) == end;
}
int main()
{
int a1[5] = { 1, 2, 3, 4, 5 };
int a2[5] = { -1, 2, 3, 4, 5 };
int a3[5] = { -1, -2, -3, -4, -5 };
int a4[5] = { 0 };
std::cout << all_neg(a1, a1 + 5) << ":"
<< all_neg(a2, a2 + 5) << ":"
<< all_neg(a3, a3 + 5) << ":"
<< all_neg(a4, a4 + 5) << std::endl;
}
You can also use a more complicated predicate that keeps track of any pos/neg to answer your original question if you really need that level of detail.
Related
I tried to solve this exercise
I got 66 percent
I can not understand why
can you help?
The exercise is:
Write a function:
int solution(vector &A);
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
The solution I wrote is:
#include <algorithm>
#include<cmath>
using namespace std;
int solution(vector<int> &A) {
if (A.size() == 0 || (A.size() == 1 && A.at(0) <= 0))
return 1;
if (A.size() == 1)
return A.at(0) + 1;
sort(A.begin(), A.end());
if (A.at(A.size() - 1) <= 0)
return 1;
auto ip = std::unique(A.begin(), A.end());
A.resize(distance(A.begin(), ip));
A.erase(remove_if(A.begin(), A.end(), [](const int i) { return i < 0; }),A.end());
if (A.at(0) != 1)
return 1;
if (A.size() == 1)
return (A.at(0) != 1 ? 1 : 2);
int i = 0;
for (; i < A.size(); ++i) {
if (A.at(i) != i + 1)
return A.at(i - 1) + 1;
}
return A.at(A.size()) + 1;
}
The following algorithm has a complexity O(n). No need to sort or to erase.
We know that the first missing value is less or equal to n+1, if n is the array size.
Then we simply have to use an array of size n+2, present[n+2], initialised to 0, and then to look at all values A[i]:
if (A[i] <= 1+n && A[i] > 0) present[A[i]] = 1;
Finally, in a second step we simply have to examine the array present[.], and search for the first index k such that present[k]==0.
#include <iostream>
#include <vector>
int find_missing (const std::vector<int> &A) {
int n = A.size();
std::vector<int> present (n+2, 0);
int vmax = n+1;
for (int i = 0; i < n; ++i) {
if (A[i] <= vmax && A[i] > 0) {
present[A[i]] = 1;
}
}
for (int k = 1; k <= vmax; ++k) {
if (present[k] == 0) return k;
}
return -1;
}
int main() {
std::vector<int> A = {1, 2, 0, 3, -3, 5, 6, 8};
int missing = find_missing (A);
std::cout << "First missing element = " << missing << std::endl;
return 0;
}
Well this is wrong
if(A.size()==1)
return A.at(0)+1;
If A is {2} that code will return 3 when the correct answer is 1
Also
A.erase(remove_if(A.begin(), A.end(),[](const int i) {return i < 0; }),A.end());
should be
A.erase(remove_if(A.begin(), A.end(),[](const int i) {return i <= 0; }),A.end());
Also
return A.at(A.size()) + 1;
is a guaranteed vector out of bounds error.
Even a small amount of testing and debugging would have caught these errors. It's a habit you should get into.
I think there are far too many special cases in the code, which only serve to complicate the code and increase the chance of bugs.
This answer is the implementation of the proposal given in the comment by PaulMcKenzie.
So, all credits go to PaulMcKenzie
It is not the fastest solution, but compact. The idea is basically.
Sort the data
Then compare the adjacent values, if the next value is equal to the previous value+1.
If not, then we found a gap. This can be implemented by using the function std::adjacent_find. Description can be found here.
We put all the side conditions into the lambda. If std::adjacent_find cannot find a value, then we take the next possible positive value.
I am not sure, what I could describe more. Please see the below example:
#include <iostream>
#include <vector>
#include <algorithm>
int solution(std::vector<int>& data) {
// Sort
std::sort(data.begin(), data.end());
// Check if there is a gap in the positive values
const auto gap = std::adjacent_find(data.begin(), data.end(), [](const int p, const int n) { return (n !=p) && (n != (p + 1) && p>0); });
// If there is no gap, the take the next positive value
return (gap == data.end()) ? (data.back() > 0 ? data.back() + 1 : 1) : *gap + 1;
}
int main() {
//Some test cases
std::vector<std::vector<int>> testCases{
{1,3,6,4,1,2},
{1,2,3},
{-1,-3}
};
for (auto& testCase : testCases)
std::cout << solution(testCase) << '\n';
return 0;
}
others have already pointed out what are the main errors, but I would like to invite you to try a different solution instead of trying to fix all the bugs and spend much time on debugging, because your solution seems a little overcomplicated.
Here I propose a way you can think about the problem:
What is the minimum number the function can return? Since it returns a positive integer, it is 1, in the case 1 is not in the array. Since that we can use any number <=0 to see if we found our result scanning the vector (see next);
In case one is not in the array, how do I find the wanted number? Your intuition is correct, if your vector is sorted it is easier: you can iterate over your data, and when you find an "hole" between two subsequent elements, then the value of the first element of the hole + 1 is you result
What do I do if the array contains 1 and has no holes? Well, you return the smallest element that is not in the array, so the last element + 1. You may notice that by checking if your "candidate" value (that is a number that shouldn't be returned, so <=0) has changed during the scanning;
Let's go to the code:
int solution(std::vector<int>& v){
int retVal=0;
std::sort(v.begin(), v.end());
for(int i=0; i<v.size()-1; i++){
if(v[i]>0 && v[i+1]>v[i]+1){
retVal=v[i]+1;
break;
}
}
if(retVal==0) {
if (v.back() > 0)
retVal = v.back() + 1;
else
retVal = 1;
}
return retVal;
}
As suggested you can use the standard library a little bit more, but I think this is reasonably simple and efficient.
Other note:
I think your assignment does not bother you with this, but I mention just for completeness. Most of the times you don't want a function to modify your parameters: you can pass the vector "by value" meaning that actually you pass a complete copy of your data, without touching the original one, or you can pass a const reference and create a copy inside the function.
I'm trying to write a recursive function that checks if two arrays have the same elements even if they aren't sorted, but I I can't change the arrays and I can't copy them or use a third/fourth arrays and it has to be recursive, lastly, I can't change the signature of the function.
So now I have to get rid of overwrite(A2, len, i); because that's destroying A2, but I don't see any way to do it and still have a working function... can I have a hint on how to do it? Maybe there's a way to save the elements of A2 by swapping them and then by the end of the recursion to restore them?
In short the algorithm below does a linear search of the last element of A1 in A2, if it's found, overwrite it and continue, this is done so the algorithm won't pick the same element twice, reaching the stopping condition means all the elements are there thus it will return true, otherwise will return false.
bool foo(int A1[], int A2[], int len){//both arrays are size len
int i;
bool found = false;
if (len == 0)return true;//stopping condition for recursion
else{
for (i = 0; i < len && !found; i++)//linear search
if (A1[len - 1] == A2[i]){
overwrite(A2, len, i);//this function shifts back the whole array
found = true;
}
if (found == false) return false;
else foo(A1, A2, len - 1);
}
}
Sample i/o:
A1: 3 2 1
A2: 1 2 3
True
A1: 3 2 3
A2: 1 2 3
False
A solution could be:
find what is the maximum value M in in A1 and how many times it appears
check if it's the same for A2, including the count
find what is the maximum value M1 among all values smaller than M and how many times is present in A1
check if it's the same for A2, including the count
find what is the maximum value M2 among all values smaller than M1 and how many times is present in A1
check if it's the same for A2, including the count
repeat this way until the counter for A1 and A2 is zero or is different
in code:
bool checkSame(int *A1, int *A2, int len) {
struct Same {
static bool check(int *A1, int *A2, int len, int limit) {
int index1=-1, count1=0;
for (int i=0; i<len; i++) {
if (A1[i] <= limit) {
if (index1==-1 || A1[i] > A1[index1]) {
index1 = i;
count1 = 1;
} else if (A1[i] == A1[index1]) {
count1++;
}
}
}
int index2=-1, count2=0;
for (int i=0; i<len; i++) {
if (A2[i] <= limit) {
if (index2==-1 || A2[i] > A2[index2]) {
index2 = i;
count2 = 1;
} else if (A2[i] == A2[index2]) {
count2++;
}
}
}
if (index1 == -1 && index2 == -1) return true;
if (count1 != count2 || count1 == 0 ||
A1[index1] != A2[index2]) return false;
return check(A1, A2, len, A1[index1]-1);
}
};
return Same::check(A1, A2, len, INT_MAX);
}
This algorithm is O(n^2) in time (worst case: arrays are identical and all values unique) and requires constant space if the compiler supports tail call optimization.
The following is a chart for the time needed in ms from 0 to 3000 elements on my PC.
Note that however all this is not a decent solution for the problem but just an exercise in futility. A real solution of course would need more context as there are different criteria for optimality, but I'd probably go for a closed hash table... adding elements while processing A1 and removing elements processing A2 (the removal will fail at some point if and only if the arrays are different):
bool checkSame2(int *A1, int *A2, int len) {
std::vector<int> ht(len, -1), next(len, -1);
for (int i=0; i<len; i++) {
int k = (unsigned)A1[i]*69069 % len;
next[i] = ht[k]; ht[k] = i;
}
for (int i=0; i<len; i++) {
int k = (unsigned)A2[i]*69069 % len;
int prev=-1,p=ht[k];
while (p!=-1 && A1[p] != A2[i]) {
prev = p; p = next[p];
}
if (p == -1) return false;
if (prev == -1) ht[k] = next[p]; else next[prev] = next[p];
}
return true;
}
The execution time for this solution is the purple line touching the N axis in the previous chart (hard to tell with this scale but it's linear + noise, as expected).
Just out of curiosity I also tried what would be the solution if "optimal" means just getting something working that is not hideous:
bool checkSame3(int *A1, int *A2, int len) {
std::map<int, int> counts;
for (int i=0; i<len; i++) counts[A1[i]]++;
for (int i=0; i<len; i++) {
if (--counts[A2[i]] < 0) return false;
}
return true;
}
and this is, unsurprisingly, about 30-40 times slower than the hand-coded hash table version on my PC (but of course still much faster than the recursive version).
Here is a solution that works given all your requirements. It rearranges the arrays, and then un-rearranges them. It uses recursion, uses no additional arrays, and does not change the function signature.
bool foo(int A1[], int A2[], int len){
int i;
if (len == 0){
return true;
} else {
for (i = len - 1; i >= 0; i--){
if (A1[len - 1] == A2[i]){
A2[i] = A2[len - 1];
A2[len - 1] = A1[len - 1];
bool result = foo(A1, A2, len - 1);
A2[len - 1] = A2[i];
A2[i] = A1[len - 1];
return result;
}
}
return false;
}
}
If you are allowed to temporarily change the arrays, provided that you restore them before the last recursive call has returned, you can swap the matching element in A2 with the element at index len - 1 before the recursive call, and swap them back afterwards. Since the recursive call will only look at the index range 0 through len - 2, the matching element will not be considered.
I am trying to complete Project Euler Problem 14 in c++ and I am honestly stuck. Right now when I run the problem it gets stuck at So Far: the number with the highest count: 113370 with the count of 155
So Far: the number with the highest count but when I try changing the i value to over 113371 it works. What is going on??
The question is:
The following iterative sequence is defined for the set of positive
integers: n → n/2 (n is even) n → 3n + 1 (n is odd)
Using the rule above and starting with 13, we generate the following
sequence:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 It can be seen that this
sequence (starting at 13 and finishing at 1) contains 10 terms.
Although it has not been proved yet (Collatz Problem), it is
thought that all starting numbers finish at 1. Which starting number,
under one million, produces the longest chain?
#include<stdio.h>
int main() {
int limit = 1000000;
int highNum, number, i;
int highCount = 0;
int count = 0;
for( number = 13; number <= 1000000; number++ )
{
i = number;
while( i != 1 ) {
if (( i % 2 ) != 0 ) {
i = ( i * 3 ) + 1;
count++;
}
else {
count++;
i /= 2;
}
}
count++;
printf( "So Far: the number with the highest count: %d with the count of %d\n",
number, count );
if( highCount < count ) {
highCount = count;
highNum = number;
}
count = 0;
//break;
}
printf( "The number with the highest count: %d with the count of %d\n",
highNum, highCount );
}
You are getting integer overflow. Update your code like this and see it yourself:
if (( i % 2 ) != 0 ) {
int prevI = i;
i = ( i * 3 ) + 1;
if (i < prevI) {
printf("oops, i < prevI: %d\n", i);
return 0;
}
count++;
}
You should change the type of i to long long or unsigned long long to prevent the overflow.
(And yes, cache the intermediate results)
Remember all intermediate results (up to some suitably high number).
Also, use a big-enough type:
#include <stdio.h>
static int collatz[4000000];
unsigned long long collatzmax;
int comp(unsigned long long i) {
if(i>=sizeof collatz/sizeof*collatz) {
if(i>collatzmax)
collatzmax = i;
return 1 + comp(i&1 ? 3*i+1 : i/2);
}
if(!collatz[i])
collatz[i] = 1 + comp(i&1 ? 3*i+1 : i/2);
return collatz[i];
}
int main() {
collatz[1] = 1;
int highNumber= 1, highCount = 1, c;
for(int i = 2; i < 1000000; i++)
if((c = comp(i)) > highCount) {
highCount = c;
highNumber = i;
}
printf( "The number with the highest count: %d with the count of %d\n",
highNumber, highCount );
printf( "Highest intermediary number: %llu\n", collatzmax);
}
On coliru: http://coliru.stacked-crooked.com/a/773bd8c5f4e7d5a9
Variant with smaller runtime: http://coliru.stacked-crooked.com/a/2132cb74e4605d5f
The number with the highest count: 837799 with the count of 525
Highest intermediary number: 56991483520
BTW: The highest intermediary encountered needs 36 bit to represent as an unsigned number.
With your algorithm, you compute several time identical series.
you may cache result for previous numbers and reuse them.
Something like:
void compute(std::map<std::uint64_t, int>& counts, std::uint64_t i)
{
std::vector<std::uint64_t> series;
while (counts[i] == 0) {
series.push_back(i);
if ((i % 2) != 0) {
i = (i * 3) + 1;
} else {
i /= 2;
}
}
int count = counts[i];
for (auto it = series.rbegin(); it != series.rend(); ++it)
{
counts[*it] = ++count;
}
}
int main()
{
const std::uint64_t limit = 1000000;
std::map<std::uint64_t, int> counts;
counts[1] = 1;
for (std::size_t i = 2; i != limit; ++i) {
compute(counts, i);
}
auto it = std::max_element(counts.begin(), counts.end(),
[](const std::pair<std::uint64_t, int>& lhs, const std::pair<std::uint64_t, int>& rhs)
{
return lhs.second < rhs.second;
});
std::cout << it->first << ":" << it->second << std::endl;
std::cout << limit-1 << ":" << counts[limit-1] << std::endl;
}
Demo (10 seconds)
Don't recompute the same intermediate results over and over!
Given
typedef std::uint64_t num; // largest reliable built-in unsigned integer type
num collatz(num x)
{
return (x & 1) ? (3*x + 1) : (x/2);
}
Then the value of collatz(x) only depends on x, not on when you call it. (In other words, collatz is a pure function.) As a consequence, you can memoize the values of collatz(x) for different values of x. For this purpose, you could use a std::map<num, num> or a std::unordered_map<num, num>.
For reference, here is the complete solution.
And here it is on Coliru, with timing (2.6 secs).
I am trying to compare char one by one. I am emulating the strcmp function from an assignment from class. Here is what I cam up with. Unfortunately I get 0 all the time because all the chars match until it gets to the last one. I assume its only checking the first char and stops. I added i++ to more to the next char but i don't think its working.
strComp("abc", "abcd");
int strComp(char a[], char b[]) {
int i = 0;
if (strLen(a) == strLen(b)) {
while (a[i] != NULL && b[i] != NULL) {
if (a[i] == b[i]) {
return 0;
} else if(a[i] > b[i]) {
return 1;
} else {
return -1;
}
}
i++;
} else if (strLen(a) > strLen(b)) {
return 1;
} else {
return -1;
}
}
Note that
NULL is different from '\0'
char[] really decays into a char*
in C/C++ anything that can be const shall be declared const
the use of strlen in a basic function like this is inefficient
Here is a very fast solution:
inline int compare(char const* const a, char const* const b)
{
/* Return -1 less than, 0 equal, 1 greater than */
if (!a[0] && b[0])
return -1;
else if (a[0] && !b[0])
return 1;
register int i = 0;
for (; a[i] && b[i]; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
#if 1 /* this addition makes this code work like std::strcmp */
if (!a[i] && b[i])
return -1;
else if (a[i] && !b[i])
return 1;
#endif
return 0;
}
This one I coded more that 20 years ago as a prototype for a 386 assembler routine. For a case-insensitive string-compare #include <locale> and modify the for-loop:
.
.
for (; a[i] && b[i]; i++) {
if (std::toupper(a[i]) < std::toupper(b[i]))
return -1;
if (std::toupper(a[i]) > std::toupper(b[i]))
return 1;
}
Put
++i;
inside the while loop
just 2 lines above...
You can detect a mismatch as soon as you see two characters that are different -- but you can't detect a match until you've reached the end of the string, and the characters are still identical.
At least in my opinion, most attempts at this get the basic idea sort of backwards, trying to compare characters immediately (with some special-casing for one or both strings being empty). Instead, it's usually best to start by just skipping non-zero bytes that are equal. Then, you're either at the end of (at least one) string, or else you've found a mismatch between bytes in the two strings. Either way, at that point you can sort out what's going on, and return the correct value.
int cmp_str(char const *a, char const *b) {
while (*a && *a == *b) {
++a;
++b;
}
if (*b < *a)
return 1;
if (*b > *a)
return -1;
return 0;
}
This keeps the loop very simple, with very few conditions, so it can execute quickly. All the more complex comparisons to figure out the actual ordering happen outside the loop where they happen only once, and have almost no effect on speed.
I should probably add one warning: this does not make any attempt at dealing with international characters correctly. To do that, you just about need to add collating tables that define the relative order of characters because (at least in many code pages) the values of characters don't correspond to the order in which the characters should be sorted.
For what it's worth, here's a quick test comparing the results and speed from this to Andreas's compare and the strcmp in the standard library:
int cmp_str(char const *a, char const *b) {
while (*a && *a == *b) {
++a;
++b;
}
if (*b < *a)
return 1;
if (*b > *a)
return -1;
return 0;
}
inline int compare(char const* const a, char const* const b)
{
/* Return -1 less than, 0 equal, 1 greater than */
if (!a[0] && b[0])
return -1;
else if (a[0] && !b[0])
return 1;
register int i = 0;
for (; a[i] && b[i]; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
#if 1 /* this addition makes this code work like std::strcmp */
if (!a[i] && b[i])
return -1;
else if (a[i] && !b[i])
return 1;
#endif
return 0;
}
#ifdef TEST
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
int main(){
char *s1 [] = { "", "a", "one", "two", "three", "one", "final" };
char *s2 [] = { "x", "b", "uno", "deux", "three", "oneone", "" };
for (int i = 0; i < 7; i++) {
printf("%d\t", cmp_str(s1[i], s2[i]));
printf("%d\t", compare(s1[i], s2[i]));
printf("%d\n", strcmp(s1[i], s2[i]));
}
// Test a long string:
static const int size = 5 * 1024 * 1024;
static char s3[size];
for (int i = 0; i < size - 1; i++)
s3[i] = (rand() % 254) + 1;
s3[size - 1] = '\0';
static char s4[size];
strcpy(s4, s3);
s3[size - 5] = (s3[size - 5] + 4) % 255;
clock_t start = clock();
int val1 = cmp_str(s3, s4);
clock_t t1 = clock() - start;
start = clock();
int val2 = compare(s3, s4);
clock_t t2 = clock() - start;
start = clock();
int val3 = strcmp(s3, s4);
clock_t t3 = clock() - start;
double v1 = (double) t1 / CLOCKS_PER_SEC;
double v2 = (double) t2 / CLOCKS_PER_SEC;
double v3 = (double) t3 / CLOCKS_PER_SEC;
printf("Jerry: %d, %f\nAndreas: %d, %f\nstdlib: %d, %f\n", val1, v1, val2, v2, val3, v3);
}
#endif
Results:
-1 -1 -1
-1 -1 -1
-1 -1 -1
1 1 1
0 0 0
-1 -1 -1
1 1 1
Jerry: 1, 0.007000
Andreas: 1, 0.010000
stdlib: 1, 0.007000
Since Andreas has corrected his code, all three produce identical results for all the tests, but this version and the standard library do so about 30% faster than Andreas's versions. That does vary somewhat with the compiler though. With VC++, my code almost matches the code in the standard library (but if I use a huge string, like 200 megabytes, the version in the standard library is measurably better. With g++, the code in the standard library seems to be a little slower than the code in the VC++ standard library, but the result it generates for either Andreas's code or my code is quite a bit worse than VC++ produces for them. On a 200 megabyte string, I get these results with VC++:
Jerry: 1, 0.288000
Andreas: 1, 0.463000
stdlib: 1, 0.256000
...but with g++ (MinGW), I get results like this:
Jerry: 1, 0.419000
Andreas: 1, 0.523000
stdlib: 1, 0.268000
Although the ranking remains the same either way, the difference in speed between the standard library and my code is much larger with g++ than with VC++.
I have to say two things about your code:
i++ needs to go inside loop, but you should use ++i, depending on compiler i++ may be slower then ++i.
It is enough while (a[i]) instead of while (a[i] != NULL && b[i] != NULL), because a and b lengths are equal.
Its just because you are returning too early. Once you execute a return in a function the control go backs to where it was invoked.
In this case you are returning in a while loop which is a logical error.Lets take the case here.First it will compare a[0] and b[0] and it will return in all three cases according to your code.. ie a[0]b[0] return 1 and else return 0...
you have to change the whole function.I will edit your function according to need please wait
int strComp(char a[], char b[]) {
int i = 0;
if (strLen(a) == strLen(b)) {
while (a[i] != NULL && b[i] != NULL) {
if (a[i] == b[i]) {
return 0;
} else if(a[i] > b[i]) {
return 1;
} else {
return -1;
}
}
i++;
} else if (strLen(a) > strLen(b)) {
return 1;
} else {
return -1;
}
}
EDITED CODE(PS:please check i havent tried):
int strComp(char a[], char b[])
{
int i = 0;
while (a[i]!='\0'&&b[i]!='\0')
{
if(a[i] > b[i])
{
return 1;
}
else if (a[i] < b[i])
{
return -1;
}
i++; //place i++ here
}
if(a[i]==b[i])
return 0; //if string are equal
if(a[i]=='\0')
return -1;
else
return 1;
}
I'm trying to write a code that returns 1s and 0s instead of true or false. But this doesn't seem to be right.
int Short_Vector::operator==(const Short_Vector& obj){
if(a == obj.a && b == obj.b && c == obj.c && d == obj.d){
return 1;
}else{
return 0;
}
}
So it should return a value for each variable.
I also tried this:
int Short_Vector::operator==(const Short_Vector& obj){
int a_tf, b_tf, c_tf, d_tf;
if(a == obj.a){
a_tf = 1;
}else{
a_tf = 0;
}
if(b == obj.b){
b_tf = 1;
}else{
b_tf = 0;
}
if(c == obj.c){
c_tf = 1;
}else{
c_tf = 0;
}
if(d == obj.d){
d_tf = 1;
}else{
d_tf = 0;
}
return(a_tf, b_tf, c_tf, d_tf)
}
But I got an error about the commas being an operator.
EDIT
Getting the error: error: conversion from 'int' to non-scalar type 'Short_Vector.
I'm trying to represent a vector that looks like this [9,1,5,5].
Then i'll say
`Short_Vector a(2, 6, 9, 4);
Short_Vector b(3, 8, 7, 6);
Short_Vector c = a == b;
cout<<c;`
Output is then: [0,0,0,0]
The second method can't work because the return type is an 'int' and '(a_tf, b_tf, c_tf, d_tf)' is not an int but 4 ints separated by commas.
Since you want to return 4 booleans you could do the following:
int Short_Vector::operator==(const Short_Vector& obj)
{
//...
return (a_tf) | (b_tf << 1) | (c_tf << 2) | (d_tf << 3);
}
//the caller would do the follwoing:
int result = (MyObject1 == MyObject2);
if(result & (1 << 1) //b_tf is set to 1;
{
}
if(result & (1 << 3) //d_tf is set to 1;
{
}
You can use std::bitset to set a bit for equality of each member
std::bitset<4> Short_Vector::operator==(const Short_Vector& obj){
std::bitset<4> r;
r[0] = (a == obj.a);
r[1] = (b == obj.b);
r[2] = (c == obj.c);
r[3] = (d == obj.d);
return r;
}
And you can use it like
Short_Vector a(1,2,3,4);
Short_Vector b(1,0,3,4);
std::bitset<4> res = (a==b);
std::cout << res;
Should give you
1011
std::bitset is good because it provides convenient methods like all any and none (and many more). So that you can check aggregate values with ease.
If you want to have the result as a Short_Vector, try this:
Short_Vector Short_Vector::operator==(const Short_Vector& obj) {
return Short_Vector(
a == obj.a,
b == obj.b,
c == obj.c,
d == obj.d
);
}
The comma operator won't work the way you presumed. It will actually evaluate each of its operands and return the last. The compiler gave you a warning about this little misconception.
One alternative is to set each bit containing the numeric true/false equivalent of your boolean expressions:
unsigned int n = 0;
n |= (a == obj.a) << 0;
n |= (b == obj.b) << 1;
n |= (c == obj.c) << 2;
n |= (d == obj.d) << 3;
return n;
You can use a smaller datatype like char or you can use std::bitset.
If you must use an int as a return type, you could use the left shift operator and do something like:
int result = 0;
result += a_tf << 3; //Shifts the bit 3 places to the left.
result += b_tf << 2; //Shifts the bit 2 places to the left.
result += c_tf << 1; //Shifts the bit 1 place to the left.
result += d_tf; //Puts d_tf as bit 0
return result;
And to get each one back out use the bit-wise and:
result = obj1 == obj2; //Where obj1 and 2 are your compared objects
int a_tf = (result >> 3) & 1;
int b_tf = (result >> 2) & 1;
int c_tf = (result >> 1) & 1;
int d_tf = result & 1;
Though I have to say Named's solution using a bitset is more easily understood, and inserting/retrieving a single value is much easier that way.