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.
Related
Using OpenSSL 1.1.0 is there an easier way to reduce a bignum such that the result would be modulo, which fits into an unsigned long
What I would like to do is something like the following:
char p_str[] = "489133282872437279"; // A big prime
BIGNUM *p = BN_new();
BN_dec2bn(&p, p_str); // Prime converted into bignum
BIGNUM *a = BN_new();
BN_rand_range(a, p); // Find random number from 0 to prime
// Define max modulo for data type. Note the +1! wont work
BN_ULONG m = std::numeric_limits<unsigned long>::max() + 1;
// Reduce random number in field Z_p such that it fits into unsigned long
unsigned long result = BN_mod_word(a, m);
std::cout << result << std::endl;
Other way would be to define another BIGNUM
char m_str[] = "4294967296"; // Note that this is now 2**32, which we want
BIGNUM *m_2 = BN_new();
BN_dec2bn(&m_2, m_str);
And then do the calculation as:
BN_CTX *ctx = BN_CTX_new();
BIGNUM *remainder = BN_new();
BN_nnmod(remainder, a, m_2, ctx);
This would require now to transform resulting BN remainder now back into data type.
I was wondering if there is any easier way to do such reductions, so that the remainder fits into the data type.
The way I would approach this is to convert the BIGNUM to binary bytes and then convert those binary bytes to the unsigned integer type, modulo any extra un-necessary bytes.
The documentation to BN_bn2bin() says that the returned bytes are in big-endian format.
Here's my solution (along with a minimal c++ wrapper for BIGNUM):
#include <openssl/bn.h>
#include <limits>
#include <limits>
#include <stdexcept>
#include <utility>
#include <iostream>
#include <memory>
#include <vector>
#include <cstdint>
struct bn_failure : std::runtime_error
{
using runtime_error::runtime_error;
};
struct BigNum
{
BigNum()
: bn_(BN_new())
{
if (!bn_) throw bn_failure("BN_new()");
}
BigNum(const char* str)
: BigNum()
{
if (!bn_) throw bn_failure("BN_new()");
auto len = BN_dec2bn(&bn_, str); // Prime converted into bignum
if (len == 0) throw bn_failure("BN_dec2bn()");
}
BigNum(BigNum&& other) noexcept
: bn_(other.bn_)
{
other.bn_ = nullptr;
}
BigNum& operator=(BigNum&& other) noexcept
{
auto tmp = BigNum(std::move(other));
swap(tmp);
return *this;
}
BigNum(BigNum const& other)
: bn_(BN_dup(other.bn_))
{
if (!bn_) throw bn_failure("BN_dup()");
}
BigNum& operator=(BigNum const& other)
{
if(!BN_copy(bn_, other.bn_))
throw bn_failure("BN_copy()");
return *this;
}
~BigNum() noexcept
{
if (bn_)
{
BN_free(bn_);
}
}
void swap(BigNum& other) noexcept
{
std::swap(bn_, other.bn_);
}
void randRange(const BigNum& other)
{
BN_rand_range(bn_, other.bn_);
}
friend std::ostream& operator<<(std::ostream& os, BigNum const& bn)
{
return os << bn.as_text().get();
}
struct string_free {
void operator()(char *str) const noexcept {
OPENSSL_free(str);
}
};
auto as_text() const -> std::unique_ptr<char, string_free>
{
auto p = BN_bn2dec(bn_);
return { p, string_free() };
}
auto as_bytes() const -> std::vector<std::uint8_t>
{
auto bytes = BN_num_bytes(bn_);
auto result = std::vector<std::uint8_t>(bytes);
BN_bn2bin(bn_, result.data());
return result;
}
BIGNUM* bn_;
};
template<class Type>
auto be_bytes_to_unsigned(std::vector<std::uint8_t> const& vec) -> Type
{
auto result = Type(0);
auto first = rbegin(vec);
auto last = rend(vec);
auto count = std::size_t(std::distance(first, last));
count = std::min(sizeof(Type), count);
last = std::next(first , count);
int i = 0;
while (first != last)
{
auto b = *first++;
auto v = Type(b);
v <<= (i * std::numeric_limits<std::uint8_t>::digits);
++i;
result |= v;
}
return result;
}
int main()
{
auto p = BigNum("489133282872437279");
auto b = BigNum();
b.randRange(p);
std::cout << p << std::endl << b << std::endl;
auto modval = be_bytes_to_unsigned<unsigned long>(b.as_bytes());
std::cout << modval << std::endl;
}
sample output (64 bit long ints):
489133282872437279
281503461139622433
281503461139622433
In this code I am calculating the number of unique Binary Search Trees using catlan numbers.
The answer remains correct until input value n=13 from n>=14 the answer turns out to be less by one. Eg. for n=14 my answer is 2674439 while the actual answer is 2674440.
Here is the code.
#include "stdafx.h"
#include "iostream"
using namespace std;
class Solution {
public:
double arr[20000] = {};
double fact(int n) {
if (n == 1 || n == 0)
return 1;
if (arr[n] != 0)
return arr[n];
return arr[n] = ceil(n*fact(n - 1));
}
int numTrees(int n) {
int res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
};
int main()
{
Solution s;
cout << s.numTrees(14)<<endl;
return 0;
}
One of your intermediate values, 28! requires 98 bits of precision.
A double has 52-53 bits of precision.
The surprising part isn't that there is an error at 14, but rather that there wasn't an error before 14. This is because some effort was taken with double to reduce cumulative error, and you basically got lucky.
In this case, we are doing lots of math with multiplication, and next to none with addition. Working with prime powers is a good move:
struct product {
std::map<std::size_t, std::ptrdiff_t> powers;
product& operator*=( product const& rhs ) {
for (auto&& e:rhs.powers)
powers[e.first] += e.second;
return tidy(*this);
}
product& operator/=( product const& rhs ) {
for (auto&& e:rhs.powers)
powers[e.first] -= e.second;
return tidy(*this);
}
friend product operator*( product lhs, product const& rhs ) {
lhs *= rhs;
return lhs;
}
friend product operator/( product lhs, product const& rhs ) {
lhs /= rhs;
return lhs;
}
// 1/x overload:
friend product operator~( product p ) {
for (auto& e:p.powers)
e.second = -e.second;
return p;
}
product() = default;
product(product const&) = default;
product(product &&) = default;
product& operator=(product const&) = default;
product& operator=(product &&) = default;
product( std::size_t in ); // TODO
bool is_integral() const {
for (auto& e:powers)
if (e.second < 0) return false;
return true;
}
template<class Scalar=std::size_t>
Scalar numerator() const {
Scalar r = 1;
for( auto& e: powers )
for (std::ptrdiff_t i = 0; i < e.second; ++i)
r *= e.first;
return r;
}
template<class Scalar=std::size_t>
Scalar denominator() const {
Scalar r = 1;
for( auto& e: powers )
for (std::ptrdiff_t i = 0; i > e.second; --i)
r *= e.first;
return r;
}
friend product& tidy(product& p) {
for (auto it = p.powers.begin(); it != p.powers.end();) {
if (!it->second)
it = p.powers.erase(it);
else
++it;
}
return p;
}
};
Here is a little factorial engine:
struct factorial_t {
std::vector<product> values;
factorial_t():values(2) {}
product const& operator()( std::size_t in ) {
if (values.size() > in) {
return values[in];
}
values.push_back( (*this)(in-1)*product{in} );
return values.back();
}
};
factorial_t factorial;
which is perfectly precise up to ridiculous values.
numTrees then becomes:
template<class Scalar=std::size_t>
Scalar numTrees(std::size_t n) {
auto res = factorial(2 * n) / ((factorial(n + 1))*factorial(n));
return res.numerator<Scalar>();
}
what is remaining to do is write code that prime factors a std::size_t.
struct factor_t {
std::vector<std::size_t> primes;
factor_t():primes{2,3,5,7,11,13,17} {}
bool make_primes( std::size_t up_to ) {
if ((primes.back()+2) > up_to)
return false;
bool added_prime = false;
for (std::size_t x = primes.back()+2; x < up_to; x += 2) {
bool found = false;
for (auto p:primes)
{
if (p*p > x) break;
if (x%p) continue;
found = true;
break;
}
if (found)
primes.push_back(x);
added_prime = added_prime || found;
}
return added_prime;
}
product operator()( std::size_t in ) {
product r;
for (auto&& prime:primes)
{
while (!(in%prime)) {
r.powers[prime]++;
in /= prime;
}
}
// are there more primes to apply?
if (make_primes(std::sqrt(in)))
{
r *= (*this)(in);
}
else if (in != 1)
{
// in is a prime
r.powers[in]++;
}
return r;
}
};
factor_t factor;
product::product( std::size_t in ):
product(factor(in))
{}
and bob is your uncle.
(amusingly, the product code I wrote "works" accidentally with a 0, as it factor mistakes 0 for a prime, and a product with a positive 0 factor has a .numerator() of 0. If you divide, you end up with a 0 in the denominator, and if they cancel I pretend it never happens. However, in general, don't feed the product class a 0.)
The problem is this function:
int numTrees(int n) {
int res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
Basically, by converting the double values to int you are losing some precision, and therefore cant come to the correct value. If you change it to double, the problem disappears.
Corrected function:
double numTrees(int n)
{
double res = fact(2 * n) / ((fact(n + 1))*fact(n));
return res;
}
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';
}
}
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;
}
The following string of mine tried to find difference between two strings.
But it's horribly slow as it iterate the length of string:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
int hd(string s1, string s2) {
// hd stands for "Hamming Distance"
int dif = 0;
for (unsigned i = 0; i < s1.size(); i++ ) {
string b1 = s1.substr(i,1);
string b2 = s2.substr(i,1);
if (b1 != b2) {
dif++;
}
}
return dif;
}
int main() {
string string1 = "AAAAA";
string string2 = "ATATT";
string string3 = "AAAAA";
int theHD12 = hd(string1,string2);
cout << theHD12 << endl;
int theHD13 = hd(string1,string3);
cout << theHD13 << endl;
}
Is there a fast alternative to do that?
In Perl we can have the following approach:
sub hd {
return ($_[0] ^ $_[1]) =~ tr/\001-\255//;
}
which is much2 faster than iterating the position.
I wonder what's the equivalent of it in C++?
Try to replace the for loop by:
for (unsigned i = 0; i < s1.size(); i++ ) {
if (b1[i] != b2[i]) {
dif++;
}
}
This should be a lot faster because no new strings are created.
Fun with the STL:
#include <numeric> //inner_product
#include <functional> //plus, equal_to, not2
#include <string>
#include <stdexcept>
unsigned int
hd(const std::string& s1, const std::string& s2)
{
// TODO: What should we do if s1.size() != s2.size()?
if (s1.size() != s2.size()){
throw std::invalid_argument(
"Strings passed to hd() must have the same lenght"
);
}
return std::inner_product(
s1.begin(), s1.end(), s2.begin(),
0, std::plus<unsigned int>(),
std::not2(std::equal_to<std::string::value_type>())
);
}
Use iterators:
int GetHammingDistance(const std::string &a, const std::string &b)
{
// Hamming distance is not defined for strings of different lengths.
ASSERT(a.length() == b.length());
std::string::const_iterator a_it = a.begin();
std::string::const_iterator b_it = b.begin();
std::string::const_iterator a_end = a.end();
std::string::const_iterator b_end = b.end();
int distance = 0;
while (a_it != a_end && b_it != b_end)
{
if (*a_it != *b_it) ++distance;
++a_it; ++b_it;
}
return distance;
}
Choice 1: Modify your original code to be as effecient as possable.
int hd(string const& s1, string const& s2)
{
// hd stands for "Hamming Distance"
int dif = 0;
for (std::string::size_type i = 0; i < s1.size(); i++ )
{
char b1 = s1[i];
char b2 = s2[i];
dif += (b1 != b2)?1:0;
}
return dif;
}
Second option use some of the STL algorithms to do the heavy lifting.
struct HammingFunc
{
inline int operator()(char s1,char s2)
{
return s1 == s2?0:1;
}
};
int hd(string const& s1, string const& s2)
{
int diff = std::inner_product(s1.begin(),s1.end(),
s2.begin(),
0,
std::plus<int>(),HammingFunc()
);
return diff;
}
Some obvious points that might make it faster:
Pass the strings as const references, not by value
Use the indexing operator [] to get characters, not a method call
Compile with optimization on
You use strings.
As explained here
The hunt for the fastest Hamming Distance C implementation
if you can use char* my experiements conclude that for Gcc 4.7.2 on an Intel Xeon X5650 the fastest general purpose hamming distance calculating function for small strings (char arrays) is:
// na = length of both strings
unsigned int HammingDistance(const char* a, unsigned int na, const char* b) {
unsigned int num_mismatches = 0;
while (na) {
if (*a != *b)
++num_mismatches;
--na;
++a;
++b;
}
return num_mismatches;
}
If your problem allows you to set an upper distance limit, so that you don't care for greater distances and this limit is always less than the strings' length, the above example can be furhterly optimized to:
// na = length of both strings, dist must always be < na
unsigned int HammingDistance(const char* const a, const unsigned int na, const char* const b, const unsigned int dist) {
unsigned int i = 0, num_mismatches = 0;
while(i <= dist)
{
if (a[i] != b[i])
++num_mismatches;
++i;
}
while(num_mismatches <= dist && i < na)
{
if (a[i] != b[i])
++num_mismatches;
++i;
}
return num_mismatches;
}
I am not sure if const does anything regarding speed, but i use it anyways...