Can I compute digital sum of 2ⁿ more efficiently? - c

I am trying to make a recursive function in C that calculates the sum of digits in 2ⁿ, where n < 10⁷. I made something that works, but it's very slow (for n = 10⁵ it takes 19 seconds). The function must return the sum in maximum 1 second. My algorithm calculates 2ⁿ using arrays to store its digits and it's not using a recursive function.
Is there any way to compute this sum of digits without calculating 2ⁿ? Or a faster way to calculate 2ⁿ and its digits sum?
P.S.: The recursive function must get only the n parameter, i.e. int f(int n);
Late edit: I wrote a recursive solution; it is faster, but it doesn't work for n > 10⁵.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int sumOfDigits(int* num, int n) {
if (n == 0) {
int sum = 0;
for (int i = 1; i <= num[0]; ++i) {
while (num[i] > 0) {
sum += num[i] % 10;
num[i] /= 10;
}
}
return sum;
}
int carry = 0;
for (int i = 1; i <= num[0]; ++i) {
num[i] = num[i] * 2 + carry;
carry = num[i] / 1000000000;
num[i] %= 1000000000;
if (carry != 0 && i == num[0]) {
++num[0];
}
}
return sumOfDigits(num, n - 1);
}
int main (void) {
int n = 100000;
int size = (n*log10(2) + 1) / 9 + 2;
int* num = calloc(size, sizeof(int));
num[0] = 1;
num[1] = 1;
printf("\n%d", sumOfDigits(num, n));
free(num);
return 0;
}

It seems that the posted code is using an "implicit" arbitrary precision type (with "digits" in the range [0, 999999999]) to recursively calculate all the multiplication by 2, which means, for e.g. n = 100, to perform 100 times those expansive calculation.
It should be more efficient (O(log(n)) instead of O(n)) to perform each time a multiplication of the number by itself or by 2, based on whether the exponent is even or odd. E.g. 27 = 2 * (23 * 23).
Another approach would be to explicitly implement a Bing Int type, but with a binary underlying type (say a uint32_t). It would be trivial to calculate 2n, it'd be just an array of zeroes with a final power of two (again, just one non-zero bit).
Now, to get the sum of the (base 10) digits you need to transform that number in base, say 100000000 (like the OP did), and to do that, you have to implement a long subtraction between two Big Ints and a long division by 100000000, which will give you the remainder too. Use that remainder to calculate the partial sum of the digits and iterate.
The following is a minimal implementation, testable here.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#define D_BASE 1000000
#define MSB_MASK 1 << 31
typedef struct
{
uint32_t size;
uint32_t capacity;
uint32_t *digits;
} BigInt;
void divide_bigint(BigInt *n, uint32_t x, uint32_t *remainder);
BigInt *make_bigint_of_two_raised_to(uint32_t n)
{
BigInt *p = malloc(sizeof *p);
if (!p)
{
perror("Fatal error");
exit(1);
}
uint32_t pos = n / 32;
uint32_t remainder = n % 32;
uint32_t capacity = (remainder == 31) ? pos + 2 : pos + 1;
uint32_t *pp = calloc(capacity, sizeof *pp);
if (!pp)
{
perror("Error initializing a Big Int as a power of two");
free(p);
exit(1);
}
p->capacity = capacity;
p->size = capacity;
pp[pos] = 1u << remainder;
p->digits = pp;
return p;
}
void free_bigint(BigInt **p);
uint64_t sum_of_digits_of_two_raised_to_the_power(uint32_t n)
{
BigInt *power_of_two = make_bigint_of_two_raised_to(n);
uint32_t remainder;
uint64_t sum = 0;
while (!(power_of_two->size == 1 && power_of_two->digits[0] == 0))
{
divide_bigint(power_of_two, 1000000000, &remainder);
while (remainder)
{
sum += remainder % 10;
remainder /= 10;
}
}
free_bigint(&power_of_two);
return sum;
}
void test(uint32_t n)
{
uint64_t sum = sum_of_digits_of_two_raised_to_the_power(n);
printf("Sum of digits of 2^%d: %" PRIu64 "\n", n, sum);
}
int main(void)
{
test(5);
test(10);
test(1000);
test(10000);
test(100000);
test(1000000);
return 0;
}
void shrink_size(BigInt *n)
{
while ( n->size > 1 )
{
if ( n->digits[n->size - 1] == 0 && !(n->digits[n->size - 2] & MSB_MASK) )
--n->size;
else
break;
}
}
void divide_bigint(BigInt *n, uint32_t x, uint32_t *remainder)
{
uint64_t carry = 0;
uint32_t i = n->size;
while ( i-- > 0 )
{
carry <<= 32;
carry += n->digits[i];
if ( carry < x )
{
n->digits[i] = 0;
continue;
}
uint64_t multiplier = (carry / x);
carry -= multiplier * x;
n->digits[i] = (uint32_t)multiplier;
}
shrink_size(n);
*remainder = carry;
}
void free_bigint(BigInt **p)
{
if (p && *p)
{
free((*p)->digits);
free(*p);
*p = NULL;
}
}

