Range checking using bitwise operators in C - bit-manipulation

I am working on this method, but I am restricted to using ONLY these operators: <<, >>, !, ~, &, ^ and |
I want to do above range checking using bitwise operator, is it possible in a one-line statement?
void OnNotifyCycleStateChanged(int cycleState)
{
// if cycleState is = 405;
if(cycleState >= 400 && cycleState <=7936) // range check
{
// do work ....
}
}
Example:
bool b1 = (cycleState & 0b1111100000000); // 0b1111100000000 = 7936
Is this the right way to do that?

bool b1 = CheckCycleStateWithinRange(cycleState, 0b110010000, 0b1111100000000); // Note *: 0b110010000 = 400 and 0b1111100000000 = 7936
bool CheckCycleStateWithinRange(int cycleState, int minRange, int maxRange) const
{
return ((IsGreaterThanEqual(cycleState, minRange) && IsLessThanEqual(cycleState, maxRange)) ? true : false );
}
int IsGreaterThanEqual(int cycleState, int limit) const
{
return ((limit + (~cycleState + 1)) >> 31 & 1) | (!(cycleState ^ limit));
}
int IsLessThanEqual(int cycleState, int limit) const
{
return !((limit + (~cycleState + 1)) >> 31 & 1) | (!(cycleState ^ limit));
}

Related

Making uint128 library and can't, find out what function is messing up

I'm making a class I think I have it mostly working correctly, but the division has stumped me. I have the part that I'm working on in the main I got it off of here. Unfortunately, I can't get the division code to work with my class. It works fine with uin64 and I don't know what part of my class isn't working.
I have found many bugs in my code and fixed them. I also did a thorough test of the code that the division function relies on but it still refuses to work
class uint128_t {
public:
unsigned long long int data[2];
uint128_t() {
data[1] = 0;
data[0] = 0;
}
uint128_t operator~() {
uint128_t out;
out.data[0] = ~data[0];
out.data[1] = ~data[1];
return out;
}
uint128_t operator+(const uint128_t& b) {
uint128_t out;
out.data[1] = data[1] + b.data[1];
out.data[0] = data[0] + b.data[0];
if (b.data[0] > (UINT8_MAX - data[0]))out.data[1]++;
return out;
}
uint128_t operator+(const unsigned long long int& b) {
uint128_t out;
out.data[1] = data[1];
out.data[0] = data[0] + b;
if (b > (UINT64_MAX - data[0]))out.data[1]++;
return out;
}
uint128_t operator-(const uint128_t& b) {
uint128_t out;
out.data[1] = data[1] + ~b.data[1];
out.data[0] = data[0] + ~b.data[0];
if (b.data[0] > (UINT8_MAX - data[0]))out.data[1]++;
out.data[0]++;
out.data[1]++;
return out;
}
bool operator<(const uint128_t& b) {
if (data[1] == b.data[1]) {
return (data[0] < b.data[0]) ? true : false;
}
else return (data[1] < b.data[1]) ? true : false;
}
bool operator>=(const uint128_t& b) {
if (data[1] == b.data[1]) {
return (data[0] >= b.data[0]) ? true : false;
}
else return (data[1] > b.data[1]) ? true : false;
}
uint128_t &operator=(const int& b) {
data[1] = 0;
data[0] = b;
return *this;
}
uint128_t& operator=(const uint128_t& b) {
data[1] = b.data[1];
data[0] = b.data[0];
return *this;
}
};
int main()
{
uint128_t divisor;
divisor = 2;
uint128_t quot, rem, t;
int bits_left = 128;
quot = 128;
rem = 0;
do {
// (rem:quot) << 1
t = quot;
quot = quot + quot;
rem = rem + rem + (quot < t);
if (rem >= divisor) {
rem = rem - divisor;
quot = quot + 1;
}
bits_left--;
} while (bits_left);
std::cout << std::bitset<64>(quot.data[1]) << std::bitset<64>(quot.data[0]) << std::endl;
}
So 128(quot)/2(divisor) = 64 but every time I run it I get some gibberish. But if I change the type from my class to uint64 it works fine
You have several places where UINT8_MAX is used when UINT64_MAX should appear instead. The operator+ is one of those cases.
uint128_t operator+(const uint128_t& b) {
uint128_t out;
out.data[1] = data[1] + b.data[1];
out.data[0] = data[0] + b.data[0];
if (b.data[0] > (UINT8_MAX - data[0]))out.data[1]++;
// ^^^^^^^ here
// should be UNIT64_MAX
return out;
}
And
uint128_t operator-(const uint128_t& b) {
uint128_t out;
out.data[1] = data[1] + ~b.data[1];
out.data[0] = data[0] + ~b.data[0];
if (b.data[0] > (UINT8_MAX - data[0]))out.data[1]++;
// ^^^^^^^ here
// should be UNIT64_MAX
out.data[0]++;
out.data[1]++;
return out;
}
Writing big-int, or int128, can be a good learning experience, but you should be aware of existing libraries that do the same, such as boost int128_t.
Also, write a set of simple unit test. Each unit test will check at most one operator at a time. Check interesting cases like adding values that almost need carry, those that barely need carry, and so on. Such tests would have found the bugs much easier.

