Armstrong numbers. Fails for 153 - c++

A C++ program to compute and display all Armstrong numbers (numbers such that the sum of each of the digits raised to the power of the number of digits equals the number) between 100 and 999. The answers should be 153, 370, 371, 407. It prints all but 153.
Debugging done to see what the values of the individual digits are for i = 153.
#include <iostream>
#include <vector>
#include <math.h>
void separateDigits(int n, std::vector<int>& digits)
{
if (n>0)
{
separateDigits(n/10, digits);
digits.push_back(n%10);
}
}
int main()
{
for (int i = 100; i <= 999; i++)
{
std::vector<int> test;
separateDigits(i, test);
int powerSum = 0;
for (auto iter = test.begin(); iter != test.end(); iter++)
{
//powerSum = powerSum + pow((*iter),3);
powerSum = powerSum + (*iter)*(*iter)*(*iter);
}
if (i==powerSum)
{
std::cout << "Armstrong: " << i << std::endl;
}
}
return 0;
}

#include <stdio.h> //PROGRAM TO FIND ARMSRONG NUMBERS.
#include <math.h> //WORKS ONLY FOR THREE DIGIT NUMBERS.
int main()
{
int num, dig1, dig2, dig3;
for (num = 1; num <= 999; num++)
{
dig3 = dig2 = dig1 = 0;
dig3 = num % 10;
dig2 = ((num - dig3) % 100) / 10;
dig1 = (num - (dig3 + 10 * dig2)) / 100;
if (num == pow(dig1, 3) + pow(dig2, 3) + pow(dig3, 3))
{
printf("%d\n", num);
}
}
return 0;
}

This doesn't seem like your best option:
powerSum = powerSum + (*iter)*(*iter)*(*iter);
as you've now embedded your previous constant 3:
powerSum = powerSum + pow((*iter),3);
in an evem more obscure fashion. Why not consider a cleaner way that also supports numbers of sizes other than three digits:
unsigned digitsSize = test.size();
for (auto iter = test.begin(); iter != test.end(); iter++)
{
unsigned power = 1;
for (unsigned size = 0; size < digitsSize; size++) {
power *= *iter;
}
powerSum += power;
}
The complete code:
#include <iostream>
#include <vector>
void separateDigits(unsigned number, std::vector<unsigned>& digits)
{
while (number > 0)
{
digits.push_back(number % 10);
number /= 10;
}
}
int main()
{
std::vector<unsigned> digits;
for (unsigned number = 100; number <= 999; number++)
{
separateDigits(number, digits);
unsigned powerSum = 0, digitsSize = digits.size();
for (std::vector<unsigned>::iterator iter = digits.begin(); iter != digits.end(); iter++)
{
unsigned power = 1;
for (unsigned size = 0; size < digitsSize; size++) {
power *= *iter;
}
powerSum += power;
}
if (number == powerSum)
{
std::cout << "Armstrong: " << number << std::endl;
}
digits.clear();
}
return 0;
}
Changing the range from 100 - 999 to 1000 - 9999, no longer breaks the code, but instead produces:
> ./a.out
Armstrong: 1634
Armstrong: 8208
Armstrong: 9474
>

Related

Print prime factorization in exponential form in C++

