Is these C++ codes optimized for adding 2 positive big integer? - c++

I wrote a program to calculate (adding) 2 positive big integer using vector to store the numbers.
#include <cstdlib>
#include <cstdio> // sd sprintf()
#include <iostream>
#include <vector>// sd vector
typedef short TYPE;// alias
void input();
void makeArray();
void display(const std::vector<TYPE> Ar);
TYPE convertChar2T( char * ch);
void add();
static std::string num1;//store big integer as string
static std::string num2;
static std::vector<TYPE> Arr1;//store as vector
static std::vector<TYPE> Arr2;
static std::vector<TYPE> result;
int main(int argc, char** argv) {
input();
makeArray();
display(Arr1);
display(Arr2);
add();
display(result);
return 0;
}
//input 2 big integer number
void input(){
std::cout << "Enter 1st number : " ;
if (! std::getline(std::cin , num1) )
std::cerr << "Not OK\n";
std::cout << "Enter 2nd number : ";
if (! std::getline(std::cin , num2) )
std::cerr << "Not OK\n";
}
//grab into 2 arrays
void makeArray(){
for (std::size_t i = 0; i < num1.size(); i++){
char temp1[2] = { num1[i], '\0'}; //use array-of-char as it need '\0'
Arr1.push_back( convertChar2T(temp1) ); //push what is converted
}
for (std::size_t i = 0; i < num2.size(); i++){
char temp2[2] = { num2[i], '\0'};
Arr2.push_back( convertChar2T(temp2) );
}
}
//convert char -> TYPE by using sscanf()
TYPE convertChar2T( char * ch){
TYPE numb ;
sscanf( ch, "%d", &numb );//NGUOC LAI SPRINTF
return numb;
}
//display array
void display(const std::vector<TYPE> Ar){
for (std::size_t i = 0; i < Ar.size(); i++)
std::cout << Ar.at(i) << '\t';
std::cout << '\n';
}
void add(){
std::size_t i = Arr1.size(); // NEVER COMES TO ZERO ( 1 AT LEAST )
std::size_t j = Arr2.size();
//check original one and later one
//3 cases : 1 - original one , not yet processed
// 2 - original # one, not yet processed
// -1 - original # one or one, processed
//NOTE: at first only value 1 or 2 ( not process )
short check_one[2] = {
( i == 1 ) ? 1 : 2,
( j == 1 ) ? 1 : 2,
};
bool boost = 0;
bool Arr1_isgood = true;// whether count to 1 or not
bool Arr2_isgood = true;// good -> not yet 1
short temp_result = 0;//temporary result to push into vector
while ( Arr1_isgood || Arr2_isgood ){// while not all comes to 1
// i == j : 2 cases
// 1st: both 1 now - 3 cases
// 1.1 #1+not process original and processed
// 1.2 processed and #1+not processed
// 1.3 both 1 original + not processed
// 2nd: both # 1
if ( i == j ) {
if ( check_one[0] == 2 && check_one[1] == -1 ){//#1+not process original and processed
temp_result = Arr1[i-1] + boost;
check_one[0] == -1;
}
else if ( check_one[0] == -1 && check_one[1] == 2 ){//processed and #1+not processed
temp_result = Arr2[j-1] + boost;
check_one[1] = -1;
}
else//both 1 original + not processed OR both # 1
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
//check result >= 10 or < 10
if ( temp_result >= 10 ){
temp_result = temp_result - 10 ;
boost = 1;
}
else
boost = 0;
//result.begin() return iterator at beginning
result.insert( result.begin() ,temp_result );
//update info
if ( i == j && i == 1){ // NOTE : NEU SD i==j==1 -> sai (vi luon true)
Arr1_isgood = Arr2_isgood = false;
continue;
}
else if ( i == j && i != 1){ // i == j # 1
i--;
j--;
}
}
if (i != j){
//check to set flag ( if one of two die )
if ( i == 1 && j > 1 )
Arr1_isgood = false;
else if ( i > 1 && j == 1 )
Arr2_isgood = false;
// i die && j live OR vice versa
if ( (!Arr1_isgood && Arr2_isgood) ||
(Arr1_isgood && !Arr2_isgood ) ){
if (!Arr1_isgood && Arr2_isgood ){ //1st case
if ( check_one[0] == 1 || check_one[0] == 2){//not yet processed as SET FLAG ABOVE first
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
check_one[0] = -1 ;
}
else
temp_result = Arr2[j-1] + boost;
j--;
}
else if ( Arr1_isgood && !Arr2_isgood ){ //2nd case
if ( check_one[1] == 1 || check_one[1] == 2 ){//not yet processed as SET FLAG ABOVE first
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
check_one[1] = -1 ;
}
else
temp_result = Arr1[i-1] + boost;
i--;
}
}
else {// both is good
temp_result = Arr1[i-1] + Arr2[j-1] + boost;
i--;
j--;
}
//check result >= 10 or < 10
if (temp_result >= 10) {
temp_result -= 10;
boost = 1;
} else
boost = 0;
result.insert( result.begin() ,temp_result );
}
}
//insert boost (if any exists)
if (boost == 1)
result.insert( result.begin(), boost);
}
I'm torn between the use of "Arr1_isgood" bool variable and the check_one variable, it seems that they can be combined into one variable ? I tried to do it and it takes a lot of time without correct result.
Can the digit be store in some kind of smaller data structure rather than "short" type ? as "short" takes more than needed bits.
Another thing is : it seems that std::size_t only reach up to 4 billion in size, as when size_t reach 1, I decreased it several times and it comes to 4 billion ? Isn't it?
I wonder if these codes somehow can be optimized more?