How can i use unsigned short int and short int to subtract hugeinteger in C++?

I try my best to code something in C++.When i use unsigned int and int to subtract, that's OK. However, using the unsigned short int and short int to subtract, i have a problem. So what i need to do in my code?
Thanks a lot.
Test value:
21758612232416725117133766166700 1758612232416725117155428849047
In the beginning, i have to define
*this > op2
absolutely.
template< typename T >
HugeInteger< T > HugeInteger< T >::operator-(const HugeInteger &op2)const // subtraction operator; HugeInteger - HugeInteger
{
int size = integer.getSize();
int op2Size = op2.integer.getSize();
int differenceSize = size;
HugeInteger < T > difference(differenceSize);
difference = *this;
Vector<T>::iterator it = difference.integer.begin();
int counter = 0;
for (Vector<T>::iterator i = difference.integer.begin(), j = op2.integer.begin(); j < op2.integer.end(); i++, j++) {
if ((*i - *j - counter) < 10) {
*i -= (*j + counter);
counter = 0;
}
else {
*i += 10;
*i -= (*j + counter);
counter = 1;
}
}
while (counter == 1) {
if ((*(it + op2Size) - counter) < 10) {
*(it + op2Size) -= counter;
counter = 0;
op2Size++;
}
else {
*(it + op2Size) += 10;
*(it + op2Size) -= counter;
counter = 1;
op2Size++;
}
}
if (*this == op2) {
HugeInteger<T> zero(1);
return zero;
}
for (Vector<T>::iterator i = difference.integer.end() - 1; i > difference.integer.begin(); i--) {
if (*i == 0) {
differenceSize--;
}
else {
break;
}
}
difference.integer.resize(differenceSize);
return difference;
}
There's not enough information in the code you posted to determine what is going wrong. I suspect it has something to do with how the "short" types are being converted to a HugeInt.
Below, I show a class definition for something very similar to HugeInt. It keeps track of a value's sign, but unfortunately, it only a few members are defined, enough to demonstrate subtraction.
This class has a nutty template conversion constructor. If none of the other constructors can handle a type, it will try to convert values with that type as if they were some kind of integer value, in a size-independent manner.
main() has two example subtraction operations, both involving a short value and a "huge" value.
#include <iostream>
#include <vector>
#include <string>
// radix-10 arbitrary size integer class
template<typename T>
class HugInt {
// integer digits are stored in a Vector container
// The example uses the class Vector, derived (statically)
// from std::vector<T> in order to mimic the class from
// code in the Question. Normally, I would just use a std::vector.
class Vector : public std::vector<T> { // virtual never needed
public:
int getSize() const {
return static_cast<int>(std::vector<T>::size());
} };
// two member variables
Vector integer;
int sign;
// For encapsulation and compactness, this class uses a lot
// of inline-friend functions. If considering using your own
// inline-friends, it must always be called passing at least one
// object from the class where the function is defined.
// Otherwise, the compiler cannot find it.
// compares just the magnitude (unsigned) parts of two HugInts
// returns a>b:1, a==b:0, a<b:-1
friend int cmpMagnitude(const HugInt& lh, const HugInt& rh) {
const int lh_size = lh.integer.getSize();
const int rh_size = rh.integer.getSize();
if(lh_size != rh_size) return lh_size > rh_size ? 1 : -1;
for(int i=lh_size-1; i+1; --i) {
if(lh.integer[i] != rh.integer[i]) {
return lh.integer[i] > rh.integer[i] ? 1 : -1;
} }
return 0;
}
// subtract the magnitude of op2 from the magnitude of *this
// does not take signs into account, but
// flips sign of *this if op2 has a greater magnitude than *this
void subMagnitude(const HugInt& op2) {
const int cm = cmpMagnitude(*this, op2);
if(cm == 0) {
// magnitudes are equal, so result is zero
integer.clear();
sign = 0;
return;
}
if(cm < 0) {
// If op2's magnitude is greater than this's
// subtract this's Magnitude from op2's,
// then set this to the negated result
HugInt temp{op2};
temp.subMagnitude(*this);
integer = temp.integer;
sign = -sign;
return;
}
// perform digit-wise Magnitude subtraction
// here, this's Magnitude is always greater or
// equal to op2's
T borrow = 0;
const int min_size = op2.integer.getSize();
int i;
for(i=0; i<min_size; ++i) {
const T s = op2.integer[i] + borrow;
if(borrow = (integer[i] < s)) {
integer[i] += T(10);
}
integer[i] -= s;
}
// propagate borrow to upper words (beyond op2's size)
// i is guaranteed to stay in bounds
while(borrow) {
if(borrow = (integer[i] < 1)) {
integer[i] += T(10);
}
--integer[i++];
}
// remove zeroes at end until a nonzero
// digit is encountered or the vector is empty
while(!integer.empty() && !integer.back()) {
integer.pop_back();
}
// if the vector is empty after removing zeroes,
// the object's value is 0, fixup the sign
if(integer.empty()) sign = 0;
}
void addMagnitude(const HugInt& op2) {
std::cout << "addMagnitude called but not implemented\n";
}
// get_sign generically gets a value's sign as an int
template <typename D>
static int get_sign(const D& x) { return int(x > 0) - (x < 0); }
public:
HugInt() : sign(0) {} // Default ctor
// Conversion ctor for template type
// Handles converting from any type not handled elsewhere
// Assumes D is some kind of integer type
// To be more correct, narrow the set of types this overload will handle,
// either by replacing with overloads for specific types,
// or use <type_traits> to restrict it to integer types.
template <typename D>
HugInt(D src) : sign(get_sign(src)) {
// if src is negative, make absolute value to store magnitude in Vector
if(sign < 0) src = D(0)-src; // subtract from zero prevents warning with unsigned D
// loop gets digits from least- to most-significant
// Repeat until src is zero: get the low digit, with src (mod 10)
// then divide src by 10 to shift all digits down one place.
while(src >= 1) {
integer.push_back(T(src % D(10)));
src /= D(10);
} }
// converting floating-point values will cause an error if used with the integer modulo
// operator (%). New overloads could use fmod. But for a shorter example, do something cheesy:
HugInt(double src) : HugInt(static_cast<long long>(src)) {}
HugInt(float src) : HugInt(static_cast<long long>(src)) {}
// conversion ctor from std::string
HugInt(const std::string& str) : sign(1) {
for(auto c : str) {
switch(c) {
// for simple, short parsing logic, a '-'
// found anywhere in the parsed value will
// negate the sign. If the '-' count is even,
// the result will be positive.
case '-': sign = -sign; break;
case '+': case ' ': case '\t': break; // '+', space and tab ignored
case '0': if(integer.empty()) break; // ignore leading zeroes or fallthrough
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
integer.insert(integer.begin(), T(c - '0'));
break;
} }
if(integer.empty()) sign = 0; // fix up zero value if no digits between '1' and '9' found
}
// conversion ctor from C-String (dispatches to std::string ctor)
HugInt(const char* str) : HugInt(std::string(str)) {}
// The default behavior, using value semantics to copy the
// two data members, is correct for our copy/move ctors/assigns
HugInt(const HugInt& src) = default;
HugInt& operator = (const HugInt& src) = default;
// some "C++11" compilers refuse to default the moves
// HugInt(HugInt&& src) = default;
// HugInt& operator = (HugInt&& src) = default;
// cmp(a, b) returns 1 if a>b, 0 if a==b or -1 if a<b
friend int cmp(const HugInt& lh, const HugInt& rh) {
if(lh.sign != rh.sign) return lh.sign > rh.sign ? 1 : -1;
const int cmpmag = cmpMagnitude(lh, rh);
return lh.sign < 0 ? -cmpmag : cmpmag;
}
friend bool operator == (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == 0;
}
friend bool operator != (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != 0;
}
friend bool operator > (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == 1;
}
friend bool operator < (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) == -1;
}
friend bool operator >= (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != -1;
}
friend bool operator <= (const HugInt& lh, const HugInt& rh) {
return cmp(lh, rh) != 1;
}
// negate operator
HugInt operator - () const {
HugInt neg;
neg.integer = integer;
neg.sign = -sign;
return neg;
}
// subtract-assign operator
HugInt& operator -= (const HugInt &op2) {
if(op2.sign == 0) { // op2 is zero, do nothing
return *this;
}
if(sign == 0) { // *this is zero, set *this to negative op2
integer = op2.integer;
sign = -op2.sign;
return *this;
}
if(sign == op2.sign) { // same signs: use magnitude subtratction
subMagnitude(op2);
return *this;
}
// opposite signs here: needs magnitude addition (but not implemented)
addMagnitude(op2);
return *this;
}
friend HugInt operator - (const HugInt& lh, const HugInt& rh) {
// a - b uses the -= operator to avoid duplicate code
HugInt result{lh};
return result -= rh;
}
// overload stream output operator for HugInt values
friend std::ostream& operator << (std::ostream& os, const HugInt& hi) {
// assumes decimal output and class radix is 10
if(hi.integer.getSize() == 0) return os << '0';
if(hi.sign < 0) os << '-';
for(int i=hi.integer.getSize()-1; i+1; --i) {
os << char('0' + int(hi.integer[i]));
}
return os;
}
};
int main() {
using HugeInt = HugInt<char>;
{
HugeInt a = "21758612232416725117133766166700 1758612232416725117155428849047";
unsigned short b = 55427;
HugeInt c = a - b;
std::cout << a << " - " << b << " = \n" << c << '\n';
}
std::cout << '\n';
{
short a = 6521;
HugeInt b = 1234567;
HugeInt c = a - b;
std::cout << a << " - " << b << " = \n" << c << '\n';
}
}