2^8 = (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2) = (2 * 2 * 2 * 2) * (2 * 2 * 2 * 2) = (2 * 2 * 2 * 2)^2 = ((2 * 2) * (2 * 2))^2 = ((2 * 2)^2)^2 = ((2^2)^2)^2
So, first you need to calculate log(2, n), to see how you can calculate effectively. If log(2, n) is an integer, then you can simply calculate the square of the square of the ... of the square with very few operations. If log(2, n) is not an integer, then calculate 2^((int)log(2, n)) and thus you will very effectively do a partial calculation and then do the same for the remainder until there is no longer remainder.
Unify your partial results into a number (possibly represented by an array) and calculate the sum of the digits. Calculating the sum of the digits is straight-forward. The actual calculation of the 2^n is what takes the most time.
If you do not reach the limits of a number format, then you can think about shift left, but with the domain you work with this is not really an option.

Related

Converting decimal into binary in c using pointers

Write a function int* dec2bin(int N, int* n), which, given a natural number 0 ≤ N < 65535, computes and returns its representation in the binary numeral system. The program has to determine the coefficients ai ∈ {0,1}, i = 0,...,n − 1, such that N = (sum->n-1) ai2^i (n ≤ 16).
#include <stdio.h>
#include <math.h>
#include <assert.h>
int decimalToBinary(int N)
{
int B_Number = 0;
int c= 0;
int ctr=0;
while (N != 0) {
int rem = N % 2;
c = pow(10, ctr);
B_Number += rem * c;
N /= 2;
ctr++;
}
return B_Number;
}
int main()
{
int N;
scanf("%d", &N);
printf("%d", decimalToBinary(N));
return 0;
}
I know how to make a program that converts the numbers but I don't understand why the pointer is needed for and how to implement it.
Another way...
This was written to print the binary representation of a value (left-to-right). Instead of printing, you could simply assign the 0/1 (left-to-right) to a passed array (of 16 integers), then return the number of assigned integers to the calling function to print them from a loop.
int main() {
for( int i = 253; i <= 258; i++ ) {
printf( "Decimal %d: ", i );
unsigned int bitmask = 0;
bitmask = ~bitmask;
bitmask &= ~(bitmask >> 1); // High bitmask ready
// skip over leading 0's (optional)
while( bitmask && (bitmask & i) == 0 ) bitmask >>= 1;
// loop using bitmask to output 1/0, then shift mask
do {
putchar( (bitmask & i) ? '1' : '0' );
} while( (bitmask >>= 1) != 0 );
putchar( '\n' );
}
return 0;
}
Use an integer type capable of encoding the decimal number 1111_1111_1111_1111: use long long.
Do not use pow(), a floating point function for an integer problem. It may generate value just slightly smaller than the integer expected and is slow.
long long decimalToBinary_alt(int N) {
long long B_Number = 0;
long long power = 1;
while (N != 0) {
int rem = N % 2; // result: -1, 0, or 1
B_Number += rem * power;
N /= 2;
power *= 10; // Scale the power of 10 for the next iteration.
}
return B_Number;
}
Usage
printf("%lld\n", decimalToBinary(N));
Your function does not have the required parameters and return value.
int* dec2bin(int N, int* n)
{
unsigned uN = N;
for(int bit = 15; bit >= 0; bit--)
{
*(n + 15 - bit) = !!(uN & (1U << bit));
}
return n;
}

tail recursion on double factorial equation in C