So far I have this code. I'm trying to print prime factorization with exponents. For example, if my input is 20, the output should be 2^2, 5
#include <iostream>
#include <cmath>
using namespace std;
void get_divisors (int n);
bool prime( int n);
int main(int argc, char** argv) {
int n = 0 ;
cout << "Enter a number and press Enter: ";
cin >>n;
cout << " Number n is " << n << endl;
get_divisors(n);
cout << endl;
return 0;
}
void get_divisors(int n){
double sqrt_of_n = sqrt(n);
for (int i =2; i <= sqrt_of_n; ++i){
if (prime (i)){
if (n % i == 0){
cout << i << ", ";
get_divisors(n / i);
return;
}
}
}
cout << n;
}
bool prime (int n){
double sqrt_of_n = sqrt (n);
for (int i = 2; i <= sqrt_of_n; ++i){
if ( n % i == 0) return 0;
}
return 1;
}
I hope someone can help me with this.
You can use an std::unordered_map<int, int> to store two numbers (x and n for x^n). Basically, factorize the number normally by looping through prime numbers smaller than the number itself, dividing the number by the each prime as many times as possible, and recording each prime you divide by. Each time you divide by a prime number p, increment the counter at map[p].
I've put together a sample implementation, from some old code I had. It asks for a number and factorizes it, displaying everything in x^n.
#include <iostream>
#include <unordered_map>
#include <cmath>
bool isPrime(const int& x) {
if (x < 3 || x % 2 == 0) {
return x == 2;
} else {
for (int i = 3; i < (int) (std::pow(x, 0.5) + 2); i += 2) {
if (x % i == 0) {
return false;
}
}
return true;
}
}
std::unordered_map<int, int> prime_factorize(const int &x) {
int currentX = abs(x);
if (isPrime(currentX) || currentX < 4) {
return {{currentX, 1}};
}
std::unordered_map<int, int> primeFactors = {};
while (currentX % 2 == 0) {
if (primeFactors.find(2) != primeFactors.end()) {
primeFactors[2]++;
} else {
primeFactors[2] = 1;
}
currentX /= 2;
}
for (int i = 3; i <= currentX; i += 2) {
if (isPrime(i)) {
while (currentX % i == 0) {
if (primeFactors.find(i) != primeFactors.end()) {
primeFactors[i]++;
} else {
primeFactors[i] = 1;
}
currentX /= i;
}
}
}
return primeFactors;
}
int main() {
int x;
std::cout << "Enter a number: ";
std::cin >> x;
auto factors = prime_factorize(x);
std::cout << x << " = ";
for (auto p : factors) {
std::cout << "(" << p.first << " ^ " << p.second << ")";
}
}
Sample output:
Enter a number: 1238
1238 = (619 ^ 1)(2 ^ 1)
To begin with, avoid using namespace std at the top of your program. Second, don't use function declarations when you can put your definitions before the use of those functions (but this may be a matter of preference).
When finding primes, I'd divide the number by 2, then by 3, and so on. I can also try with 4, but I'll never be able to divide by 4 if 2 was a divisor, so non primes are automatically skipped.
This is a possible solution:
#include <iostream>
int main(void)
{
int n = 3 * 5 * 5 * 262417;
bool first = true;
int i = 2;
int count = 0;
while (i > 1) {
if (n % i == 0) {
n /= i;
++count;
}
else {
if (count > 0) {
if (!first)
std::cout << ", ";
std::cout << i;
if (count > 1)
std::cout << "^" << count;
first = false;
count = 0;
}
i++;
if (i * i > n)
i = n;
}
}
std::cout << "\n";
return 0;
}
Note the i * i > n which is an alternative to the sqrt() you are using.

How to get the longest sequence of prime numbers from an array in c++