How do I convert a C string to a int at compile time?

I want to be able to pass an integer or a double (or a string) as a template argument and in some instances convert the result to an integer and use it as a template argument for a type in the class.
Here's what I've tried:
template <typename MPLString>
class A
{
// the following works fine
int fun()
{
// this function should return the int in the boost mpl type passed to it
// (e.g. it might be of the form "123")
return std::stoi(boost::mpl::c_str<MPLString>::value);
}
// the following breaks because std::stoi is not constexpr
std::array<int, std::stoi(boost::mpl::c_str<MPLString>::value)> arr;
};
Can I do this somehow? I've tried std::stoi and atoi but neither are constexpr... Any ideas how this could be done (I cannot change the template parameter to take an int directly, as it might be a double).
Defining a constexpr stoi isn't too hard with regular C strings. It can be defined as follows:
constexpr bool is_digit(char c) {
return c <= '9' && c >= '0';
}
constexpr int stoi_impl(const char* str, int value = 0) {
return *str ?
is_digit(*str) ?
stoi_impl(str + 1, (*str - '0') + value * 10)
: throw "compile-time-error: not a digit"
: value;
}
constexpr int stoi(const char* str) {
return stoi_impl(str);
}
int main() {
static_assert(stoi("10") == 10, "...");
}
The throw expression is invalid when used in constant expressions so it'll trigger a compile time error rather than actually throwing.
mystoi():
#include <cstdint> // for int32_t
#include <iosfwd> // for ptrdiff_t, size_t
#include <iterator> // for size
#include <stdexcept> // for invalid_argument
#include <string_view> // for string_view
constexpr std::int32_t mystoi(std::string_view str, std::size_t* pos = nullptr) {
using namespace std::literals;
const auto numbers = "0123456789"sv;
const auto begin = str.find_first_of(numbers);
if (begin == std::string_view::npos)
throw std::invalid_argument{"stoi"};
const auto sign = begin != 0U && str[begin - 1U] == '-' ? -1 : 1;
str.remove_prefix(begin);
const auto end = str.find_first_not_of(numbers);
if (end != std::string_view::npos)
str.remove_suffix(std::size(str) - end);
auto result = 0;
auto multiplier = 1U;
for (std::ptrdiff_t i = std::size(str) - 1U; i >= 0; --i) {
auto number = str[i] - '0';
result += number * multiplier * sign;
multiplier *= 10U;
}
if (pos != nullptr) *pos = begin + std::size(str);
return result;
}
main():
int main() {
static_assert(mystoi(" 0 ") == 0);
static_assert(mystoi(" 1 ") == 1);
static_assert(mystoi("-1 ") == -1);
static_assert(mystoi(" 12 ") == 12);
static_assert(mystoi("-12 ") == -12);
static_assert(mystoi(" 123 ") == 123);
static_assert(mystoi("-123 ") == -123);
static_assert(mystoi(" 1234") == 1234);
static_assert(mystoi("-1234") == -1234);
static_assert(mystoi("2147483647") == 2147483647);
static_assert(mystoi("-2147483648") == -2147483648);
}