If you want to manipulate big integers, you should use a big-integer library, e.g. GMP.

In your machine has 32-bit ints, suppose you represent each number (unsigned) as an array of 31-bit signed ints, starting from the least significant.
Then maybe you could do something like this:
// do c = a + b
int a[n], b[n], c[n];
int carry = 0;
for (i = 0; i < n; i++){
// do the addition with carry
c[i] = a[i] + b[i] + carry;
// if the addition carried into the sign bit
carry = (c[i] < 0);
// detect it and remove it from the sum
if (carry){
c[i] &= 0x7fffffff;
}
}
Then you could figure out how to handle negatives.

Related

Conver BCD Strings to Decimal

I am looking for better ways to optimize this function for better performance, speed its targeted towards embedded device. i welcome any pointers, suggestion thanks
function converts string BCD to Decimal
int ConvertBCDToDecimal(const std::string& str, int splitLength)
{
int NumSubstrings = str.length() / splitLength;
std::vector<std::string> ret;
int newvalue;
for (auto i = 0; i < NumSubstrings; i++)
{
ret.push_back(str.substr(i * splitLength, splitLength));
}
// If there are leftover characters, create a shorter item at the end.
if (str.length() % splitLength != 0)
{
ret.push_back(str.substr(splitLength * NumSubstrings));
}
string temp;
for (int i=0; i<(int)ret.size(); i++)
{
temp +=ReverseBCDFormat(ret[i]);
}
return newvalue =std::stoi(temp);
}
string ReverseBCDFormat(string num)
{
if( num == "0000")
{
return "0";
}
else if( num == "0001")
{
return "1";
}
else if( num == "0010")
{
return "2";
}
else if( num == "0011")
{
return "3";
}
else if( num == "0100")
{
return "4";
}
else if( num == "0101")
{
return "5";
}
else if( num == "0110")
{
return "6";
}
else if( num == "0111")
{
return "7";
}
else if( num == "1000")
{
return "8";
}
else if( num == "1001")
{
return "9";
}
else
{
return "0";
}
}
Update
this is what i plan to get, for a BCD Value::0010000000000000 Decimal Result 2000
BCD is a method of encoding decimal numbers, two to a byte.
For instance 0x12345678 is the BCD representation of the decimal number 12345678. But, that doesn't seem to be what you're processing. So, I'm not sure you mean BCD when you say BCD.
As for the code, you could speed it up quite a bit by iterating over each substring and directly calculating the value. At a minimum, change ReverseBCDFormat to return an integer instead of a string and calculate the string on the fly:
temp = temp * 10 + ReverseBCDFormat(...)
Something like that.
What you call BCD is not actually BCD.
With that out of the way, you can do this:
int ConvertBCDToDecimal(const std::string& str, int splitLength)
{
int ret = 0;
for (unsigned i = 0, n = unsigned(str.size()); i < n; )
{
int v = 0;
for (unsigned j = 0; j < splitLength && i < n; ++j, ++i)
v = 2*v + ('1' == str[i] ? 1 : 0); // or 2*v + (str[i]-'0')
ret = 10*ret + v;
}
return ret;
}
Get rid of all the useless vector making and string copying. You don't need any of those.
Also, I think your code has a bug when processing strings with lengths that aren't a multiple of splitLength. I think your code always considers them to be zero. In fact, now that I think about it, your code won't work with any splitLength other than 4.
BTW, if you provide some sample inputs along with their expected outputs, I would be able to actually verify my code against yours (given that your definition of BCD differs from that of most people, what your code does is not exactly clear.)
as soon as you're optimizing function, here is different variant:
int ConvertBCDToDecimal(const std::string& str) {
unsigned int result = 0;
const std::string::size_type l = str.length();
for (std::string::size_type i = 0; i < l; i += 4)
result = result * 10 + ((str[i] - '0') << 3) + ((str[i + 1] - '0') << 2) + ((str[i + 2] - '0') << 1) + (str[i + 3] - '0');
return result;
}
note: you don't need splitLength argument, as you know that every digit is 4 symbols