I have a difficulty in implementing the tail recursive solution of the following problem:
There is another recursive relation for the double factorial, which also depends on the factorial, which is the above: (for n<20)
I have to implement a recursive relation of this equation- which I did as the above code that works:
long long factorial(int n) {
if (n < 0)
return 0;
if (n < 1)
return 1;
return n * factorial(n - 1);
}
long long doublefactorial(int n) {
if (n < 0)
return 0;
if (n < 2)
return 1;
return factorial(n) / doublefactorial(n - 1);
}
Now I have to implement the same problem using a tail recursion. can someone show me how to do this because I cant figure it out. (no need to implement the factorial function also in a tail recursive way)
test cases:
5!! = 15
10!! = 3840
18!! = 185,794,560
-10!! = 0
Here is a tail-recursive version of Factorial function:
long factorial(int n, int factor)
{
if (n == 0)
return factor;
return factorial(n-1, factor * n);
}
factorial(5, 1); // 120
Here's a tail-recursive double factorial with a simpler logic:
long doublefactorial(int n, int factor)
{
if (n < 0)
return 0;
if (n < 2)
return factor;
return doublefactorial(n-2, factor * n);
}
printf("%d ", doublefactorial(5,1)); // 15
printf("%d ", doublefactorial(10,1)); // 3840
printf("%d ", doublefactorial(18,1)); // 185794560
If you expand your math a little bit you'll get that the factorial function result is iterating between the numerator and the denominator of the final result.
so this code will do that in Python
def _factorial(n, m):
if n < 0:
return 0
elif n == 0:
return 1.0 * m
return _factorial(n - 1, n * m)
def factorial(n):
return _factorial(n, 1)
def _doublefactorial(n, m, is_even):
if n < 0:
return 0
elif n < 2:
return 1.0 * m
if is_even:
m *= factorial(n)
else:
m /= factorial(n)
return _doublefactorial(n - 1, m, (not is_even))
def doublefactorial(n):
return _doublefactorial(n, 1, True)
And in C:
unsigned int _factorial(const unsigned int n, const unsigned int m) {
if (n < 0) {
return 0;
} else if (n == 0) {
return m;
}
return _factorial(n - 1, n * m);
}
unsigned int factorial(const unsigned int n) {
return _factorial(n, 1);
}
double _doublefactorial(const unsigned int n, const double m, const char is_even) {
double value = m;
if (n < 0) {
return 0;
} else if (n < 2) {
return m;
}
if (is_even) {
value *= factorial(n);
} else {
value /= factorial(n);
}
return _doublefactorial(n - 1, value, !is_even);
}
double doublefactorial(const unsigned int n) {
return _doublefactorial(n, 1, 1);
}
Your definition of this double factorial function is incomplete: you need an initial value such as 0!! = 1. From the recurrence definition, it appears that p!! is the product of all numbers from 1 to p that have the same parity as p:
5!! = 1 * 3 * 5 = 15
6!! = 2 * 4 * 6 = 48
10!! = 2 * 4 * 6 * 8 * 10 = 3840
Computing the double factorial by computing the factorial and dividing by the result of the double factorial of the previous number will fail for numbers larger than 19 because of the limited range of integer types and the exponential growth of the factorial function. The double factorial grows quickly too, but its logarithm grows half as fast as that of the factorial function.
Here is an recursive function:
unsigned long long doublefactorial(int n) {
if (n < 0)
return 0;
if (n < 2)
return 1;
return n * doublefactorial(n - 2);
}
Here is a tail recursive implementation with a helper function:
unsigned long long doublefactorial_helper(int n, unsigned long long res) {
if (n < 2)
return res;
return doublefactorial(n - 2, res * n);
}
unsigned long long doublefactorial(int n) {
return doublefactorial_helper(n, n >= 0);
}
The trick to convert the first function to a tail recursive one is instead of waiting for the result and multiplying then by n, pass an updated intermediary result to the recursive function. The multiplications are performed in the opposite order but will produce the same result (even modulo ULLONG_MAX+1).

C reverse a number recursivly