C++ multiplication of 2 strings representing decimal value of a number

The idea is to overload an operator * so it can multiply two strings representing decimal value of a number. The operator is part of a bigger class but that is not important. The algorithm is the same as in elementary school :)
Here's my code:
Bignumber operator* (Bignumber x, Bignumber y ){
int i, j, transfer=0, tmp, s1, s2, k;
char add[1];
string sol;
string a, b;
Bignumber v1, v2;
a=x.GetValue();
b=y.GetValue();
a.insert(0,"0");
b.insert(0,"0");
for(i=a.length()-1; i>=0; i--){
s1 = (int) a[i]-48;
for(k=a.length()-i-1; k >0 ; k--){
sol+="0";
}
for(j=b.length()-1; j >=0; j--){
s2=(int) b[j]-48;
tmp=s1*s2+transfer;
if(tmp >= 10){
transfer=tmp/10;
tmp=tmp-(10*transfer);
}
itoa(tmp, add, 10);
sol.insert(0, add);
}
v1=sol;
v2=v1+v2;
sol.erase(0);
transfer=0;
}
return v2;
}
This works fine most of the time but for some random values it doesnt work properly. like for example for 128*28 it returns 4854 instead of 3584.
Any idea what might be the problem?
operators + and = are already overloaded for the class Bignumber and they work fine.
While my first answer solves your issue (by my testing, anyway), here's an alternative implementation; I don't have your Bignumber class so I wrote a small fake one to test with:
#include <string>
#include <ios>
#include <iostream>
#include <ostream>
#include <sstream>
class Bignumber
{
static inline unsigned long long strtoull(std::string const& str)
{
unsigned long long val;
return std::istringstream(str) >> val ? val : 0uLL;
}
unsigned long long val_;
public:
Bignumber() : val_() { }
explicit Bignumber(unsigned long long const val) : val_(val) { }
explicit Bignumber(std::string const& str) : val_(strtoull(str)) { }
Bignumber& operator +=(Bignumber const rhs)
{
val_ += rhs.val_;
return *this;
}
std::string GetValue() const
{
std::ostringstream oss;
oss << val_;
return oss.str();
}
};
Bignumber operator *(Bignumber const x, Bignumber const y)
{
typedef std::string::const_reverse_iterator cr_iter_t;
std::string const& a = '0' + x.GetValue();
std::string const& b = '0' + y.GetValue();
Bignumber ret;
for (cr_iter_t a_iter = a.rbegin(), a_iter_end = a.rend(); a_iter != a_iter_end; ++a_iter)
{
unsigned transfer = 0u;
std::string sol(a.end() - a_iter.base(), '0');
for (cr_iter_t b_iter = b.rbegin(), b_iter_end = b.rend(); b_iter != b_iter_end; ++b_iter)
{
unsigned tmp = static_cast<unsigned>(*a_iter - '0') * static_cast<unsigned>(*b_iter - '0') + transfer;
if (tmp >= 10u)
{
transfer = tmp / 10u;
tmp -= transfer * 10u;
}
sol.insert(sol.begin(), static_cast<char>(tmp + '0'));
}
ret += Bignumber(sol);
}
return ret;
}
int main()
{
Bignumber const z = Bignumber(123456789uLL) * Bignumber(987654321uLL);
std::cout << std::boolalpha << (z.GetValue() == "121932631112635269") << std::endl;
}
itoa null-terminates the string it writes, so add is too small for the data being written to it, resulting in memory corruption. Change the definition of add to char add[2]; and it should work.

