I have an assignment which requires me to write a program that multiplies two large numbers that are each stored in an array of characters with the maximum length of 100. After countless efforts and debugging and multiplying 10 digit numbers step by step and by hand I have now written the following piece of messy code:
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_SIZE = 100;
int charToInt(char);
char IntToChar(int);
long long int pow10(int);
bool isNumber(char[]);
void fillWith0(char[], int);
void multiply(char[], char[], char[]);
int main(){
char first_num[MAX_SIZE + 1], second_num[MAX_SIZE + 1], product[2 * MAX_SIZE + 1];
cout << "A =\t";
cin.getline(first_num, MAX_SIZE);
cout << "B =\t";
cin.getline(second_num, MAX_SIZE);
multiply(first_num, second_num, product);
cout << "A * B = " << product << endl;
return 0;
}
int charToInt(char ch){
return ch - '0';
}
char intToChar(int i){
return i + '0';
}
long long int pow10(int pow){
int res = 1;
for (int i = 0; i < pow ; i++){
res *= 10;
}
return res;
}
bool isNumber(char input[]){
for (int i = 0; input[i] != '\0'; i++){
if (!(input[i] >= '0' && input[i] <= '9')){
return false;
}
}
return true;
}
void fillWith0(char input[], int size){
int i;
for (i = 0; i < size; i++){
input[i] = '0';
}
input[i] = '\0';
}
void multiply(char first[], char second[], char prod[]){
_strrev(first);
_strrev(second);
if (isNumber(first) && isNumber(second)){
fillWith0(prod, 2 * MAX_SIZE + 1);
int i, j, k;
long long int carry = 0;
for (i = 0; second[i] != '\0'; i++){
for (j = 0; first[j] != '\0'; j++){
long long int mult = (pow10(i) * charToInt(first[j]) * charToInt(second[i])) + carry + charToInt(prod[j]);
prod[j] = intToChar(mult % 10);
carry = mult / 10;
}
k = j;
while (carry != 0){
carry += charToInt(prod[k]);
prod[k] = intToChar(carry % 10);
carry = carry / 10;
k++;
}
}
prod[k] = '\0';
_strrev(first);
_strrev(second);
_strrev(prod);
}
}
My problem is that it does not work with numbers that have more than 10 digits (1234567891 * 1987654321 works fine but nothing with more digits than that), as the output in those cases is a set of weird characters I presume the issue is somewhere something is overflowing and causing weird issues, although I have used long long int to store the only two numeric integers in the algorithm, doing so helped me bump from 6 digits to 10 but nothing more. Is there any suggestions or possibly solutions I can implement?
P.S. : As I mentioned before this is an assignment, so using libraries and other stuff is not allowed, I've already seen this implemented using vectors but unfortunately for me, I can't use vectors here.
The core mistake is using a long long int to store the intermediate multiplied number. Instead, use another char[] so the core of your multiply becomes simply:
for (i = 0; second[i] != '\0'; i++){
char scratch[2 * MAX_SIZE + 1];
// Fill up the first i positions with 0
fillWith0(scratch, i);
// Store second[i] * first in scratch, starting at position i.
// Make sure to 0-terminate scratch.
multiplyArrWithNumber(&scratch[i], intToChar(second[i]), first);
// Add pairwise elements with carry, stop at the end of scratch
addArrays(scratch, prod);
}
So my problem is bigger but I just do not know what to do with my code. I can do what I want if I use an array works just fine but we are not using arrays yet so I have no idea how to do it. So I have to take user input as a string validate that the string is 16 characters long, all of them are digits, and most importantly I have to multiply every other or even character by 2. Then if it is a double digit add the two digit (ex. 10 1+0). Oh by the way I do not know why but every time I do i%2 == 0 I get the odd numbers. Is it because i is unsigned?
for(unsigned i = 1; i < card.length(); i++){
if (i % 2 == 1){
}
else {
}
}
return sum;
}
You could use an array of strings where each string contains a number.
Go through them checking for 2 conditions:
Double the number if it is even (i.e., i % 2 == 0)
Add the digits if the number has 2 digits (i.e., string's length is 2)
Code:
#include <iostream>
#include <iterator> using namespace std;
int TOTAL_CARDS = 16;
void printCards(string msg, string *array) {
cout<<msg<<endl;
for(int i = 0; i < TOTAL_CARDS; i++) {
cout<<"array["<<i<<"]="<<array[i]<<endl;
}
cout<<"\n"<<endl; }
int main() {
string cards[TOTAL_CARDS];
// hardcoded numbers 0 up to TOTAL_CARDS for demo purposes
for(int i = 0; i < TOTAL_CARDS; i++) {
cards[i] = to_string(i);
}
printCards("Before:", cards);
for (unsigned i = 1; i < TOTAL_CARDS; i++){
// double if even
if (i % 2 == 0){
cards[i] = to_string(stoi(cards[i]) * 2);
}
// add digits if double digit number
if (cards[i].length() == 2) {
// get each digit
string currentNum = cards[i];
int firstDigit = currentNum[0] - '0'; // char - '0' gives int
int secondDigit = currentNum[1] - '0';
// do sum and put in array
int sum = firstDigit + secondDigit;
cards[i] = to_string(sum);
}
}
printCards("After:", cards); }
Output:
Before:
array[0]=0
array[1]=1
array[2]=2
array[3]=3
array[4]=4
array[5]=5
array[6]=6
array[7]=7
array[8]=8
array[9]=9
array[10]=10
array[11]=11
array[12]=12
array[13]=13
array[14]=14
array[15]=15
After:
array[0]=0
array[1]=1
array[2]=4
array[3]=3
array[4]=8
array[5]=5
array[6]=3
array[7]=7
array[8]=7
array[9]=9
array[10]=2
array[11]=2
array[12]=6
array[13]=4
array[14]=10
array[15]=6
If you wanted to get user input for the numbers:
// get user to enter numbers
cout<<"Please enter "<<TOTAL_CARDS<<" numbers: "<<endl;
for(int i = 0; i < TOTAL_CARDS; i++) {
cin>>cards[i];
}
I found the answer to it. I first needed to create char variable named num. Convert the char to an int using chnum and then multiply.
for(unsigned i = 0; i < card.length(); i++){
if (i % 2 == 1){
num = card.at(i);
chnum = (num -'0');
add = chnum * 2;
if(add >= 10){
char ho = (add + '0');
string str(1,ho);
for (unsigned j = 0; j < str.length();j++){
char digi = str.at(j);
int chub = (digi - '0');
cout << digi;
//add = (chub) + (chub);
}
}
sum += add;
}
I'm trying to print the numbers from 1 to N in lexicographic order, but I get a failed output. for the following input 100, I get the 100, but its shifted and it doesn't match with the expected output, there is a bug in my code but I can not retrace it.
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> result;
for(int i = 1; i <= 9; i ++){
int j = 1;
while( j <= n){
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
j *= 10;
}
}
return result;
}
};
Input:
100
Output:
[1,10,11,12,13,14,15,16,17,18,19,100,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47,48,49,5,50,51,52,53,54,55,56,57,58,59,6,60,61,62,63,64,65,66,67,68,69,7,70,71,72,73,74,75,76,77,78,79,8,80,81,82,83,84,85,86,87,88,89,9,90,91,92,93,94,95,96,97,98,99]
Expected:
[1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,22,23,24,25,26,27,28,29,3,30,31,32,33,34,35,36,37,38,39,4,40,41,42,43,44,45,46,47
Think about when i=1,j=10 what will happen in
for(int m = 0; m < j ; ++ m){
if(m + j * i <= n){
result.push_back(m+j*i);
}
}
Yes,result will push_back 10(0+10*1),11(1+10*1),12(2+10*1)..
Here is a solution:
#include <iostream>
#include <vector>
#include <string>
std::vector<int> fun(int n)
{
std::vector<std::string> result;
for (int i = 1; i <= n; ++i) {
result.push_back(std::to_string(i));
}
std::sort(result.begin(),result.end());
std::vector<int> ret;
for (auto i : result) {
ret.push_back(std::stoi(i));
}
return ret;
}
int main(int argc, char *argv[])
{
std::vector<int> result = fun(100);
for (auto i : result) {
std::cout << i << ",";
}
std::cout << std::endl;
return 0;
}
You are looping through all 2 digit numbers starting with 1 before outputting the first 3 digit number, so your approach won't work.
One way to do this is to output the digits in base 11, padded out with leading spaces to the maximum number of digits, in this case 3. Output 0 as a space, 1 as 0, 2 as 1 etc. Reject any numbers that have any non-trailing spaces in this representation, or are greater than n when interpreted as a base 10 number. It should be possible to jump past multiple rejects at once, but that's an unnecessary optimization. Keep a count of the numbers you have output and stop when it reaches n. This will give you a lexicographical ordering in base 10.
Example implementation that uses O(1) space, where you don't have to generate and sort all the numbers up front before you can output the first one:
void oneToNLexicographical(int n)
{
if(n < 1) return;
// count max digits
int digits = 1, m = n, max_digit11 = 1, max_digit10 = 1;
while(m >= 10)
{
m /= 10; digits++; max_digit11 *= 11; max_digit10 *= 10;
}
int count = 0;
bool found_n = false;
// count up starting from max_digit * 2 (first valid value with no leading spaces)
for(int i = max_digit11 * 2; ; i++)
{
int val = 0, trailing_spaces = 0;
int place_val11 = max_digit11, place_val10 = max_digit10;
// bool valid_spaces = true;
for(int d = 0; d < digits; d++)
{
int base11digit = (i / place_val11) % 11;
if(base11digit == 0)
{
trailing_spaces++;
val /= 10;
}
else
{
// if we got a non-space after a space, it's invalid
// if(trailing_spaces > 0)
// {
// valid_spaces = false;
// break; // trailing spaces only
// }
val += (base11digit - 1) * place_val10;
}
place_val11 /= 11;
place_val10 /= 10;
}
// if(valid_spaces && (val <= n))
{
cout << val << ", ";
count++;
}
if(val == n)
{
found_n = true;
i += 10 - (i % 11); // skip to next number with one trailing space
}
// skip past invalid numbers:
// if there are multiple trailing spaces then the next run of numbers will have spaces in the middle - invalid
if(trailing_spaces > 1)
i += (int)pow(11, trailing_spaces - 1) - 1;
// if we have already output the max number, then all remaining numbers
// with the max number of digits will be greater than n
else if(found_n && (trailing_spaces == 1))
i += 10;
if(count == n)
break;
}
}
This skips past all invalid numbers, so it's not necessary to test valid_spaces before outputting each.
The inner loop can be removed by doing the base11 -> base 10 conversion using differences, making the algorithm O(N) - the inner while loop tends towards a constant:
int val = max_digit10;
for(int i = max_digit11 * 2; ; i++)
{
int trailing_spaces = 0, pow11 = 1, pow10 = 1;
int j = i;
while((j % 11) == 0)
{
trailing_spaces++;
pow11 *= 11;
pow10 *= 10;
j /= 11;
}
int output_val = val / pow10;
if(output_val <= n)
{
cout << output_val << ", ";
count++;
}
if(output_val == n)
found_n = true;
if(trailing_spaces > 1)
{
i += (pow11 / 11) - 1;
}
else if(found_n && (trailing_spaces == 1))
{
i += 10;
val += 10;
}
else if(trailing_spaces == 0)
val++;
if(count == n)
break;
}
Demonstration
The alternative, simpler approach is just to generate N strings from the numbers and sort them.
Maybe more general solution?
#include <vector>
#include <algorithm>
using namespace std;
// returns true is i1 < i2 according to lexical order
bool lexicalLess(int i1, int i2)
{
int base1 = 1;
int base2 = 1;
for (int c = i1/10; c > 0; c/=10) base1 *= 10;
for (int c = i2/10; c > 0; c/=10) base2 *= 10;
while (base1 > 0 && base2 > 0) {
int d1 = i1 / base1;
int d2 = i2 / base2;
if (d1 != d2) return (d1 < d2);
i1 %= base1;
i2 %= base2;
base1 /= 10;
base2 /= 10;
}
return (base1 < base2);
}
vector<int> lexicalOrder(int n) {
vector<int> result;
for (int i = 1; i <= n; ++i) result.push_back(i);
sort(result.begin(), result.end(), lexicalLess);
return result;
}
The other idea for lexicalLess(...) is to convert integers to string before comparision:
#include <vector>
#include <algorithm>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;
// returns true is i1 < i2 according to lexical order
bool lexicalLess(int i1, int i2)
{
string s1 = boost::lexical_cast<string>(i1);
string s2 = boost::lexical_cast<string>(i2);
return (s1 , s2);
}
You need Boost to run the second version.
An easy one to implement is to convert numbers to string, them sort the array of strings with std::sort in algorithm header, that sorts strings in lexicographical order, then again turn numbers to integer
Make a vector of integers you want to sort lexicographically, name it numbers.
Make an other vector and populate it strings of numbers in the first vector. name it strs.
Sort strs array.4. Convert strings of strs vector to integers and put it in vectors
List item
#include <cstdlib>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
string int_to_string(int x){
string ret;
while(x > 0){
ret.push_back('0' + x % 10);
x /= 10;
}
reverse(ret.begin(), ret.end());
return ret;
}
int main(){
vector<int> ints;
ints.push_back(1);
ints.push_back(2);
ints.push_back(100);
vector<string> strs;
for(int i = 0; i < ints.size(); i++){
strs.push_back(int_to_string((ints[i])));
}
sort(strs.begin(), strs.end());
vector<int> sorted_ints;
for(int i = 0; i < strs.size(); i++){
sorted_ints.push_back(atoi(strs[i].c_str()));
}
for(int i = 0; i < sorted_ints.size(); i++){
cout<<sorted_ints[i]<<endl;
}
}
As the numbers are unique from 1 to n, you can use a set of size n and insert all of them into it and then print them out.
set will automatically keep them sorted in lexicographical order if you store the numbers as a string.
Here is the code, short and simple:
void lexicographicalOrder(int n){
set<string> ans;
for(int i = 1; i <= n; i++)
ans.insert(to_string(i));
for(auto ele : ans)
cout <<ele <<"\n";
}
So I have to solve one USACO problem involving computing all the primes <= 100M and printing these of them which are palindromes while the restrictions are 16MB memory and 1 sec executions time. So I had to make a lot of optimisations.
Please take a look at the following block of code:
for(int i = 0; i < all.size(); ++i)
{
if(all[i] < a) continue;
else if(all[i] > b) break;
if(isPrime(all[i]))
{
char buffer[50];
//toString(all[i], buffer);
int c = all[i];
log10(2);
buffer[3] = 2;
//buffer[(int)log10(all[i])+1] = '\n';
//buffer[(int)log10(all[i])+2] = '\0';
//fputs(buffer, pFile);
}
}
Now, it executes in the satisfying 0.5 sec range, but when I change log10(2) to log10(all[i]) it skyrockets nearly to 2 seconds! For no apparent reason. I'm assigning all[i] to the variable c and it doesn't slow down the execution at all, but when I pass all[i] as parameter, it makes the code 4 times slower! Any ideas why this is happening and how I can fix it?
Whole code:
/*
ID: xxxxxxxx
PROG: pprime
LANG: C++11
*/
#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <string>
#include <cstring>
#include <algorithm>
#include <list>
#include <ctime>
#include <cstdio>
using namespace std;
typedef struct number Number;
ifstream fin("pprime.in");
ofstream fout("pprime.out");
int MAXN = 100000000;
unsigned short bits[2000000] = {};
vector<int> primes;
vector<int> all;
int a, b;
short getBit(int atPos)
{
int whichNumber = (atPos-1) / 16;
int atWhichPosInTheNumber = (atPos-1) % 16;
return ((bits[whichNumber] & (1 << atWhichPosInTheNumber)) >> atWhichPosInTheNumber);
}
void setBit(int atPos)
{
int whichNumber = (atPos-1) / 16;
int atWhichPosInTheNumber = (atPos-1) % 16;
int old = bits[whichNumber];
bits[whichNumber] = bits[whichNumber] | (1 << atWhichPosInTheNumber);
}
void calcSieve()
{
for(int i = 2; i < MAXN; ++i)
{
if(getBit(i) == 0)
{
for(int j = 2*i; j <= (MAXN); j += i)
{
setBit(j);
}
primes.push_back(i);
}
}
}
int toInt(list<short> integer)
{
int number = 0;
while(!integer.empty())
{
int current = integer.front();
integer.pop_front();
number = number * 10 + current;
}
return number;
}
void toString(int number, char buffer[])
{
int i = 0;
while(number != 0)
{
buffer[i] = number % 10 + '0';
number /= 10;
}
}
void DFS(list<short> integer, int N, int atLeast)
{
if(integer.size() > N)
{
return;
}
if(!(integer.size() > 0 && (integer.front() == 0 || integer.back() % 2 == 0)) && atLeast <= integer.size())
{
int toI = toInt(integer);
if(toI <= b) all.push_back(toInt(integer));
}
for(short i = 0; i <= 9; ++i)
{
integer.push_back(i);
integer.push_front(i);
DFS(integer, N, atLeast);
integer.pop_back();
integer.pop_front();
}
}
bool isPrime(int number)
{
for(int i = 0; i < primes.size() && number > primes[i]; ++i)
{
if(number % primes[i] == 0) return false;
}
return true;
}
int main()
{
int t = clock();
ios::sync_with_stdio(false);
fin >> a >> b;
MAXN = min(MAXN, b);
int N = (int)log10(b) + 1;
int atLeast = (int)log10(a) + 1;
for(short i = 0; i <= 9; ++i)
{
list<short> current;
current.push_back(i);
DFS(current, N, atLeast);
}
list<short> empty;
DFS(empty, N, atLeast);
sort(all.begin(), all.end());
//calcSieve
calcSieve();
//
string output = "";
int ends = clock() - t;
cout<<"Exexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
cout<<"\nsize: "<<all.size()<<endl;
FILE* pFile;
pFile = fopen("pprime.out", "w");
for(int i = 0; i < all.size(); ++i)
{
if(all[i] < a) continue;
else if(all[i] > b) break;
if(isPrime(all[i]))
{
char buffer[50];
//toString(all[i], buffer);
int c = all[i];
log10(c);
buffer[3] = 2;
//buffer[(int)log10(all[i])+1] = '\n';
//buffer[(int)log10(all[i])+2] = '\0';
//fputs(buffer, pFile);
}
}
ends = clock() - t;
cout<<"\nExexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
ends = clock() - t;
cout<<"\nExexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
fclose(pFile);
//fout<<output;
return 0;
}
I think you've done this backwards. It seems odd to generate all the possible palindromes (if that's what DFS actually does... that function confuses me) and then check which of them are prime. Especially since you have to generate the primes anyway.
The other thing is that you are doing a linear search in isPrime, which is not taking advantage of the fact that the array is sorted. Use a binary search instead.
And also, using list instead of vector for your DFS function will hurt your runtime. Try using a deque.
Now, all that said, I think that you should do this the other way around. There are a huge number of palindromes that won't be prime. What's the point in generating them? A simple stack is all you need to check if a number is a palindrome. Like this:
bool IsPalindrome( unsigned int val )
{
int digits[10];
int multiplier = 1;
int *d = digits;
// Add half of number's digits to a stack
while( multiplier < val ) {
*d++ = val % 10;
val /= 10;
multiplier *= 10;
}
// Adjust for odd-length palindrome
if( val * 10 < multiplier ) --d;
// Check remaining digits
while( val != 0 ) {
if(*(--d) != val % 10) return false;
val /= 10;
}
return true;
}
This avoids the need to call log10 at all, as well as eliminates all that palindrome generation. The sieve is pretty fast, and after that you'll only have a few thousand primes to test, most of which will not be palindromes.
Now your whole program becomes something like this:
calcSieve();
for( vector<int>::iterator it = primes.begin(); it != primes.end(); it++ ) {
if( IsPalindrome(*it) ) cout << *it << "\n";
}
One other thing to point out. Two things actually:
int MAXN = 100000000;
unsigned short bits[2000000] = {};
bits is too short to represent 100 million flags.
bits is uninitialised.
To address both these issues, try:
unsigned short bits[1 + MAXN / 16] = { 0 };
I'm trying to verify ISBN numbers in C but when I run the program I get the following error: Disallowed system call: SYS_socketcall
This is for a homework assignment in a CS class. I've done all the work so it's not like I'm asking people to do my assignment for me. I'm just wondering why I'm getting this error as I'm new to the C language; I come from a Java background as well as some web programming languages. Anyways, here's the assignment description if it'll help:
Perform a check on the characters in an ISBN to verify correctness.
The check character is computed as follows:
First, compute the sum of the first digit plus two times the second digit
plus three times the third digit, ... , plus nine times the ninth digit. The
last character is the remainder when the sum is divided by 11. If the
remainder is 10, the last character is X. For example, the sum for
the ISBN 0-8065-0959-7 is
1*0 + 2*8 + 3*0 + 4*6 + 5*5 + 6*0 + 7*9 + 8*5 + 9*9 = 249
The remainder when 249 is divided by 11 is 7, the last character in the ISBN.
The check character is used to validate an ISBN.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int checkISBN( char[] );
#define size 18L
int main() {
int i,j;
char* s[size] = {
"0-8065-0959-7",
"0-534-37964-8",
"0-618-50298-X",
"0-8065-0959-8",
"0-534-37964-9",
"0-618-50298-5",
"0-534-37964-8",
"0-618-50298-X",
"032121353X",
"0321199553",
"0201794896",
"0870495275",
"0452264464",
"0536901562",
"158901104X",
"080801076X",
"80-902734-1-6"
"158901104X" };
for( i = 0; i < size; i++){
if( checkISBN( s[i] ) == 1 )
printf("%-15s is a valid ISBN \n",s[i]);
else
printf("%-15s is NOT a valid ISBN*****\n",s[i]);
}
putchar('\n'); //write a newline
system("pause");`enter code here`
return EXIT_SUCCESS;
}
int checkISBN( char s[] )
{
int result = 0;
int i;
int n = 1;
int sum = 0;
char ch[10];
int final[10];
int sizeOfArray = strlen(s);
for(i=0; i<sizeOfArray; i++){
if(s[i] == '-'){
++i;}
if(s[strlen(s)-1] == 'X'){
s[strlen(s)-1] = 10;}
ch[i] = s[i];
}
for(i=0; i<10; i++){
final[i] = atoi(&ch[i]);}
for(i=0; i<9; i++){
sum+= final[i]*n;
++n;}
int checkCharacter = sum%11;
if(checkCharacter == final[9]){
result = 1;}
return result;}
#include <ctype.h>
int checkISBN( char s[] ) {
int i, n = 1, sum = 0, checksum;
for(i=0; s[i]; ++i){
if(s[i] == '-')
continue;
if(n<10 && isdigit(s[i]))
sum += n++*(s[i] - '0');
else if(n==10){
if(s[i] == 'X')
checksum = 10;
else if(isdigit(s[i]))
checksum = s[i] - '0';
}
}
return sum % 11 == checksum;
}
also
"80-902734-1-6", //need comma