I have an assigment to create a function that recieves a number, and return the reversed number.
E.G :
Input : 12343
Output : 34321
No loops allowed, and the input is only the number .
This is what I've tried :
long GetReverse(unsigned long n)
{
if (n < 10)
return n % 10;
else
return 10 * GetReverse(n / 10) + n % 10;
}
Though This is retuning me the same input and not reversing the number ( I know what is the problem here, I just can't think of a way to do it)
Any thoughts?
EDIT: This is the solution I came up with :
int numOfMulti(unsigned long num) {
if (num < 10)
return 1;
return 10 * numOfMulti(num / 10);
}
long GetReverse(unsigned long n)
{
if (n < 10)
return n % 10;
else
return n % 10 * numOfMulti(n) + GetReverse(n / 10) ;
}
Wasn't able to find a solution without a secondary function or static variables.
It's easy. Please try my solution. NO LOOPS, ONE PARAMETER.
long GetReverse(unsigned long n)
{
static unsigned long m = 0;
static int recursive_level = 0;
recursive_level++;
if (n < 10) {
recursive_level--;
m = m * 10 + n;
int temp = m;
if (recursive_level == 0) {
m = 0;
}
return temp;
}
m = m * 10 + (n % 10);
GetReverse(n / 10);
recursive_level--;
int temp = m;
if (recursive_level == 0) {
m = 0;
}
return temp;
}
You will need to pass 2 elements to the GetReverse function, because the last digit will have to be shifted on the left:
long GetReverse(unsigned long n, unsigned long m)
{
if (n < 10)
return 10 * m + n;
else
return GetReverse(n / 10, 10 * m + n % 10);
}
You can then call GetReverse(12343, 0) and get as expected 34321
This is silly and should not be used in real life, but complies with the requirements:
unsigned long GetReverse(unsigned long n)
{
if (n < 10)
return n;
else
return n % 10 * lround(pow(10,floor(log10(n)))) + GetReverse(n / 10);
}
Here's a solution that only takes one parameter, although you can only use the least significant 32 bits for your input:
uint64_t rev(uint64_t n)
{
uint32_t _n = n;
uint32_t _m = n >> 32;
return _n < 10
? 10 * _m + _n
: rev(_n / 10 + (uint64_t)(10 * _m + _n % 10) * 65536 * 65536)
;
}
int main(){
uint32_t n = 12345;
n = rev(n);
}
Essentially the coefficient is stored in the higher order bits of n. In many ways this is a terrible contrivance since all I'm doing is using a single parameter where there should be two parameters, and I'm relying on a (well-defined) narrowing unsigned conversion at the call site! But it does show the elegance of using the fixed width unsigned types.
How about this?
#include <stdio.h>
#include <math.h>
long GetReverse(unsigned long n){
if (n < 10){
return n;
} else {
unsigned long r = GetReverse(n / 10);
int p = snprintf(NULL, 0, "%lu", r);
return lround(pow(10, p)) * (n % 10) + r;
}
}
int main(void){
unsigned long n = 112233445566778899;
printf("%lu", GetReverse(n));
return 0;
}
To place the last digit first you need to multiply it by 10 once for each digit in the number:
#include <math.h>
long GetReverse(unsigned long n)
{
if (n < 10)
return n; // Removed the % 10 as it is not needed when n is < 10
else {
long digit = n%10;
long factor = (long) pow(10, (int)log(n));
return digit * factor + GetReverse(n / 10);
}
}
log and pow is used instead of loops to calculate the number of digits in n. Note that this may fail unless the implementation of pow is good enough. I did a test using gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16) and that combination produced correct results for integer powers of 10 for results that fit in a long.
No loops, no variables, no additional parameters!
#include <stdio.h>
unsigned long reverse(unsigned long num)
{
if (num < 10) return num;
if (num < 100) return 10 * (num %10) + reverse(num/10);
if (num < 1000) return 100 * (num %10) + reverse(num/10);
if (num < 10000) return 1000 * (num %10) + reverse(num/10);
if (num < 100000) return 10000 * (num %10) + reverse(num/10);
if (num < 1000000) return 100000 * (num %10) + reverse(num/10);
if (num < 10000000) return 1000000 * (num %10) + reverse(num/10);
if (num < 100000000) return 10000000 * (num %10) + reverse(num/10);
return 100000000 * (num %10) + reverse(num/10);
}
int main(int argc, char **argv)
{
unsigned long num, rev;
if (argc < 2) return 1;
sscanf(argv[1], "%lu", &num);
rev = reverse(num);
printf("%lu -->> %lu\n", num, rev );
return 0;
}
Or, using a helper function (not a variable)
[note: this has quadratic complexity(on the number of digits)]
unsigned long tencount(unsigned long num)
{
if (num < 10) return 1;
return 10 * tencount( num/10);
}
unsigned long reverse2(unsigned long num)
{
if (num < 10) return num;
return tencount(num) * (num %10) + reverse2(num/10);
}
Assuming a 32bit long you could do it without loops or recursion;
long GetReverse(unsigned long n)
{
unsigned long x = ((n/1000000000) +
((n/100000000)%10)*10 +
((n/10000000)%10)*100 +
((n/1000000)%10)*1000 +
((n/100000)%10)*10000 +
((n/10000)%10)*100000 +
((n/1000)%10)*1000000 +
((n/100)%10)*10000000 +
((n/10)%10)*100000000 +
((n)%10)*1000000000);
return (x/(9*(x%10==0)+1)/
(9*(x%100==0)+1)/
(9*(x%1000==0)+1)/
(9*(x%10000==0)+1)/
(9*(x%100000==0)+1)/
(9*(x%1000000==0)+1)/
(9*(x%10000000==0)+1)/
(9*(x%100000000==0)+1)/
(9*(x%1000000000==0)+1));
}
This is a solution:
int reverse(int i) {
static int p = 0;
if (i==0) { int r = p; p = 0; return r; }
p = 10*p+i%10;
return reverse(i/10);
}
Idea is to use a second argument, but as it is used only to store the partial result a static variable can be used. To be able to reuse the function you just need to reset the static at the end of the recursion.
Becareful as such a function is not an involution means that reverse(reverse(x)) not equals to x, think about x=1000. If you want involution then you need to define it over a C-string that represent the value.
C reverse a number recursively
I have an assignment to create a function that receives a number and return the reversed number.
No loops allowed, and the input is only the number .
Add a helper recursive function. #Art
No static variable, no floating point math needed.
The below meets the goals:
1) Recursion used.
2) Function receives a number and return the reversed number
3) No loops allowed, and the input is only the number
#include <stdio.h>
#include <stdlib.h>
static unsigned reverse_helper(unsigned x, unsigned *pow10) {
if (x < 10) {
*pow10 = 10;
return x;
}
unsigned y = reverse_helper(x / 10, pow10);
y += *pow10 * (x%10);
*pow10 *= 10;
return y;
}
unsigned reverse(unsigned x) {
unsigned pow10 = 1;
unsigned y = reverse_helper(x, &pow10);
printf("%10u %10u\n", x, y);
return y;
}
int main(void) {
reverse(0);
reverse(9);
reverse(10);
reverse(99);
reverse(100);
reverse(1234);
reverse(123456789);
}
Output
0 0
1 1
9 9
10 1
99 99
100 1
1234 4321
123456789 987654321
A solution like OP's yet uses 2 recursive functions.
Recurse function with 1 parameter, no floating-point, no static variables.
// return the great power-of-10 less than n
unsigned long p10(unsigned long n) {
if (n < 10) {
return 1;
}
return p10(n/10) * 10;
}
unsigned long GetReverse(unsigned long n) {
if (n < 10) {
return n;
}
// OPs code
//return 10 * GetReverse(n / 10) + n % 10;
// v----------------v------------------- scale by 1
// | | v-----------v--- scale by a power of 10 <= n
return GetReverse(n / 10) + p10(n)*(n%10);
}
What about calling a function like char* getReverse(int n) So you could use mod and concatenation to obtain the reverse. Then in the caller method int getReverse(int n) you parse the string to int. You could use recursion and then the single line to make the parsing. No loops needed and one parameter.
Here's my completely reentrant version, with no extra variable. It works by using ldiv( num / 10 ) to get quotient and remainder, then returns the remainder multiplied by 10^(num digits in quotient) added to the reverse of the quotient (code is formatted to remove the scroll bar - normally I'd have blank lines and more braces):
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/* unsigned long power function */
unsigned long lpow( unsigned long base, unsigned long exp )
{
unsigned long result = 1UL;
while ( exp )
{
if ( exp & 1 )
result *= base;
exp >>= 1;
base *= base;
}
return( result );
}
/* count the number of decimal digits */
unsigned long numdigits( unsigned long num )
{
return( floor( log10( num ) ) + 1 );
}
unsigned long reverse( unsigned long in )
{
ldiv_t tmp = ldiv( in, 10UL );
if ( tmp.quot == 0 )
return( tmp.rem );
return( reverse( tmp.quot ) + tmp.rem * lpow( 10, numdigits( tmp.quot ) ) );
}
unsigned long lpow() function from https://stackoverflow.com/a/101613/4756299
unsigned long numdigits() function from https://stackoverflow.com/a/1068870/4756299
Called like this:
int main( int argc, char **argv )
{
for ( int ii = 1; ii < argc; ii++ )
{
unsigned long num = strtoul( argv[ ii ], NULL, 10 );
printf( "Reverse of %lu is %lu\n", num, reverse( num ) );
}
return( 0 );
}
For starters it is unclear why the return type is declared like long while the parameter has the type unsigned long.
long GetReverse(unsigned long n);
^^^^ ^^^^^^^^^^^^^
To have a more large of integers it is better to declare the parameter and the return type like unsigned long long int.
The function can be defined by using a local static variable that will keep the calculated reversed value.
Here it is.
unsigned long long int GetReverse(unsigned long long int n)
{
const unsigned long long int Base = 10;
static unsigned long long int reversed;
unsigned long long int tmp;
reversed = Base * reversed + n % Base;
return (n /= Base ) == 0 ? tmp = reversed, reversed = n, n = tmp, n
: GetReverse(n);
}
In the demonstrative program below there is shown how the function works.
#include <stdio.h>
unsigned long long int GetReverse(unsigned long long int n)
{
const unsigned long long int Base = 10;
static unsigned long long int reversed;
unsigned long long int tmp;
reversed = Base * reversed + n % Base;
return (n /= Base ) == 0 ? tmp = reversed, reversed = n, n = tmp, n
: GetReverse(n);
}
int main(void)
{
const unsigned long long int Base = 10;
for ( unsigned long long int i = 1, n = 0; i < Base; i++ )
{
n = Base * n + i;
printf( "%llu\n", n );
printf( "%llu\n", GetReverse( n ) );
putchar( '\n' );
}
return 0;
}
The program output is
1
1
12
21
123
321
1234
4321
12345
54321
123456
654321
1234567
7654321
12345678
87654321
123456789
987654321