Compare versions as strings

Comparing version numbers as strings is not so easy...
"1.0.0.9" > "1.0.0.10", but it's not correct.
The obvious way to do it properly is to parse these strings, convert to numbers and compare as numbers.
Is there another way to do it more "elegantly"? For example, boost::string_algo...
I don't see what could be more elegant than just parsing -- but please make use of standard library facilities already in place. Assuming you don't need error checking:
void Parse(int result[4], const std::string& input)
{
std::istringstream parser(input);
parser >> result[0];
for(int idx = 1; idx < 4; idx++)
{
parser.get(); //Skip period
parser >> result[idx];
}
}
bool LessThanVersion(const std::string& a,const std::string& b)
{
int parsedA[4], parsedB[4];
Parse(parsedA, a);
Parse(parsedB, b);
return std::lexicographical_compare(parsedA, parsedA + 4, parsedB, parsedB + 4);
}
Anything more complicated is going to be harder to maintain and isn't worth your time.
I would create a version class.
Then it is simple to define the comparison operator for the version class.
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
class Version
{
// An internal utility structure just used to make the std::copy in the constructor easy to write.
struct VersionDigit
{
int value;
operator int() const {return value;}
};
friend std::istream& operator>>(std::istream& str, Version::VersionDigit& digit);
public:
Version(std::string const& versionStr)
{
// To Make processing easier in VersionDigit prepend a '.'
std::stringstream versionStream(std::string(".") + versionStr);
// Copy all parts of the version number into the version Info vector.
std::copy( std::istream_iterator<VersionDigit>(versionStream),
std::istream_iterator<VersionDigit>(),
std::back_inserter(versionInfo)
);
}
// Test if two version numbers are the same.
bool operator<(Version const& rhs) const
{
return std::lexicographical_compare(versionInfo.begin(), versionInfo.end(), rhs.versionInfo.begin(), rhs.versionInfo.end());
}
private:
std::vector<int> versionInfo;
};
// Read a single digit from the version.
std::istream& operator>>(std::istream& str, Version::VersionDigit& digit)
{
str.get();
str >> digit.value;
return str;
}
int main()
{
Version v1("10.0.0.9");
Version v2("10.0.0.10");
if (v1 < v2)
{
std::cout << "Version 1 Smaller\n";
}
else
{
std::cout << "Fail\n";
}
}
First the test code:
int main()
{
std::cout << ! ( Version("1.2") > Version("1.3") );
std::cout << ( Version("1.2") < Version("1.2.3") );
std::cout << ( Version("1.2") >= Version("1") );
std::cout << ! ( Version("1") <= Version("0.9") );
std::cout << ! ( Version("1.2.3") == Version("1.2.4") );
std::cout << ( Version("1.2.3") == Version("1.2.3") );
}
// output is 111111
Implementation:
#include <string>
#include <iostream>
// Method to compare two version strings
// v1 < v2 -> -1
// v1 == v2 -> 0
// v1 > v2 -> +1
int version_compare(std::string v1, std::string v2)
{
size_t i=0, j=0;
while( i < v1.length() || j < v2.length() )
{
int acc1=0, acc2=0;
while (i < v1.length() && v1[i] != '.') { acc1 = acc1 * 10 + (v1[i] - '0'); i++; }
while (j < v2.length() && v2[j] != '.') { acc2 = acc2 * 10 + (v2[j] - '0'); j++; }
if (acc1 < acc2) return -1;
if (acc1 > acc2) return +1;
++i;
++j;
}
return 0;
}
struct Version
{
std::string version_string;
Version( std::string v ) : version_string(v)
{ }
};
bool operator < (Version u, Version v) { return version_compare(u.version_string, v.version_string) == -1; }
bool operator > (Version u, Version v) { return version_compare(u.version_string, v.version_string) == +1; }
bool operator <= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != +1; }
bool operator >= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != -1; }
bool operator == (Version u, Version v) { return version_compare(u.version_string, v.version_string) == 0; }
https://coliru.stacked-crooked.com/a/7c74ad2cc4dca888
Here's a clean, compact C++20 solution, using the new spaceship operator <=>, and Boost's string split algorithm.
This constructs and holds a version string as a vector of numbers - useful for further processing, or can be disposed of as a temporary. This also handles version strings of different lengths, and accepts multiple separators.
The spaceship operator lets us provide results for <, > and == operators in a single function definition (although the equality has to be separately defined).
#include <compare>
#include <boost/algorithm/string.hpp>
struct version {
std::vector<size_t> data;
version() {};
version(std::string_view from_string) {
/// Construct from a string
std::vector<std::string> data_str;
boost::split(data_str, from_string, boost::is_any_of("._-"), boost::token_compress_on);
for(auto const &it : data_str) {
data.emplace_back(std::stol(it));
}
};
std::strong_ordering operator<=>(version const& rhs) const noexcept {
/// Three-way comparison operator
size_t const fields = std::min(data.size(), rhs.data.size());
// first compare all common fields
for(size_t i = 0; i != fields; ++i) {
if(data[i] == rhs.data[i]) continue;
else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
else return std::strong_ordering::greater;
}
// if we're here, all common fields are equal - check for extra fields
if(data.size() == rhs.data.size()) return std::strong_ordering::equal; // no extra fields, so both versions equal
else if(data.size() > rhs.data.size()) return std::strong_ordering::greater; // lhs has more fields - we assume it to be greater
else return std::strong_ordering::less; // rhs has more fields - we assume it to be greater
}
bool operator==(version const& rhs) const noexcept {
return std::is_eq(*this <=> rhs);
}
};
Example usage:
std::cout << (version{"1.2.3.4"} < version{"1.2.3.5"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} > version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} == version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} > version{"1.2.3"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} < version{"1.2.3.4.5"}) << std::endl; // true
int VersionParser(char* version1, char* version2) {
int a1,b1, ret;
int a = strlen(version1);
int b = strlen(version2);
if (b>a) a=b;
for (int i=0;i<a;i++) {
a1 += version1[i];
b1 += version2[i];
}
if (b1>a1) ret = 1 ; // second version is fresher
else if (b1==a1) ret=-1; // versions is equal
else ret = 0; // first version is fresher
return ret;
}