The function should take the address of the integer and modify it by inserting zeros between its digits. For example:
insert_zeros(3) //3
insert_zeros(39) //309
insert_zeros(397) //30907
insert_zeros(3976) //3090706
insert_zeros(39765) //309070605
My code:
#include <stdio.h>
#include <math.h>
void insert_zeros(int* num);
int main() {
int num;
printf("Enter a number:");
scanf("%d", num);
insert_zeros(&num);
printf("Number after inserting zeros: %d", num);
return 0;
}
void insert_zeros(int* num){
int count = 0;
int tmp = *num;
//Count the number of digits in the number
while(tmp != 0){
tmp /= 10;
count++;
}
//calculating the coefficient by which I will divide the number to get its digits one by one
int divider = (int)pow(10, count-1);
int multiplier;
tmp = *num;
*num = 0;
/*
The point at which I'm stuck
Here I tried to calculate the degree for the number 10
(my thought process and calculations are provided below)
*/
(count >= 3)? count += (count/2): count;
//the main loop of assembling the required number
while (count >= 0){
multiplier = (int)pow(10, count); //calculating a multiplier
*num += (tmp / divider) * multiplier; //assembling the required number
tmp %= divider; //removing the first digit of the number
divider /= 10; //decreasing divider
count -= 2; //decreasing the counter,
//which is also a power of the multiplier (witch is 10)
}
}
My idea consists of the following formula:
For number "3" I shold get "30" and it will be:
30 = (3 * 10^1) - the power is a counter for number "3" that equals 1.
For number "39" it will be "309":
309 = (3 * 10^2) + (9 * 10^1)
For number "397" it will be "30907":
30907 = (3 * 10^4) + (9 * 10^2) + (7 * 10^0)
For number "3976" it will be "3090706":
3090706 = (3 * 10^6) + (9 * 10^4) + (7 * 10^2) + (6 * 10^0) - with each iteration power is decreasing by 2
For number "39765" it will be "309070605":
309070605 = (3 * 10^8) + (9 * 10^6) + (7 * 10^4) + (6 * 10^2) + (5 * 10^0)
And so on...
For a 3-digit number, the start power should be 4, for a 4-digit number power should be 6, for a 5-digit it should be 8, for 6-digit it should be 10, etc.
That algorithm works until it takes a 5-digit number. It outputs a number like "30907060" with an extra "0" at the end.
And the main problem is in that piece of code (count >= 3)? count += (count/2): count;, where I tried to calculate the right power for the first iterating through the loop. It should give the right number to which will be added all the following numbers. But it only works until it gets a 5-digit number.
To be honest, so far I don't really understand how it can be realized. I would be very grateful if someone could explain how this can be done.
As noted in comments, your use of scanf is incorrect. You need to pass a pointer as the second argument.
#include <stdio.h>
#include <math.h>
int main(void) {
int num;
scanf("%d", &num);
int num2 = 0;
int power = 0;
while (num > 0) {
num2 += (num % 10) * (int)pow(10, power);
num /= 10;
power += 2;
}
printf("%d\n", num2);
return 0;
}
There's an easy recursive formula for inserting zeros: IZ(n) = 100*IZ(n/10) + n%10.
That gives a very concise solution -- here the test cases are more code than the actual function itself.
#include <stdio.h>
#include <stdint.h>
uint64_t insert_zeros(uint64_t n) {
return n ? (100 * insert_zeros(n / 10) + n % 10) : 0;
}
int main(int argc, char **argv) {
int tc[] = {1, 12, 123, 9854, 12345, 123450};
for (int i = 0; i < sizeof(tc)/sizeof(*tc); i++) {
printf("%d -> %lu\n", tc[i], insert_zeros(tc[i]));
}
}
Output:
1 -> 1
12 -> 102
123 -> 10203
9854 -> 9080504
12345 -> 102030405
123450 -> 10203040500
Adapting some code just posted for another of these silly exercises:
int main() {
int v1 = 12345; // I don't like rekeying data. Here's the 'seed' value.
printf( "Using %d as input\n", v1 );
int stack[8] = { 0 }, spCnt = -1;
// Peel off each 'digit' right-to-left, pushing onto a stack
while( v1 )
stack[ ++spCnt ] = v1%10, v1 /= 10;
if( spCnt == 0 ) // Special case for single digit seed.
v1 = stack[ spCnt ] * 10;
else
// multiply value sofar by 100, and add next digit popped from stack.
while( spCnt >= 0 )
v1 = v1 * 100 + stack[ spCnt-- ];
printf( "%d\n", v1 );
return 0;
}
There's a ceiling to how big a decimal value can be stored in an int. If you want to start to play with strings of digits, that is another matter entirely.
EDIT: If this were in Java, this would be a solution, but the problem is in C, which I'm not sure if this can convert to C.
This may be a lot easier if you first convert the integer to a string, then use a for loop to add the zeros, then afterward reconvert to an integer. Example:
int insert_zeros(int num) {
String numString = Integer.toString(num);
String newString = "";
int numStringLength = numString.length();
for (int i = 0; i < numStringLength; i++) {
newString += numString[i];
// Only add a 0 if it's not the last digit (with exception of 1st digit)
if (i < numStringLength - 1 || i == 0) newString += '0';
}
return Integer.parseInt(newString);
}
I think this should give you your desired effect. It's been a little bit since I've worked with Java (I'm currently doing JavaScript), so I hope there's no syntax errors, but the logic should all be correct.
Related
I need to write a program that takes 2 digits(X and n) and then prints X with last n digits of X reversed.
For example
Input: 12345 3
Output: 12543
Input: 523 2
Output: 532
I already wrote a control mechanism for checking n is greater or equal than the number of digits of X
For example if inputs are 6343 and 7, program prints that inputs should be changed and takes input again.
My main problem is I couldn't find an algorithm for reversing last n digits. I can reverse any int with this code
int X, r = 0;
printf("Enter a number to reverse\n");
scanf("%d", &n);
while (X != 0)
{
r = r * 10;
r = r + n%10;
X = X/10;
}
printf("Reverse of the number = %d", r);
But I couldn't figure how two reverse just last digits. Can you give me any idea for that?
I couldn't figure how to reverse just last digits
Separate the number using pow(10,n) - see later code.
unsigned reverse_last_digits(unsigned x, unsigned n) {
unsigned pow10 = powu(10, n);
unsigned lower = x%pow10;
unsigned upper = x - lower;
return upper + reverseu(lower, n);
}
Create a loop that extracts the least-significant-digit (%10) and builds up another integer by applying that digit. (y = y*10 + new_digit)
unsigned reverseu(unsigned x, unsigned n) {
unsigned y = 0;
while (n-- > 0) {
y = y*10 + x%10;
x /= 10;
}
return y;
}
For integer type problems, consider integer helper functions and avoid floating point functions like pow() as they may provide only an approximate results. Easy enough to code an integer pow().
unsigned powu(unsigned x, unsigned expo) {
unsigned y = 1;
while (expo > 0) {
if (expo & 1) {
y = x * y;
}
expo >>= 1;
x *= x;
}
return y;
}
Test
int main() {
printf("%u\n", reverse_last_digits(12345, 3));
printf("%u\n", reverse_last_digits(523, 2));
printf("%u\n", reverse_last_digits(42001, 3));
printf("%u\n", reverse_last_digits(1, 2));
}
Output
12543
532
42100
10
Code uses unsigned rather than int to avoid undefined behavior (UB) on int overflow.
It is an easy one.
1. let say the number you want to reverse is curr_number;
2. Now, the places you want to reverse is x;
(remember to verify that x must be less than the number of digit of curr_number);
3. now, just take a temp integer and store curr_number / pow(10,x) ('/' = divide and pow(10,x) is 10 to the power x)
4. now, take a second number temp2, which will store curr_number-(temp * pow(10,x) )
5. reverse this temp2 (using your function)
6. now, answer = (temp * pow(10,x) ) + (temp2) //(note temp2 is reversed)
example with steps:
curr_number = 1234567
places you want to reverse is 3
temp = 1234567 / (10^3) i.e (1234567/1000) = 1234 (because it is int type)
temp2 = 1234567 - (1234*10^3) i.e 1234567 - 1234000 = 567
reverse(567) = 765
answer = (1234 * 10^3) + 765 = 1234765
Create two variables
lastn which stores the last n digits (345)
r which stores the reversed last n digits (543)
Subtract lastn from the original number (12345 - 345 = 12000)
Add r to the above number (12000 + 543 = 12543)
int c = 0; // count number of digits
int original = x;
int lastn = 0;
while (x != 0 && c < n) {
r = r * 10;
r = r + x % 10;
lastn += (x % 10) * pow(10, c);
x = x / 10;
c++;
}
printf("reversed: %d\n", original - lastn + r);
In case you don't have problems using char, you can do this
#include <stdio.h>
#include <string.h>
#define SIZE 10
int main() {
char n[SIZE]; // the Number;
int x; // number of last digits of n to reverse
int len; // number of digits of n
scanf("%s%d", n, &x);
len = strlen(n);
for(int i = 0; i < len; i++) {
i < len - x ? printf("%c", n[i]) : printf("%c", n[2*len -1 - i - x]);
}
return 0;
}
If you want you can make the program more readable by splitting the for in two
for(int i = 0; i < len - x; i++) {
printf("%c", n[i]);
}
for(int i = len-1; i >= len - x; i--) {
printf("%c", n[i]);
}
Note: the program won't work if n > x (i.e. if you want to swap more digits than you got)
I am trying to construct a simple program which adds together the digits of a long number. I attempted to do this by using a loop employing the modulo operator and some basic arithmetic. I want to increment the modulo operator by multiplying it by ten on each iteration of the loop in order to reach the next digit. I want to check if my code is correct, however, I receive errors pertaining to the lines involving the modulo operations and I'm not quite sure why.
This was my attempted construction:
{
long i = 0;
long b;
int m = 1;
do
{
long number = get_long("Number?\n");
long a = number % m;
b = number - a;
long c = b % m x 10;
long d = c / m;
{
i = i + d;
}
{
m = m x 10
}
}
while (b > 0);
printf("%ld\n", i);
}
Edit:
I made the basic error of writing "x" instead of "*". However, having fixed this, I no longer receive errors, but the program simply returns "0". Any diagnosis would be appreciated.
int main(void)
{
long i = 0;
long b;
int m = 10;
long number = get_long("Number?\n");
do
{
long a = number % m;
b = number - a;
long c = b % m * 10;
long d = c / m;
{
i = i + d;
}
{
m = m * 10;
}
}
while (b > 0);
printf("%ld\n", i);
}
For your revised code:
long c = b % m * 10;
this line will evaluate (b % m) and then multiply it by 10 because of the order of operations.
I presume what you actually want is:
long c = b % (m * 10);
Secondly, the following line determines which digit you start at:
int m = 10;
and this line determines how many digits between the ones you include in your total:
m = m * 10;
So for this configuration, it will start at the 2nd digit from the right and add every digit.
So for the number 1234, you'd get 3 + 2 + 1 = 6.
If you want to add every digit, you could set:
int m = 10;
and you'd get 4 + 3 + 2 + 1 = 10.
Alternatively, if you had used:
m = m * 10;
you'd have 3 + 1 = 4.
First, you're likely getting errors due to these lines:
long c = b % m x 10;
m = m x 10
This is because x is not a valid operator.
The multiplication operator is *:
long c = b % m * 10;
m = m * 10;
As for your approach, I would suggest, instead of changing the modulo operand, you simply divide the original number by 10 to shift it one digit each operation.
For example:
#include <stdio.h>
int main()
{
int sumofdigits = 0;
int num = 12345;
while(num > 0) {
sumofdigits += num % 10;
num /= 10;
}
printf("%d", sumofdigits);
return 0;
}
The reduced-sum of the digits of a number is the same as that number modulo 9.
Example:
#include <stdio.h>
int main(void) {
int number = 57283;
printf("%d \n", number%9);
// 5 + 7 + 2 + 8 + 3 == 25 ==> 2 + 5 == 7
// 57283 % 9 == 7
return 0;
}
If you want to use loops to get the reduced sum:
int sum_of_digits(int num)
{
int sum;
do
{
sum = 0;
while(num)
{
sum += num%10;
num /= 10;
}
num = sum;
} while (sum >9);
return sum;
}
But if you only want the simple sum of digits (one pass only):
int sum_of_digits(int num)
{
int sum = 0;
while(num)
{
sum += num%10;
num /= 10;
}
return sum;
}
You have to find the sum of the digits of a variable of type long by the two operators modulo (%) and division (/), you start with the operator modulo to find the remainder of the division (the digits) then, you add this degit to the sum, then you do the division / 10 to overwrite (the summed digit) until the number is equal to 0 like this:
int main()
{
long number=0,m=0;
printf("Give a number :");
scanf("%ld",&number);
long s=0,temp=number;
while(number != 0)
{
m=number%10;
s+=m;
number/=10;
}
printf("\n%The sum of the digits of the Number %ld is : %ld\n",temp,s);
}
I can't elaborate a program with arrays language C.
The console received 4 numbers. I want to change the first number digits and multiply with the other.
Example input: 1260
Desire output: Change 12 to 21 and them multiple by 60 -> so output will be 1260 (as 21 * 60)
This is my current code:
int main() {
int number, temp;
int newnumber[4];
int n = 3;
printf("put the number");
scanf("%d", &number);
do {
newnumber[n] = number % 10;
number = number / 10;
n--;
} while (n >= o);
temp = newnumber[1];
newnumber[1] = newnumber[2];
newnumber[2] = temp;
}
know how i do 21 multiply with 60?
If we look at your example:
1260 => change 2 with 1, and multiply 21 with 60.
The permutation in your main function is wrong, cause you changed numbers at the index 1 (second position) and 2 (third position).
Back to your question, you can get the result you're looking for by doing the oppisite of what you did to get the units, tens and hundreds...
int main() {
int number, temp1, temp2;
int newnumber[4];
int n = 3;
printf("put the number");
scanf("%d", &number);
do {
newnumber[n] = number % 10;
number = number / 10;
n--;
} while (n >= 0);
temp1 = newnumber[0];
newnumber[0] = newnumber[1];
newnumber[1] = temp1;
temp1 = newnumber[0] * 10;
temp1 += newnumber[1];
temp2 = newnumber[2] * 10;
temp2 += newnumber[3];
printf("%d", temp1 * temp2);
}
I would have go with slightly different approach: first separate the numbers. Then call function to change the number order.
If you always get numbers with 2 digit you can do this:
int first = number / 100;
int second = number % 100;
And a function to swap the digit:
function swapDigits(int num) {
int ans = 0;
while (num > 0) {
ans = ans * 10 + num % 10;
num /= 10;
}
return ans;
}
Now just do second * swapDigits(first) to get your result.
I'm not c expert so verify my code before use...
If your conditions always hold you can keep it simple and do something like this:
int main() {
int number;
int newnumber[4];
int n = 3;
printf("put the number");
scanf("%d", &number);
do {
newnumber[n] = number % 10;
number = number / 10;
n--;
} while (n >= 0);
printf("And the result: %d\n", (newnumber[1] * 10 + newnumber[0]) * (newnumber[2] * 10 + newnumber[3]));
}
Then you are not getting the individual digits, but pairs and the like. Just get the last two digits in one shot:
int rem = number % 100; /* last two digits */
number /= 100;
int msd = number % 10; /* next, third digit */
number /= 10;
int lsd = number % 10; /* most significant digit */
/* I don't assume you have more digits, because you are doing different
* operations with them, no pattern up to here, but you should continue
* your approach here. */
int out = (msd * 10 + lsd) * rem;
should give you a solution. No arrays needed.
When I run this code, I get outputs that don't really make any sense. I'm most likely just missing something, but I've been working on trying to find the problem with my code by working out the problems by hand, but I'm getting the values I should be getting when I do it by hand. A simplified version of this calculation is (c%10^n - c%10^(n-1)) / 10^(n-1).
The goal of this calculation is to assign the digits of a number to an array of ints. I'm not really looking for alternate solutions.
int cNumberV[nLength];
for(int n = nLength; n > 0; n--) {
cNumberV[nLength - n] = (cNumber % (long long) pow(10, n) - cNumber % (long long) pow(10, n - 1)) / (long long) pow(10, n - 1);
printf("%i\n", cNumberV[n]);
}
This is my output when cNumber = 5105105105105100 and nLength = 16:
-1981492631
232830
-1530494976
1188624
-397102900
134514540
-1081801416
1188624
0
1
5
0
1
5
0
1
The problem is that your loop sets cNumberV[nLength - n], but then prints out cNumberV[n].
So the first half of the loop prints uninitialized array entries, and the second half of the loop prints the result of the first half's calculation in reverse order (but due to an off-by-one error as pointed out by rowan.G, it never prints the first digit).
pow() is an expensive and inaccurate floating function. You only
need simple integer divide by ten to get digits. If you really want
to get them left-to-right as you do above, make a lookup table with
the 19 powers of 10 as integers.
#include <stdio.h>
#define nLength 20
long long cNumber = 5105105105105100;
int cNumberV[nLength];
int negative = 0;
int main(int argc, char *argv[]) {
if (cNumber < 0) {
negative = 1;
cNumber = -cNumber;
}
int n;
for (n = nLength - 1; n >= 0; n -= 1) {
cNumberV[n] = cNumber % 10;
cNumber /= 10;
if (0 == cNumber) break;
}
if (negative) printf("-");
for (int i = n; i < nLength; i += 1) {
printf("%1d", cNumberV[i]);
}
printf("\n");
}
I have to find the sum of the first 4 digits, the sum of the last 4 digits and compare them (of all the numbers betweem m and n). But when I submit my solution online there's a problem with the time limit.
Here's my code:
#include <stdio.h>
int main()
{
int M, N, res = 0, cnt, first4, second4, sum1, sum2;
scanf("%d", &M);
scanf("%d", &N);
for(cnt = M; cnt <= N; cnt++)
{
first4 = cnt % 10000;
sum1 = first4 % 10 + (first4 / 10) % 10 + (first4 / 100) % 10 + (first4 / 1000) % 10;
second4 = cnt / 10000;
sum2 = second4 % 10 + (second4 / 10) % 10 + (second4 / 100) % 10 + (second4 / 1000) % 10;
if(sum1 == sum2)
res++;
}
printf("%d", res);
return 0;
}
I'm trying to find a more efficient way to do this.
Finally, if you are still interested, there is a much faster way to do this.
Your task doesn't specifically require you to calculate the sums for all the numbers,
it only asks for the number of some special numbers.
In such cases optimization techniques like memoization or dynamic programming come really handy.
In this case, when you have the first four digits of some number (let them be 1234),
you calculate their sum (in this case 10) and you immediately know,
what is the sum of the other four digits supposed to be.
Any 4-digit number, that yields sum 10 can now be the other half to create a valid number.
Therefore total number of valid numbers beginning with 1234 is exactly the number of all four digit numbers that give the sum 10.
Now consider another number, say 3412. This number has also sum equal to 10,
therefore any right-side that completes 1234 also completes 3412.
What this means is that the number of valid numbers beginning with 3412 is the same
as the number of valid numbers beginning with 1234, which is in turn the same as the total number of valid numbers, where the first half yields the sum 10.
Therefore if we precompute for each i the number of four digit numbers
that yield the sum i, we would know for each first four digits the exact number of
combinations of last four digits that complete a valid number,
without having to iterate over all 10000 of them.
The following implementation of this algorithm
Precomputes number of different ending halves for each sum of the beginning half
Splits the [M,N] interval in three subintervals, because in the first and the last beginning not every ending is possible
This algorithm runs quadratically faster than the naive implementation (for sufficiently big N-M).
#include <string.h>
int sum_digits(int number) {
return number%10 + (number/10)%10 + (number/100)%10 + (number/1000)%10;
}
int count(int M, int N) {
if (M > N) return 0;
int ret = 0;
int tmp = 0;
// for each i from 0 to 36 precompute number of ways we can get this sum
// out of a four-digit number
int A[37];
memset(A, 0, 37*4);
for (int i = 0; i <= 9999; ++i) {
++A[sum_digits(i)];
}
// nearest multiple of 10000 greater than M
int near_M = ((M+9999)/10000)*10000;
// nearest multiple of 10000 less than N
int near_N = (N/10000)*10000;
// count all numbers up to first multiple of 10000
tmp = sum_digits(M/10000);
if (near_M <= N) {
for (int i = M; i < near_M; ++i) {
if (tmp == sum_digits(i % 10000)) {
++ret;
}
}
}
// count all numbers between the 10000 multiples, use the precomputed values
for (int i = near_M / 10000; i < near_N / 10000; ++i) {
ret += A[sum_digits(i)];
}
// count all numbers after the last multiple of 10000
tmp = sum_digits(N / 10000);
if (near_N >= M) {
for (int i = near_N; i <= N; ++i) {
if (tmp == sum_digits(i % 10000)) {
++ret;
}
}
}
// special case when there are no multiples of 10000 between M and N
if (near_M > near_N) {
for (int i = M; i <= N; ++i) {
if (sum_digits(i / 10000) == sum_digits(i % 10000)) {
++ret;
}
}
}
return ret;
}
EDIT: I fixed the bugs mentioned in the comments.
I don't know if this would be significantly faster or not, but you might try breaking the number into two 4 digit numbers, then use a table lookup to get the sums. That way there's only one division operation instead of eight.
You can pre-compute the table of 10000 sums so it gets compiled in so there's no runtime cost at all.
Another slightly more complicated, but probably much faster, approach that can be used is have a table or map of 10000 elements that's the reverse of the sum lookup table where you can map the sum to the set of four digit numbers that would produce that sum. That way, when you have to find the result for a particular range 10000 number range, it's a simple lookup on the sum of the most significant four digits. For example, to find the result for the range 12340000 - 12349999, you could use a binary search on the reverse lookup table to quickly find how many numbers in the range 0 - 9999 have the sum 10 (1 + 2 + 3 + 4).
Again - this reverse sum lookup table can be pre-computed and compiled in as a static array.
In this way, the results for complete 10000 number ranges are performed with a couple binary searches. Any partial ranges can also be handled with the reverse lookup table with slightly more complication due to having to ignore matches that are from out of the range of interest. But that complication only has to happen at most twice for your whole set of subranges.
This would reduce the complexity of the algorithm from O(N*N) to O(N log N) (I think).
update:
Here's some timings I got (Win32-x86, using VS 2013 (MSVC 12) with release build default options):
range range
start end count time
================================================
alg1(10000000, 99999999): 4379055, 1.854 seconds
alg2(10000000, 99999999): 4379055, 0.049 seconds
alg3(10000000, 99999999): 4379055, 0.001 seconds
with:
alg1() is the original code from the question
alg2() is my first cut suggestion (lookup precomputed sums)
alg3() is the second suggestion (binary search lookup of sum matches using a table sorted by sums)
I'm actually surprised at the difference between alg1() to alg2()
You are going about this the wrong way. A little bit of cleverness is worth a lot of horsepower. You should not be comparing the first and last four digits of every number.
First - notice that the first four digits will change very slowly - so for sure you can have a loop of 10000 of the last four digits without re-computing the first sum.
Second - the sum of digits repeats itself every 9th number (until you get overflow). This is the basis of the "number is divisible by 9 if sum of digits is divisible by 9". example:
1234 - sum = 10
1234 + 9 = 1243 - sum is still 10
What this means is that the following will work pretty well (pseudo code):
take first 4 digits of M, find sum (call it A)
find sum of last four digits of M (call it B)
subtract: C = (A - B)
If C < 9:
D = C%9
first valid number is [A][B+D]. Then step by 9, until...
You need to think a bit about the "until", and also about what to do when C >= 9. This means you need to find a zero in B and replace it with a 9, then repeat the above.
If you want to do nothing else, then see that you don't need to re-compute the sum of digits that did not change. In general when you add 1 to a number, the sum of digits increases by 1 (unless there is carry - then it decreases by 9; and that happens every 9th, 99th (twice -> sum drops by 18), 999th (drop by 27), etc.
I hope this helps you think about the problem differently.
I am going to try an approach which doesn't make use of the lookup table (even though I know that the second one should be faster) to investigate how much we can speedup just optimizing calculus. This algorithm can be used where stack is an important resource...
Let's work on the idea that divisions and modulus are slow, for example in cortex R4 a 32 bit division requires up to 16 loops while a multiplication can be done in a single loop, with older ARMs things can be even worse.
This basic idea will try to get rid of them using digit arrays instead of integers. To keep it simple let's show an implementation using printf before a pseudo optimized version.
void main() {
int count=0;
int nmax;
char num[9]={0};
int n;
printf( "Insert number1 ");
scanf( "%d", &nm );
printf( "Insert number2 ");
scanf( "%d", &nmax );
while( nm <= nmax ) {
int sumup=0, sumdown=0;
sprintf( num, "%d", nm );
for( n=0; n<4; n++ ) {
sumup += num[n] -'0'; // subtracting '0' is not necessary (see below)
sumdown += num[7-n]-'0'; // subtracting '0' is not necessary (see below)
}
if( sumup == sumdown ) {
/* whatever */
count++;
}
nm++;
}
}
You may want to check that the string is a valid number using strtol before calling the for loop and the length of the string using strlen. I set here fixed values as you required (I assume length always 8).
The downside of the shown algorithm is the sprintf for any loop that may do thing worse... So we apply two major changes
we use [0-9] instead of ['0';'9']
we drop the sprintf for a faster solution which takes in account that we need to format a digit string starting from the previous number (n-1)
Finally the pseudo optimized algorithm should look something like the one shown below in which all divisions and modules are removed (apart from the first number) and bytes are used instead of ASCII.
void pseudo_optimized() {
int count=0;
int nmax,nm;
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
printf( "Insert number1 ");
scanf( "%d", &nm );
printf( "Insert number2 ");
scanf( "%d", &nmax );
n = nm;
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
while( nm <= nmax ) {
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
if( sumup == sumdown ) {
/* whatever */
count++;
}
nm++;
/* Following loop is a faster sprintf replacement and
* it will exit at the first value 9 times on 10
*/
for( i=7; i>=0; i-- ) {
if( num[i] == 9 ) {
num[i]=0;
} else {
num[i] += 1;
break;
}
}
}
}
Original algo on my vm 5.500000 s, this algo 0.950000 s tested for [00000000=>99999999]
The weak point of this algorithm is that it uses sum of digits (which are not necessary and a for...loop that can be unrolled.
* update *
further optimization. The sums of digits are not necessary.... thinking about it I could improve the algorithm in the following way:
int optimized() {
int nmax=99999999,
int nm=0;
clock_t time1, time2;
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
int count=0;
n = nm;
time1 = clock();
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
while( nm <= nmax ) {
if( sumup == sumdown ) {
count++;
}
nm++;
for( i=7; i>=0; i-- ) {
if( num[i] == 9 ) {
num[i]=0;
if( i>3 )
sumdown-=9;
else
sumup-=9;
} else {
num[i] += 1;
if( i>3 )
sumdown++;
else
sumup++;
break;
}
}
}
time2 = clock();
printf( "Final-now %d %f\n", count, ((float)time2 - (float)time1) / 1000000);
return 0;
}
with this we arrive to 0.760000 s which is 3 times slower than the result achieved on the same machine using lookup tables.
* update* Optimized and unrolled:
int optimized_unrolled(int nm, int nmax) {
char num[9]={0};
int sumup=0, sumdown=0;
int n,i;
int count=0;
n = nm;
for( i=7; i>=0; i-- ) {
num[i]=n%10;
n/=10;
}
sumup = num[0] + num[1] + num[2] + num[3];
sumdown = num[7] + num[6] + num[5] + num[4];
while( nm <= nmax ) {
if( sumup == sumdown ) {
count++;
}
nm++;
if( num[7] == 9 ) {
num[7]=0;
if( num[6] == 9 ) {
num[6]=0;
if( num[5] == 9 ) {
num[5]=0;
if( num[4] == 9 ) {
num[4]=0;
sumdown=0;
if( num[3] == 9 ) {
num[3]=0;
if( num[2] == 9 ) {
num[2]=0;
if( num[1] == 9 ) {
num[1]=0;
num[0]++;
sumup-=26;
} else {
num[1]++;
sumup-=17;
}
} else {
num[2]++;
sumup-=8;
}
} else {
num[3]++;
sumup++;
}
} else {
num[4]++;
sumdown-=26;
}
} else {
num[5]++;
sumdown-=17;
}
} else {
num[6]++;
sumdown-=8;
}
} else {
num[7]++;
sumdown++;
}
}
return count;
}
Unrolling vectors improves the speed of about 50%. The algorithm costs now 0.36000 s, by the way it makes use of the stack a bit more than the previous solution (as some 'if' statements may result in a push, so it cannot be always used). The result is comparable with Alg2#Michael Burr on the same machine, [Alg3-Alg5]#Michael Burr are a lot faster where stack isn't a concern.
Note all test where performed on a intel VMS. I will try to run all those algos on a ARM device if I will have time.
#include <stdio.h>
int main(){
int M, N;
scanf("%d", &M);
scanf("%d", &N);
static int table[10000] = {0,1,2,3,4,5,6,7,8,9};
{
register int i=0,i1,i2,i3,i4;
for(i1=0;i1<10;++i1)
for(i2=0;i2<10;++i2)
for(i3=0;i3<10;++i3)
for(i4=0;i4<10;++i4)
table[i++]=table[i1]+table[i2]+table[i3]+table[i4];
}
register int cnt = M, second4 = M % 10000;
int res = 0, first4 = M / 10000, sum1=table[first4];
for(; cnt <= N; ++cnt){
if(sum1 == table[second4])
++res;
if(++second4>9999){
second4 -=10000;
if(++first4>9999)break;
sum1 = table[first4];
}
}
printf("%d", res);
return 0;
}
If you know that the numbers are fixed like that, then you can you substring functions to get the components and compare them. Otherwise, your modulator operations are contributing unnecessary time.
i found faster algorithm:
#include <stdio.h>
#include <ctime>
int main()
{
clock_t time1, time2;
int M, N, res = 0, cnt, first4, second4, sum1, sum2,last4_ofM,first4_ofM,last4_ofN,first4_ofN,j;
scanf("%d", &M);
scanf("%d", &N);
time1 = clock();
for(cnt = M; cnt <= N; cnt++)
{
first4 = cnt % 10000;
sum1 = first4 % 10 + (first4 / 10) % 10 + (first4 / 100) % 10 + (first4 / 1000) % 10;
second4 = cnt / 10000;
sum2 = second4 % 10 + (second4 / 10) % 10 + (second4 / 100) % 10 + (second4 / 1000) % 10;
if(sum1 == sum2)
res++;
}
time2 = clock();
printf("%d\n", res);
printf("first algorithm time: %f\n",((float)time2 - (float)time1) / 1000000.0F );
res=0;
time1 = clock();
first4_ofM = M / 10000;
last4_ofM = M % 10000;
first4_ofN = N / 10000;
last4_ofN = N % 10000;
for(int i = first4_ofM; i <= first4_ofN; i++)
{
sum1 = i % 10 + (i / 10) % 10 + (i / 100) % 10 + (i / 1000) % 10;
if ( i == first4_ofM )
j = last4_ofM;
else
j = 0;
while ( j <= 9999)
{
sum2 = j % 10 + (j / 10) % 10 + (j / 100) % 10 + (j / 1000) % 10;
if(sum1 == sum2)
res++;
if ( i == first4_ofN && j == last4_ofN ) break;
j++;
}
}
time2 = clock();
printf("%d\n", res);
printf("second algorithm time: %f\n",((float)time2 - (float)time1) / 1000000.0F );
return 0;
}
i just dont need to count sum of the first four digits all the time the number in changed. I need to count it one time per 10000 iterations. In worst case output is:
10000000
99999999
4379055
first algorithm time: 5.160000
4379055
second algorithm time: 2.240000
about half the better result.