Swapping some digits of a number in c programming

I have a number that I wish to sort. I know how to sort it in ascending and descending order, but what the question wants is to switch places value in the number.
try this
#include <stdio.h>
unsigned power(unsigned base, unsigned exp){
unsigned result = 1;
while(exp > 0){
if(exp & 1)
result = result * base;
base = base * base;
exp >>=1;
}
return result;//Overflow is not considered
}
int pow10(int exp){
return power(10, exp);
}
int get_num_at(int n, int pos){
int exp = pow10(pos);
return n / exp % 10;//Changed by advice of chux
}
int swap(int n, int pos1, int pos2){
if(pos1 == pos2)
return n;
int n1 = get_num_at(n, pos1);
int n2 = get_num_at(n, pos2);
return n - n1 * pow10(pos1) - n2 * pow10(pos2) + n1 * pow10(pos2) + n2 * pow10(pos1);
}
int length(int n){
int len = 1;
while(n /= 10)
++len;
return len;
}
int arrange(int v){
int len = length(v), half = len / 2;
return (len & 1) ? swap(v, 0, len-1) : swap(v, half-1, half);//0 origin
}
int main (void) {
int v;
scanf("%d", &v);
printf ("%d\n", arrange(v));
}
Continuing from my comment, to answer your question:
How would I modify the code below to get the above or do i have to start a new code?
I would start with a new approach. Why? While you could use a set of place-holders and set various conditions to manipulate the integer values to accomplish a mid-digit or end-digit swap depending on odd/even, it is far easier to simply convert your integer value to a string and then manipulate the characters.
Given you are working with integers, the longest integer you will have to address is INT_MIN (-2147483648), or 11-chars (+1 for the nul-terminating character). You can simply use a static character buffer of 12 chars and call sprintf to convert you integer to a string (while getting its length in the same call). A simple odd/even test and you know to either swap the middle characters or the end characters. To convert the resulting string back to integer, simply use strtol.
You can test for a negative value at the beginning, handle the positive form, and then multiply the resulting value by -1 for return if the value was negative. (note: you should also test for INT_MIN before assigning the positive form as -INT_MIN will not fit in an integer value. You must also check that the resulting integer after you swap digits will fit within an integer as well. -- that is left as an exercise for you).
Putting those pieces together, you can do something similar to:
#include <stdio.h>
#include <stdlib.h>
enum {BASE = 10, MAXS = 12}; /* constants */
int minswap (int v)
{
char buf[MAXS] = "";
int neg = v < 0 ? -1 : 1, /* flag negative numbers */
val = v * neg, /* handle as positive val */
len = sprintf (buf, "%d", val); /* conver to str, get len */
if (len % 2 == 0) { /* val is even */
int m = len / 2;
char tmp = buf[m - 1]; /* swap mid digits */
buf[m - 1] = buf[m];
buf[m] = tmp;
}
else {
char tmp = *buf; /* swap end digits */
*buf = buf[len - 1];
buf[len - 1] = tmp;
}
return (int)strtol (buf, NULL, BASE) * neg;
}
int main (void) {
int v1 = 264802,
v2 = 1357246;
printf (" %d => %d\n", v1, minswap(v1));
printf (" %d => %d\n", v2, minswap(v2));
return 0;
}
Example Use/Output
Using your test values:
$ ./bin/minswap
264802 => 268402
1357246 => 6357241
Look things over and let me know if you have any questions.
Without Library Function Usage
If you have a requirement to no use any of the C-library functions in your minswap function, you can easily replace them with loops with something similar to the following:
enum {BASE = 10, MAXS = 12}; /* constants */
int minswap (int v)
{
char buf[MAXS] = "";
int neg = v < 0 ? -1 : 1, /* flag negative numbers */
val = v * neg, /* handle as positive val */
len = 0;
while (len + 1 < MAXS && val) { /* convert to string get len */
buf[len++] = val % 10 + '0';
val /= 10;
}
/* (you should validate len > 0 here) */
if (len % 2 == 0) { /* val is even */
int m = len / 2;
char tmp = buf[m - 1]; /* swap mid digits */
buf[m - 1] = buf[m];
buf[m] = tmp;
}
else {
char tmp = *buf; /* swap end digits */
*buf = buf[len - 1];
buf[len - 1] = tmp;
}
while (len--) /* convert to int */
val = val * 10 + buf[len] - '0';
return val * neg;
}
(note: there is actually no need to convert to the character values with -/+ '0' since you are simply swapping the values at the mid or end positions, but for sake of completeness, that was included.)
Look things over and let me know if your have further questions.
Here is a solution without any standard library calls, arrays or strings, except for printing the result:
#include <stdio.h>
long long shuffle(int v) {
int i, n, x, d0, d1;
long long p;
/* compute the number of digits and the largest power of 10 <= v */
for (x = v, p = 1, n = 1; x > 9; x /= 10, p *= 10, n++)
continue;
if (n & 1) {
/* odd number of digits, swap first and last */
d0 = v % 10;
d1 = v / p;
return d0 * p + v % p - d0 + d1;
} else {
/* even number of digits, swap middle 2 digits */
for (i = 0, p = 1; i < n / 2 - 1; i++, p *= 10)
continue;
d0 = (v / p) % 10;
d1 = (v / p) / 10 % 10;
return v + p * (d0 - d1) * 9;
}
}
int main(void) {
printf("%d => %lld\n", 0, shuffle(0));
printf("%d => %lld\n", 1, shuffle(1));
printf("%d => %lld\n", 42, shuffle(42));
printf("%d => %lld\n", 24, shuffle(24));
printf("%d => %lld\n", 264802, shuffle(264802));
printf("%d => %lld\n", 1357246, shuffle(1357246));
return 0;
}
Output:
0 => 0
1 => 1
42 => 24
24 => 42
264802 => 268402
Notes:
I do not handle negative numbers
The reversed number might not fit in an int, so I used type long long, but on systems where int would have the same range as long long, you might still get an incorrect result.
Ive completed the assignment and my code is as below. It is a bit primitive, but it works thank you all for your contribution.
int swapvalues(int input, int digit)
{
int swapsort = 0; //initializes swapsort to 0
int lastdigit; //finds he last digit of input
int digits; //the total number of digits - 1
int firstdigit; //finds the first digit of the input
int middledigit; //finds the first middle digit in an even digit number
int secondmiddledigit; //finds the second middle digit in an even digit number
int firsthalf; //the first half of an even digit number
int firsthalf2; //the second half of an even digit number
int spacing; //the spacing between the output and the input
if(digit % 2 != 0)
{
lastdigit = input % 10;
digits = digit - 1;
firstdigit = (int)(input / pow(10, digits));
swapsort = lastdigit;
swapsort *= (int) pow(10, digits);
swapsort += input % ((int)pow(10, digits));
swapsort -= lastdigit;
swapsort += firstdigit;
}
else
{
firsthalf = input / pow(10, (digit / 2));
middledigit = firsthalf % 10;
firsthalf2 = input / pow(10, (digit / 2) - 1);
secondmiddledigit = firsthalf2 % 10;
spacing = (((secondmiddledigit * 10) + (middledigit)) - ((middledigit * 10) + (secondmiddledigit))) * pow(10, ((digit / 2) - 1));
swapsort = input + spacing;
}
return(swapsort);
}