How to convert a decimal string to binary string?

I have a decimal string like this (length < 5000):
std::string decimalString = "555";
Is there a standard way to convert this string to binary representation? Like this:
std::string binaryString = "1000101011";
Update.
This post helps me.
As the number is very large, you can use a big integer library (boost, maybe?), or write the necessary functions yourself.
If you decide to implement the functions yourself, one way is to implement the old pencil-and-paper long division method in your code, where you'll need to divide the decimal number repeatedly by 2 and accumulate the remainders in another string. May be a little cumbersome, but division by 2 should not be so hard.
Since 10 is not a power of two (or the other way round), you're out of luck. You will have to implement arithmetics in base-10. You need the following two operations:
Integer division by 2
Checking the remainder after division by 2
Both can be computed by the same algorithm.
Alternatively, you can use one of the various big integer libraries for C++, such as GNU MP or Boost.Multiprecision.
I tried to do it.. I don't think my answer is right but here is the IDEA behind what I was trying to do..
Lets say we have 2 decimals:
100 and 200..
To concatenate these, we can use the formula:
a * CalcPower(b) + b where CalcPower is defined below..
Knowing this, I tried to split the very long decimal string into chunks of 4. I convert each string to binary and store them in a vector..
Finally, I go through each string and apply the formula above to concatenate each binary string into one massive one..
I didn't get it working but here is the code.. maybe someone else see where I went wrong.. BinaryAdd, BinaryMulDec, CalcPower works perfectly fine.. the problem is actually in ToBinary
#include <iostream>
#include <bitset>
#include <limits>
#include <algorithm>
std::string BinaryAdd(std::string First, std::string Second)
{
int Carry = 0;
std::string Result;
while(Second.size() > First.size())
First.insert(0, "0");
while(First.size() > Second.size())
Second.insert(0, "0");
for (int I = First.size() - 1; I >= 0; --I)
{
int FirstBit = First[I] - 0x30;
int SecondBit = Second[I] - 0x30;
Result += static_cast<char>((FirstBit ^ SecondBit ^ Carry) + 0x30);
Carry = (FirstBit & SecondBit) | (SecondBit & Carry) | (FirstBit & Carry);
}
if (Carry)
Result += 0x31;
std::reverse(Result.begin(), Result.end());
return Result;
}
std::string BinaryMulDec(std::string value, int amount)
{
if (amount == 0)
{
for (auto &s : value)
{
s = 0x30;
}
return value;
}
std::string result = value;
for (int I = 0; I < amount - 1; ++I)
result = BinaryAdd(result, value);
return result;
}
std::int64_t CalcPowers(std::int64_t value)
{
std::int64_t t = 1;
while(t < value)
t *= 10;
return t;
}
std::string ToBinary(const std::string &value)
{
std::vector<std::string> sets;
std::vector<int> multipliers;
int Len = 0;
int Rem = value.size() % 4;
for (auto it = value.end(), jt = value.end(); it != value.begin() - 1; --it)
{
if (Len++ == 4)
{
std::string t = std::string(it, jt);
sets.push_back(std::bitset<16>(std::stoull(t)).to_string());
multipliers.push_back(CalcPowers(std::stoull(t)));
jt = it;
Len = 1;
}
}
if (Rem != 0 && Rem != value.size())
{
sets.push_back(std::bitset<16>(std::stoull(std::string(value.begin(), value.begin() + Rem))).to_string());
}
auto formula = [](std::string a, std::string b, int mul) -> std::string
{
return BinaryAdd(BinaryMulDec(a, mul), b);
};
std::reverse(sets.begin(), sets.end());
std::reverse(multipliers.begin(), multipliers.end());
std::string result = sets[0];
for (std::size_t i = 1; i < sets.size(); ++i)
{
result = formula(result, sets[i], multipliers[i]);
}
return result;
}
void ConcatenateDecimals(std::int64_t* arr, int size)
{
auto formula = [](std::int64_t a, std::int64_t b) -> std::int64_t
{
return (a * CalcPowers(b)) + b;
};
std::int64_t val = arr[0];
for (int i = 1; i < size; ++i)
{
val = formula(val, arr[i]);
}
std::cout<<val;
}
int main()
{
std::string decimal = "64497387062899840145";
//6449738706289984014 = 0101100110000010000100110010111001100010100000001000001000001110
/*
std::int64_t arr[] = {644, 9738, 7062, 8998, 4014};
ConcatenateDecimals(arr, 5);*/
std::cout<<ToBinary(decimal);
return 0;
}
I found my old code that solve sport programming task:
ai -> aj
2 <= i,j <= 36; 0 <= a <= 10^1000
time limit: 1sec
Execution time was ~0,039 in worst case. Multiplication, addition and division algorithms is very fast because of using 10^9 as numeration system, but implementation can be optimized very well I think.
source link
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define sz(x) (int((x).size()))
typedef vector<int> vi;
typedef long long llong;
int DigToNumber(char c) {
if( c <= '9' && c >= '0' )
return c-'0';
return c-'A'+10;
}
char NumberToDig(int n) {
if( n < 10 )
return '0'+n;
return n-10+'A';
}
const int base = 1000*1000*1000;
void mulint(vi& a, int b) { //a*= b
for(int i = 0, carry = 0; i < sz(a) || carry; i++) {
if( i == sz(a) )
a.push_back(0);
llong cur = carry + a[i] * 1LL * b;
a[i] = int(cur%base);
carry = int(cur/base);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
}
int divint(vi& a, int d) { // carry = a%d; a /= d; return carry;
int carry = 0;
for(int i = sz(a)-1; i >= 0; i--) {
llong cur = a[i] + carry * 1LL * base;
a[i] = int(cur/d);
carry = int(cur%d);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
return carry;
}
void add(vi& a, vi& b) { // a += b
for(int i = 0, c = 0, l = max(sz(a),sz(b)); i < l || c; i++) {
if( i == sz(a) )
a.push_back(0);
a[i] += ((i<sz(b))?b[i]:0) + c;
c = a[i] >= base;
if( c ) a[i] -= base;
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int from, to; cin >> from >> to;
string s; cin >> s;
vi res(1,0); vi m(1,1); vi tmp;
for(int i = sz(s)-1; i >= 0; i--) {
tmp.assign(m.begin(), m.end());
mulint(tmp,DigToNumber(s[i]));
add(res,tmp); mulint(m,from);
}
vi ans;
while( sz(res) > 1 || res.back() != 0 )
ans.push_back(divint(res,to));
if( sz(ans) == 0 )
ans.push_back(0);
for(int i = sz(ans)-1; i >= 0; i--)
cout << NumberToDig(ans[i]);
cout << "\n";
return 0;
}
How "from -> to" works for string "s":
accumulate Big Number (vector< int >) "res" with s[i]*from^(|s|-i-1), i = |s|-1..0
compute digits by dividing "res" by "to" until res > 0 and save them to another vector
send it to output digit-by-digit (you can use ostringstream instead)
PS I've noted that nickname of thread starter is Denis. And I think this link may be useful too.

LZ77 compression of palmdoc

I am trying to create a utility for generating palmdoc/mobipocket format ebook files, it is said that mobi uses LZ77 compression technique to compress their records, but I found that there is quite a deviation from standard LZ77, My main source of reference is Calibre ebook creator with C implementation for palmdoc
In this file, uncompress works well, but I have not been able to compress a mobi record identically similar either using other implementation or this (Calibre code doent decompress the same).
I found some differences like, (<-- my comments follow in code)
static Py_ssize_t <-- can replaced with size_t
cpalmdoc_do_compress(buffer *b, char *output) {
Py_ssize_t i = 0, j, chunk_len, dist;
unsigned int compound;
Byte c, n;
bool found;
char *head;
buffer temp;
head = output;
temp.data = (Byte *)PyMem_Malloc(sizeof(Byte)*8); temp.len = 0;
if (temp.data == NULL) return 0;
while (i < b->len) {
c = b->data[i];
//do repeats
if ( i > 10 && (b->len - i) > 10) { <-- ignores any match outside this range
found = false;
for (chunk_len = 10; chunk_len > 2; chunk_len--) {
j = cpalmdoc_rfind(b->data, i, chunk_len);
dist = i - j;
if (j < i && dist <= 2047) { <-- 2048 window size instead of 4096
found = true;
compound = (unsigned int)((dist << 3) + chunk_len-3);
*(output++) = CHAR(0x80 + (compound >> 8 ));
*(output++) = CHAR(compound & 0xFF);
i += chunk_len;
break;
}
}
if (found) continue;
}
//write single character
i++;
if (c == 32 && i < b->len) { <-- if space is encountered skip char & check for next sequence for match otherwise do this, due to this code had wrong result.
n = b->data[i];
if ( n >= 0x40 && n <= 0x7F) {
*(output++) = CHAR(n^0x80); i++; continue;
}
}
if (c == 0 || (c > 8 && c < 0x80))
*(output++) = CHAR(c);
else { // Write binary data <-- why binary data? LZ is for text encoding
j = i;
temp.data[0] = c; temp.len = 1;
while (j < b->len && temp.len < 8) {
c = b->data[j];
if (c == 0 || (c > 8 && c < 0x80)) break;
temp.data[temp.len++] = c; j++;
}
i += temp.len - 1;
*(output++) = (char)temp.len;
for (j=0; j < temp.len; j++) *(output++) = (char)temp.data[j];
}
}
PyMem_Free(temp.data);
return output - head;
}
is this implementation correct?
PalmDoc compression essentially is byte pair compression, i.e. a variant of LZ77

How should I approach a credit card number validation algorithm?

I'm writing a program to validate credit card numbers and I have to use Luhn's Algorithm. Let me say beforehand, that I have just started to learn to program (we covered loops like last week), so there a lot of things I am unfamiliar with. I am having trouble with one of my functions that checks the arithmetic. Basically, it has to double every second digit from right to left and add everything together. But if you double a number, like 5, and you get 10, then you will have to add 1+0=1 to the total sum instead of 10. That's the part I'm stuck on. How can I put that in a program?
Sample code so far:
int
doubleEvenSum(string creditCardNumber) {
int evenSum;
int countPosition;
int doublePosition;
int length;
length = creditCardNumber.length ();
countPosition = creditCardNumber.at(length - 2);
evenSum = 0;
while(countPosition>0) {
if ((2 * countPosition) < 10) {
doublePosition = 2 * countPosition;
}
else if ((2 * countPosition) > 9) {
???
}
evenSum = evenSum + doublePosition;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/*
return the Luhn (MOD10) checksum for a sequence of digits.
-1 is returned on error (a non-digit was in the sequence
*/
int mod10( char const* s)
{
int len = strlen(s);
int sum = 0;
int dbl = 0;
while (len) {
char digit;
int val;
--len;
digit = s[len];
if (!isdigit( (unsigned char) digit)) return -1; // non digit in the sequence
val = digit - '0'; // convert character to numeric value
if (dbl) {
// double the value
val *= 2;
// if the result is double-digits, add the digits together
if (val > 9) {
val = val - 10;
val = val + 1;
}
}
dbl = !dbl; // only double value every other time
sum += val;
}
return sum % 10;
}
Here is a different algorithm. I cut/pasted from a C# example; the second link discusses a number of optimization for Luhn.
Please study this example, and please run it through the debugger to study how the code behaves as it's executing. Understanding how code actually runs (as opposed to how you think it will run when you write it) is an essential skill. IMHO....
/*
* Validate credit card with Luhn Algorithm
*
* REFERENCES:
* - http://jlcoady.net/c-sharp/credit-card-validation-in-c-sharp
* - http://orb-of-knowledge.blogspot.com/2009/08/extremely-fast-luhn-function-for-c.html
*/
#include <stdio.h> // printf(), scanf(), etc
#include <string.h> // strlen (), etc
#include <ctype.h> // isdigit(), etc
#if !defined(FALSE)
#define FALSE 0
#define TRUE ~FALSE
#endif
/*
* type definitions (should go in separate header)
*/
enum CardType {
MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7
};
/*
* function prototypes (should also go in header)
*/
int luhn (int number[], int len);
bool validate (CardType cardType, char *cardNumber);
/*
* program main
*/
int
main (int argc, char *argv[])
{
char cc_number[80];
int cc_type;
for ( ;; ) {
printf ("Enter a credit card number and type (1, 2, 3, 4, 5. 6 or 7):\n");
printf (" MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7\n");
int iret = scanf ("%s %d", cc_number, &cc_type);
if (iret == 2)
break;
else
printf ("Incorrect input: please enter a valid CC# and CC type\n");
}
if (validate ((CardType)cc_type, cc_number))
printf ("Valid\n");
else
printf ("Invalid card type/number\n");
return 0;
}
/*
* validate card#
*/
bool
validate (CardType cardType, char *cardNumber)
{
// 16 or fewer digits?
int len = strlen(cardNumber);
if (strlen (cardNumber) > 16)
return false;
// number to validate
int number[16];
for(int i = 0; i < (int)strlen (cardNumber); i++) {
if(!isdigit(cardNumber[i]))
return FALSE;
number[i] = cardNumber[i] - '0';
}
// Validate based on card type, first if tests length, second tests prefix
switch(cardType) {
case MASTERCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] == 0 || number[1] > 5)
return FALSE;
break;
case BANKCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] != 6 || number[2] > 1)
return FALSE;
break;
case VISA:
if(len != 16 && len != 13)
return FALSE;
if(number[0] != 4)
return FALSE;
break;
case AMEX:
if(len != 15)
return FALSE;
if(number[0] != 3 || (number[1] != 4 && number[1] != 7))
return FALSE;
break;
case DISCOVER:
if(len != 16)
return FALSE;
if(number[0] != 6 || number[1] != 0 || number[2] != 1 || number[3] != 1)
return FALSE;
break;
case DINERS:
if(len != 14)
return FALSE;
if(number[0] != 3 || (number[1] != 0 && number[1] != 6 && number[1] != 8) || number[1] == 0 && number[2] > 5)
return FALSE;
break;
case JCB:
if(len != 16 && len != 15)
return FALSE;
if(number[0] != 3 || number[1] != 5)
return FALSE;
break;
default:
return FALSE;
}
int sum = luhn (number, len);
return (sum % 10 == 0);
}
// Use Luhn Algorithm to validate
int luhn (int number[], int len)
{
int sum = 0;
for(int i = len - 1; i >= 0; i--)
{
if(i % 2 == len % 2)
{
int n = number[i] * 2;
sum += (n / 10) + (n % 10);
}
else
sum += number[i];
}
return sum;
}
int luhnCardValidator(char cardNumbers[]) {
int sum = 0, nxtDigit, i;
for (i = 0; cardNumbers[i] != NULL_TERMINATOR ; i++) {
nxtDigit = cardNumbers[i] - START_OF_ASCII_NUMERIC;
if (i % 2 == 0)
nxtDigit = (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : nxtDigit * 2;
sum += nxtDigit;
}
return (sum % 10);
}
This:
... (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : ...
is the clever bit. If the digit is greater than 4, then the doubling will be 10 or more. In that case, you take the doubled number and subtract 10 which will give you the ones-digit then you add 1 (the tens-digit).
Just subtract 9 from the double of the number then you will equivalent of the sum of the digits.
For ex.
7= 7*2 = 14 = 1+4 = 5 OR 14-9 = 5
This is more efficient than writing code for adding both digits.

How to calculate bit transitions using bitset < >

I am new to C++. I want to calculate the no of transitions from 0 to 0, 0 to 1, 1 to 0 and 1 to 1 in a 9 bit sequence. I have written the following code;
int main {
srand((unsigned)time(0));
unsigned int x;
for (int i=0:i<=512;i++) // loop-1
{
x=rand()%512;
bitset<9>bitseq(x);
for(int j=0;j<=bitseq.size();j++) // loop-2
{
bool a= bitseq.test(j);
bool b= bitseq.test(j+1)
if ((a==0)&(b==0)==0)
{
transition0_0 = transition0_0 + 1; // transition from 0 to 0
}
else if ((a==0)&(b==1)==0)
{
transition0_1 = transition0_1 + 1;
else if ((a==1)&(b==0)==0)
{
transition1_0 = transition1_0 + 1;
else
{
transition1_1 = transition1_1 + 1;
cout<<transition0_0<<" "<<transition0_1<<endl;
cout<<transition1_0<<" "<<transition1_1<<endl;
}
}
Somebody please guide me on the following
how to save the last bit value in loop-2 to check the transition from last bit of the last bitset output to the 1st bit of the next bitset output?
If this does not work, How I can save it in vector and use iterators to check the transitions?
First of all, the loop index j is running past the end of the bitset. Indices go from 0 to bitseq.size()-1 (inclusive). If you're going to test j and j+1 the largest value j can take is bitseq.size()-2.
Second, the ==0 part that appears in your ifs is strange, you should just use
if( (a==0)&&(b==0) )
Notice the use of two &&. While a single & works for this code, I think it's better to use the operator that correctly conveys your intentions.
And then to answer your question, you can keep a "last bit" variable that is initially set to a sentinel value (indicating you're seeing the first bitseq just now) and compare it to bitseq[0] before the start of loop 2. Here's a modified version of your code that should do what you ask.
int main {
srand((unsigned)time(0));
unsigned int x;
int transition0_0 = 0,
transition0_1 = 0,
transition1_0 = 0,
transition1_1 = 0;
int prev = -1;
for (int i=0:i<=512;i++) // loop-1
{
x=rand()%512;
bitset<9> bitseq(x);
if( prev != -1 ) // don't check this on the first iteration
{
bool cur = bitseq.test(0);
if( !prev && !cur )
++transition0_0;
else if( !prev && cur )
++transition0_1;
else if( prev && !cur )
++transition1_0;
else
++transition1_1;
}
for(int j=0;j+1<bitseq.size();j++) // loop-2
{
bool a= bitseq.test(j);
bool b= bitseq.test(j+1)
if ((a==0)&&(b==0))
{
transition0_0 = transition0_0 + 1; // transition from 0 to 0
}
else if ((a==0)&&(b==1))
{
transition0_1 = transition0_1 + 1;
}
else if ((a==1)&&(b==0))
{
transition1_0 = transition1_0 + 1;
}
else
{
++transition1_1 = transition1_1 + 1;
}
} // for-2
prev = bitseq.test(bitseq.size()-1); // update prev for the next iteration
cout<<transition0_0<<" "<<transition0_1<<endl;
cout<<transition1_0<<" "<<transition1_1<<endl;
} // for-1
} // main
Would something like this be better for you? Use an array of 4 ints where [0] = 0->0, [1] = 0->1, [2] = 1->0, [3] = 1->1.
int main {
int nTransition[] = { 0,0,0,0 };
bool a,b;
unsigned int x;
int j;
srand ((unsigned)time(0));
for (int i = 0: i < 512; i++) {
x = rand () % 512;
bitset<9> bitseq(x);
if (i == 0) {
a = bitseq.test (0);
j = 1;
} else
j = 0;
for (; j < bitseq.size (); j++) {
b = bitseq.test(j);
int nPos = (a) ? ((b) ? 3 : 2) : ((b) ? 1 : 0);
nTransition[nPos]++;
a = b;
}
}
}