I'm trying to get the longest(largest) sequence of consecutive prime numbers from an array..
On first test with 10 elements in the array works , but when i tried with 15 elements like: 3, 5, 7, 8, 9, 11, 13, 17, 19, 20, 23, 29, 31, 37, 41 it spit out 4, which is incorrect.
#include <iostream>
using namespace std;
int main()
{
int bar[100];
int x, j = 0;
int maxseq = 0;
int longestseqstart = 0;
cout << "How big is the array? =";
cin >> x;
for (int i = 0; i < x; i++) {
cout << "bar[" << i << "]=";
cin >> bar[i];
}
for (int i = 1; i < x - 1; i = j) {
int startseq = i;
int seq = 0;
j = i + 1;
bool prim = true;
int a = bar[i];
for (int d = 2; d <= a / 2; d++) {
if (a % d == 0) {
prim = false;
}
}
while (j < x && prim) {
seq++;
if (seq > maxseq) {
maxseq = seq;
longestseqstart = i;
}
int a = bar[j];
for (int d = 2; d <= a / 2; d++) {
if (a % d == 0) {
prim = false;
}
}
j++;
}
}
cout << "The longest sequence is: ";
cout << maxseq;
return 0;
}
I would write the program the following way
#include <iostream>
#include <iterator>
#include <algorithm>
bool is_prime( unsigned int n )
{
bool prime = n % 2 == 0 ? n == 2 : n != 1;
for ( unsigned int i = 3; prime && i <= n / i; i += 2 )
{
prime = n % i != 0;
}
return prime;
}
int main()
{
unsigned int a[] = { 3, 5, 7, 8, 9, 11, 13, 17, 19, 20, 23, 29, 31, 37, 41 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t maxseq = 0;
for ( auto current = std::find_if( a, a + N, is_prime );
current != a + N;
current = std::find_if( current, a + N, is_prime ) )
{
auto first = current;
current = std::find_if_not( current, a + N, is_prime );
size_t n = std::distance( first, current );
if ( maxseq < n ) maxseq = n;
}
std::cout << "The longest sequence is: " << maxseq << '\n';
return 0;
}
The program output is
The longest sequence is: 5
I did not use generic functions std::begin( a ) and std::end( a ) because in your program the array can contain less actual elements than the array dimension.
If you do not know yet standard C++ algorithms then the program can be defined the following way
#include <iostream>
bool is_prime( unsigned int n )
{
bool prime = n % 2 == 0 ? n == 2 : n != 1;
for ( unsigned int i = 3; prime && i <= n / i; i += 2 )
{
prime = n % i != 0;
}
return prime;
}
int main()
{
unsigned int a[] = { 3, 5, 7, 8, 9, 11, 13, 17, 19, 20, 23, 29, 31, 37, 41 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t maxseq = 0;
size_t n = 0;
for ( size_t i = 0; i < N; i++ )
{
bool prime = a[i] % 2 == 0 ? a[i] == 2 : a[i] != 1;
for ( unsigned int j = 3; prime && j <= a[i] / j; j += 2 )
{
prime = a[i] % j != 0;
}
if ( prime )
{
if ( maxseq < ++n ) maxseq = n;
}
else
{
n = 0;
}
}
std::cout << "The longest sequence is: " << maxseq << '\n';
return 0;
}
The program output is the same as above
The longest sequence is: 5
As for your program then this loop
for (int i = 1; i < x - 1; i = j) {
skips the first element of the array that is bar[0].
And due to this statement
j = i + 1;
the calculated value of seq one less than it should be because you do not take into account that bar[i] is already prime.
Set initially seq equal to 1.
int seq = 1;
Moreover you incorrectly are determining prime numbers. For example according to your algorithm 1 is prime.
You are checking twice for prime numbers and you are using a nested loop. That's not necessary. It's enough to read all numbers, check each number, increment the count if it's a prime number and store the maximum sequence length.
#include <iostream>
#include <vector>
using namespace std;
bool isPrime(int a) {
bool prim = true;
for (int d = 2; d*d <= a; ++d) {
if (a % d == 0) {
prim = false;
}
}
return prim;
}
int main()
{
int x;
int longestseqstart = 0;
cout << "How big is the array? =";
cin >> x;
std::vector<int> bar(x);
for (int i = 0; i < x; i++) {
cout << "bar[" << i << "]=";
cin >> bar[i];
}
unsigned int count = 0;
unsigned int maxseq = 0;
for (const auto &el : bar) {
if (isPrime(el)) {
++count;
if (count > maxseq) maxseq = count;
} else count = 0;
}
cout << "The longest sequence is: ";
cout << maxseq;
return 0;
}
Of course you can avoid the usage of std::vector and functions with
#include <iostream>
using namespace std;
int main()
{
int x;
int longestseqstart = 0;
cout << "How big is the array? =";
cin >> x;
int bar[100];
for (int i = 0; i < x; i++) {
cout << "bar[" << i << "]=";
cin >> bar[i];
}
unsigned int count = 0;
unsigned int maxseq = 0;
for (unsigned int i = 0; i < x; ++i) {
int a = bar[i];
bool prim = true;
for (int d = 2; d*d <= a; ++d) {
if (a % d == 0) {
prim = false;
}
}
if (prim) {
++count;
if (count > maxseq) maxseq = count;
} else count = 0;
}
cout << "The longest sequence is: ";
cout << maxseq;
return 0;
}
The algorithm looks basically OK. The issue is mostly one of organization: the way the inner loop block is set up means that a run of primes will be short by 1 because the longest sequence is only updated at the beginning of the inner loop, missing the final prime.
A couple of minimal failing examples are:
How big is the array? =1
bar[0]=13
The longest sequence is: 0
How big is the array? =2
bar[0]=5
bar[1]=6
The longest sequence is: 0
Note that there's a repeated prime check in two places. This should not be. If we move all of the prime logic into the loop and test for a new longest sequence only after finishing the entire run, we'll have a clear, accurate algorithm:
#include <iostream>
int is_prime(int n) {
for (int i = 2; i <= n / 2; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
int main() {
int nums[100];
int n;
std::cout << "How big is the array? =";
std::cin >> n;
for (int i = 0; i < n; i++) {
std::cout << "nums[" << i << "]=";
std::cin >> nums[i];
}
int longest = 0;
for (int i = 0, start = 0; i < n; i++) {
for (start = i; i < n && is_prime(nums[i]); i++);
longest = std::max(longest, i - start);
}
std::cout << "The longest sequence is: " << longest;
return 0;
}
In this rewrite I...
avoided using namespace std;.
removed unnecessary/confusing variables.
used clear variable names (bar should only be used in example code when the name doesn't matter).
moved is_prime to its own function.
But there are outstanding issues with this code. It should...
use a vector instead of an array. As it stands, it's vulnerable to a buffer overflow attack should the user specify an array length > 100.
use a faster method of finding primes. We only need to check up to the square root of the number and can skip a lot of numbers such as even numbers after 2. I suspect this is incidental to this exercise but it's worth mentioning.
move the longest_prime_sequence to a separate function (and possibly user input gathering as well).
Convert the array to a Boolean array and find longest length. Try this snippet(not optimized):
bool is_prime(int n) {
for (int i = 2; i < n; i++) {
if (n%i == 0) return false;
}
return true;
}
int main() {
//Input
unsigned int bar[15] = { 3, 5, 7, 8, 9, 11, 13, 17, 19, 20, 23, 29, 31, 37, 41 };
// Convert input to boolean array
bool boo[15];
for (int i = 0; i < 15; i++) {
boo[i] = is_prime(bar[i]);
}
//Check the longest boolean array
int longest = 0;
for (int i = 0; i < 15; i++) {
int count = 0;
while (boo[i + count] && (i+ count) <15) {
count++;
}
if (longest < count) longest = count;
}
//Output
cout << longest;
return 0;
}

Given an integer N, print numbers from 1 to N in lexicographic order

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";
}

Iterative equivalent a recursive algorithm

I'm trying to modify this program to their equivalent iterative but it becomes very difficult to me because as yet i'm still a newbie, it comes to an algorithm that decomposes a number into its prime factors, here the code:
#include <iostream>
#include <map>
#include <cmath>
std::map< int, std::pair<int, int> > decompositions;
void descompon_number(int num, int root, int i = 2 )
{
auto iterator = decompositions.find(num);
if (iterator == decompositions.end())
{
if (num > 1 && i <= root)
{
if (num % i == 0)
{
int n = num / i;
decompositions[num] = std::make_pair(i, n);
descompon_number(n, (int) std::sqrt(n));
}
else
descompon_number(num, root, i + 1);
}
else
decompositions[num] = std::make_pair(num, 1);
}
}
void show(int num, int factor, int exponent, int see)
{
auto pair = decompositions[num];
if (num <= 1 || factor != pair.first)
{
if (see)
std::cout << factor;
if (exponent > 1 && see)
std::cout << "^" << exponent;
if (pair.first > 1 && see)
std::cout << " * ";
exponent = 0;
}
if (num > 1)
show(pair.second, pair.first, exponent + 1, see);
}
void descompon(int a, int b, int see)
{
if (a <= b)
{
descompon_number(a, (int) std::sqrt(a));
if (see)
std::cout << a << " = ";
show(a, decompositions[a].first, 0, see);
if (see)
std::cout << std::endl;
descompon(a + 1, b, see);
}
}
int main()
{
descompon(2, 100, 1);
return 0;
}
Someone can help me out with this
Finding prime factors iteratively is not very complicated.
Here's the pseudocode how to do this.
Let P be a list of the first n prime numbers, such that Pn <= sqrt(m).
array findPrimeFactors(m)
answer = new array
for p in P
while m can be divided by p
m = m / p
answer.append(p)
if m == 1
break
return answer
Note: empty array is returned if m is prime.
You can use an erastotenes' sieve to compute prime numbers, and later you can use the algorithm posted by popovitsj.
The following code can be optimized, but its main purpose is to show you how to proceed.
Complete example:
#include <iostream>
#include <vector>
using namespace std;
// Returns a vector containing the first <number> prime numbers
vector<int> erastotenes_sieve(int number)
{
vector<int> result;
int *sieve = new int[number];
for (int i = 0; i < number; i++) sieve[i] = 0;
// Traverse the sieve marking multiples.
for (int i = 2; i < number / 2; i++)
for (int j = i + i; j < number; j += i)
sieve[j] = 1;
// Collect unaffected indexes, those are prime numbers.
for (int i = 2; i < number; i++)
if (!sieve[i])
result.push_back(i);
delete [] sieve;
return result;
}
vector<int> descompon_number(int number)
{
vector<int> result;
if (number == 1 || number == 0)
{
result.push_back(number);
return result;
}
for (int &prime : erastotenes_sieve(number))
{
while (number % prime == 0 && number != 1)
{
number /= prime;
result.push_back(prime);
}
}
return result;
}
int main()
{
for (auto &i : descompon_number(20))
{
cout << i << endl;
}
return 0;
}

Significant C++ code execution slowdown

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 };