Sort numbers according to n-th term

I know how to sort an array(i.e. bubble sort) but I don't have any idea how I can sort an array according to n-th term. Could you give me idea or example if there is? Thank you for all appreciated answer.
#edit: how can be the program sensed a number with zeros I mean for 1 program sense 0001 or 00001 .... ?
Example:
2 --> nth digit
4 45 62 1 900 105 --> inputs
Output:
001 004 105 900 045 065
void bubble_sort(int iarr[], int num) {
int i, j, k, temp;
printf("\nUnsorted Data:");
for (k = 0; k < num; k++) {
printf("%5d", iarr[k]);
}
for (i = 1; i < num; i++) {
for (j = 0; j < num - 1; j++) {
if (iarr[j] > iarr[j + 1]) {
temp = iarr[j];
iarr[j] = iarr[j + 1];
iarr[j + 1] = temp;
}
}
printf("\nAfter pass %d : ", i);
for (k = 0; k < num; k++) {
printf("%5d", iarr[k]);
}
}
}
The quick answer is that your comparison function needs to look at the n-th digit instead of the whole number.
So if your original comparison was something like:
if (a < b) // handle a before b case
elseif (b < a) // handle b before a case
you'll want to change it to be:
aDigit = getNthDigit(a, n);
bDigit = getNthDigit(b, n);
if (aDigit < bDigit) // handle a before b case
elseif (bDigit < aDigit) // handle b before a case
You'll also have to implement getNthDigit, which would involve integer division and modulus operators.
Take a look at qsort for what a generic sort function requires. For your specific question, look at the sort algorithm you want to implement (i.e. bubble sort), and replace comparisons of elements with a function call to an order function. Your compare function should then extract the second digit and compare those digits.
Based on your code, you should change if (iarr[j] > iarr[j + 1]) with if(comp_gt(iarr[j], iarr[j + 1])). And, I would implement comp_gt by
int comp_gt(int a, int b)
{
int a_second_digit = (a / 10) % 10;
int b_second_digit = (b / 10) % 10;
return (a_second_digit < b_second_digit);
}
It means that you sort the numbers based on their n-th digit.
In the example you have, you see that the bolded digits (the second digit in every number) are the ones who define the order of the output.
Here is an example on how you can solve it (I am tuning it right now, because the method it uses to find a digit is wrong):
#include <stdio.h>
#include <math.h>
void quickSort(int a[], int first, int last, int n_th);
int pivot(int a[], int first, int last, int n_th);
void swap(int* a, int* b);
int n_th_digit(int number, int n);
void print(int array[], const int N);
int main() {
int test[] = { 7, 9, 1, 3, 6, 5, 2, 4 };
int N = sizeof(test) / sizeof(int);
int n_th = 0; // digit(from the end) to sort by
printf("Size of test array : %d\n", N);
printf("Before sorting : \n");
print(test, N);
quickSort(test, 0, N - 1, n_th);
printf("After sorting : \n");
print(test, N);
return 0;
}
/**
* Quicksort.
* #param a The array to be sorted.
* #param first The start of the sequence to be sorted.
* #param last The end of the sequence to be sorted.
* #param n_th The digit to sort by
*/
void quickSort(int a[], int first, int last, int n_th) {
int pivotElement;
if (first < last) {
pivotElement = pivot(a, first, last, n_th);
quickSort(a, first, pivotElement - 1, n_th);
quickSort(a, pivotElement + 1, last, n_th);
}
}
/**
* Find and return the index of pivot element.
* #param a The array.
* #param first The start of the sequence.
* #param last The end of the sequence.
* #param n_th The digit to sort by
* For example the third digit of 137
* requires n_th to be 0.
*
*/
int pivot(int a[], int first, int last, int n_th) {
int i, p = first;
int pivotElement = a[first];
for (i = first + 1; i <= last; i++) {
if (n_th_digit(a[i], n_th) <= n_th_digit(pivotElement, n_th)) {
p++;
swap(&a[i], &a[p]);
}
}
swap(&a[p], &a[first]);
return p;
}
/**
* Swap the parameters.
* #param a The first parameter.
* #param a The second parameter.
*/
void swap(int* a, int* b) {
// You still can use the swap that
// does not uses an extra variable
// from the C++ implementation.
int temp = *a;
*a = *b;
*b = temp;
}
int n_th_digit(int number, int n) {
if (number < 0)
number *= -1;
return fmod((number / pow(10, n)), 10);
}
/**
* Print an array.
* #param a The array.
* #param N The size of the array.
*/
void print(int a[], const int N) {
int i;
for (i = 0; i < N; i++)
printf("array[%d] = %d\n", i, a[i]);
}
I got the how to find the n-th digit from here and the quicksort from here.
Replace
void bubble_sort(int iarr[], int num) {
....
if (iarr[j] > iarr[j + 1])
With
void bubble_sort(int iarr[], int num, int term) {
unsigned pow10 = upow10(term - 1);
....
if (compareu(iarr[j], iarr[j + 1], pow10) > 0)
// To calculate pow(10, x) quickly
static unsigned upow10(unsigned y) {
unsigned z = 1;
unsigned base = 10;
while (y) {
if (y & 1) {
z *= base;
}
y >>= 1;
base *= base;
}
return z;
}
int compareu(int a1, int a2, unsigned pow10) {
unsigned b1 = abs(a1);
unsigned b2 = abs(a2);
b1 = (b1 / pow10) % 10;
b2 = (b2 / pow10) % 10;
if (b1 > b2) return 1;
if (b1 < b2) return -1;
return (a1 > a2) - (a1 < a2);
}
[Edit] per OP's update
Q: how can be the program sensed a number with zeros I mean for 1 program sense 0001 or 00001?
A: That is part of the code that reads input which is not posted. If code needs to distinguish between "0001" and "00001", then the whole problem is one of strings and not integers. In that case save each element as a string and do compares from a textual point-of-view.
Yet I suspect that is not the true coding goal. Simply use arithmetical compares and not be concerned with differing leading zeros.
The printf() function is another matter. To print at least term digits with leading 0, use "%0*d".
term = 2; // or 6 or 9, etc.
// printf("%5d", iarr[k]);
printf("%0*d ", term, iarr[k]);

Resources