9

Suppose I have

int n=123456;
int x,y=0;

How do I split the integer "n" in two half.

Note : The Total Number of digits in n will always be multiple of 2, e.g. 1234, 4567, 234567, 345621 etc... all have 2,4,6,8 digits. I want to divide them in half.

I am trying with following Code but it's not working, the y variable is holding reversed second part somehow.

int x, y=0, len, digit;
int n=123456;

len=floor(log10(abs(n))) + 1;
x=n;
while((floor(log10(abs(x))) + 1)>len/2)
{
    digit=x%10;
    x=x/10;
    y=(y*10)+digit;
}
printf("First Half = %d",x);
printf("\nSecond Half = %d",y);

When Input is :

n=123456;

Output I am getting :

First Half = 123
Second Half = 654

Output I want :

First Half : 123

Second Half : 456

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Prateek
  • 189
  • 1
  • 3
  • 13
  • Please guide me , can't we do something like this ? first convert int to string via sprintf and then substring it and then convert back to int ?? How to do this ? – Prateek Aug 14 '15 at 18:48
  • Your question is very unclear. Perhaps if you get it right, you will find the answer yourself already. – too honest for this site Aug 14 '15 at 18:48
  • 1
    I said the number of digits in the number .. both have 4 and 6 digits which are multiple of 2 – Prateek Aug 14 '15 at 18:49
  • 1
    @Eugene you're missing some code here. Nothing in the above example would give 654, or any value other than the initial 0, to `y` – Paul Roub Aug 14 '15 at 18:51
  • @PaulRoub: Please also take another look. I aalready edited my comment. Stiil, it is unclear what he means by "split into two halves. Upper/lower decimal digits? Upper/lower 16/32 bits? – too honest for this site Aug 14 '15 at 18:52
  • Please give a clear example: input and required output. – Weather Vane Aug 14 '15 at 18:54
  • @Olaf I just want to split 123456 into two , 1st = 123 and 2nd = 456 , half half .. – Prateek Aug 14 '15 at 18:55
  • 1
    Please put this essential info **in your question**. – Weather Vane Aug 14 '15 at 18:56
  • ..else we get REALLY confused. For instance, half of 123456 is 61728. The skilled and experienced engineers on SO need to be told quite clearly what you are intending to do, after all, the machines they program have to be told exactly what to do. – Martin James Aug 14 '15 at 19:17

7 Answers7

12

Here is a demonstrative program. It does not use any function except printf.:) Thus it is the simplest solution.

#include <stdio.h>

int main( void )
{
    unsigned int a[] = { 12, 1234, 123456, 12345678, 1234567890 };
    const unsigned int Base = 10;

    for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
    {   
        unsigned int divisor = Base;
        while ( a[i] / divisor > divisor ) divisor *= Base;

        printf( "%u\t%u\n", a[i] / divisor, a[i] % divisor );
    }        
}

The program output is

1       2
12      34
123     456
1234    5678
12345   67890

If you are going to use a signed integer type and negative numbers then the program can look the following way

#include <stdio.h>

int main( void )
{
    int a[] = { -12, 1234, -123456, 12345678, -1234567890 };
    const int Base = 10;

    for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
    {   
        int divisor = Base;
        while ( a[i] / ( a[i] < 0 ? -divisor : divisor ) > divisor ) divisor *= Base;

        printf( "%d\t%d\n", a[i] / divisor, a[i] % divisor );
    }        
}

Its output is

-1      -2
12      34
-123    -456
1234    5678
-12345  -67890
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
4

Here is actually what I would do

#include <stdio.h>
#include <math.h>

int main(void)
{
  int x, y=0, len, digit;
  int n=123456;

  len=floor(log10(abs(n))) + 1;
  x = n / pow(10, len / 2);
  y = n - x * pow(10, len / 2;
  printf("First Half = %d",x);
  printf("\nSecond Half = %d",y);
}
Swann
  • 2,413
  • 2
  • 20
  • 28
  • Thanks did my work :) You are the best ... thanks a lot .. God Bless you – Prateek Aug 14 '15 at 19:01
  • 3
    Actually, operating on floating-point values is a pretty poor solution when the problem is about integers. – The Paramagnetic Croissant Aug 14 '15 at 19:03
  • You edited your first code :) ,, your first code was better than reversing the string again .. it's bit lengthy .. .Why you removed your first code bro ? it was working fine... – Prateek Aug 14 '15 at 19:03
  • Oh! I see .. but reversing the int again is little bit childish and not looking like professional :\ any other way other than this ? – Prateek Aug 14 '15 at 19:05
  • I edited it again, but I actually you were trying to get 123 654 so I added a `reverse` function. But then I realized you actually wanted 123 456. – Swann Aug 14 '15 at 19:05
  • @TheParamagneticCroissant I totally support your answer, I actually used his line of code to save me some time. Otherwise I would have simple used a while loop to find the number of digits. – Swann Aug 14 '15 at 19:08
3

This can be done by division an modulus operators with the divider, that is 10(NumberOfDigits/2).

#include <stdio.h>

int getNumberOfDigits(int n)
{
    int counter = 0;
    for (; n > 0; n /= 10)
        counter++;
    return counter;
}

int main(void)
{
    int n = 123456;

    int divider = 1;
    for (int i = 0; i < getNumberOfDigits(n) / 2; i++) {
        divider *= 10;
    }
    printf("%d, %d\n", n / divider, n % divider);

    return 0;
}
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
1

Another possibility:

// split an int value into two pieces with the same number of decimal
// digits in each piece.  a couple of examples to demonstrate the output
//     iVal          iTop           iBot
//     1234            12             34
//   123456           123            456
void split_int (int iVal, int *iTop, int *iBot)
{
    int iTopx = iVal;   // save a copy of the value to be split later

    // start with assuming two decimal digits. if value is zero will still work.
    // we will then keep shifting the value right by two decimal digits as
    // we increment our divisor by one decimal digit so that we can create
    // a divisor we can then use to split the value using integer division
    // to get the top half and remainder of integer division for the bottom half.

    int iTen = 10;   // divisor value to split two decimal digits
    iVal /= 100;     // shift value right by two decimal digits
    while (iVal) {   // check to see if we are done, if not continue counting
        iTen *= 10;  // increase the divisor value we will use to split digits
        iVal /= 100; // shift value right by two decimal digits
    }

    *iTop = iTopx / iTen;  // split off top part by dividing by divisor
    *iBot = iTopx % iTen;  // split off bottom part by taking remainder
}

// test harness for the function above to try out several input data variations
// and print the results.  This is a Visual Studio Windows Console Application
// so the entry point is _tmain().
int _tmain(int argc, _TCHAR* argv[])
{
    int iTop, iBot, iVal;

    printf ("    iVal       iTop        iBot\n");    // output heading

    split_int ((iVal = 123456), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    split_int ((iVal = 12345), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    split_int ((iVal = 12), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    split_int ((iVal = 0), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    split_int ((iVal = 1234567890), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    split_int ((iVal = -1234567890), &iTop, &iBot);
    printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);

    return 0;
}

which produces the output of

    iVal       iTop        iBot
   00123456   00000123    00000456
   00012345   00000012    00000345
   00000012   00000001    00000002
   00000000   00000000    00000000
   1234567890   00012345    00067890
   -1234567890   -00012345    -00067890
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
0

The easiest way to do this is with the sprintf function. This takes a value and formats it according to the provided specifier. Once you have your integer represented as a string, you simply take each half of your string. Using sscanf, you reverse the process back to integer.

void print_both_halves(int x) {
    char str[80]; // magic number lengths
    char tmp[80];
    int len;
    int a, b;

    len = sprintf(str, "%d", x); // returns the number of chars written

    strncpy(tmp, str, len/2);
    tmp[len/2] = '\0';
    sscanf(tmp, "%d", &a); // gets the first half

    strncpy(tmp, &(str[len/2]), len/2); // copies from the middle of str
    tmp[len/2] = '\0';
    sscanf(tmp, "%d", &b); // gets the second half
}
mfsiega
  • 2,852
  • 19
  • 22
  • Thanks but in your code tmp is string datatype and I want the resultant in integer data type so that I can do more calculations later – Prateek Aug 14 '15 at 19:00
  • Use atoi() to convert the two strings back to an integer – Robert Jacobs Aug 14 '15 at 19:01
  • 1
    this is a problem about numbers, you shouldn't be using strings for solving it. – The Paramagnetic Croissant Aug 14 '15 at 19:07
  • Why did you assign `tmp = strncpy(...)`? `tmp` is not modifiable, the function return value is for convenience so you can pass it to another function in a compound statement. This gives a compilation error. – Weather Vane Aug 14 '15 at 19:07
  • @Weather Vane I don't actually have a compiler on hand, but I would've thought it was modifiable (it's not static, const, or anything else)? regardless, you're right, better style at the very least – mfsiega Aug 14 '15 at 19:11
  • You don't null-terminate `tmp` (twice). Passing a potentially not null-terminated string to `sscanf()` is UB. There are also lots of online compilers available nowadays ([1](http://coliru.stacked-crooked.com/), [2](http://melpon.org/wandbox/), [3](http://rextester.com/runcode), …) – cremno Aug 14 '15 at 19:16
  • @cremno good call! (albeit entirely moot, since this answer is buried pretty far down) misread the strncpy spec; it's been a while. – mfsiega Aug 14 '15 at 19:19
  • @mfrankli `tmp` is a local var with a fixed address on the stack. You can't just assign another value to it. `tmp` is not a pointer. – Weather Vane Aug 14 '15 at 19:44
  • This seems to go against popular opinion here, but I actually *like* the idea of doing this with strings. Computers have no concept of decimal numbers internally, so splitting a `2*n` length decimal number in "half" is essentially a string problem unless there's some mathematical significance I'm missing. In a language with better string handling, e.g. Python, your approach is 2 lines of code, but even in C, it's much clearer to the *reader* of the code what's going on. That said, doing it numerically is likely faster. – Brian McFarland Aug 14 '15 at 20:47
0

Since this seems to be a problem about numbers, more specifically integers, you shouldn't use either strings or floating-point operations.

int n = 123456;

int digits = 0;
int m = n;
while (m) {
    digits++;
    m /= 10;
}

digits /= 2;
int tmp = 0, lower_half = 0;
while (digits--) {
    tmp *= 10;
    tmp += n % 10;
    n /= 10;
}

while (tmp) {
    lower_half *= 10;
    lower_half += tmp % 10;
    tmp /= 10;
}

Here, n contains the upper half of the digits, lower_half the lower ones.

0

Another variation on using strings to do the split:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int split( int val, int *top, int *bot )
{
  char  tmp[23]; // should be large enough to hold a 64-bit decimal integer
                 // plus sign plus 0 terminator
  char  low[12] = {0};
  char high[12] = {0};

  if ( val < 0 )
    val = -val;

  sprintf( tmp, "%d", val );
  if ( strlen( tmp ) % 2 )
    return 0;

  strncpy( low, tmp, strlen( tmp ) / 2 );
  strncpy( high, tmp + strlen( tmp ) / 2, strlen( tmp ) / 2 );

  *top = (int) strtol( low, NULL, 10 );
  *bot = (int) strtol( high, NULL, 10 );

  return val;
}

int main( int argc, char **argv )
{
  if ( argc < 2 )
  {
    fprintf( stderr, "USAGE: %s integer_value_with_even_number_of_digits\n", argv[0] );
    exit( 0 );
  }

  int val = (int) strtol( argv[1], NULL, 10 );
  int lo, hi;

  if ( split( val, &lo, &hi ) )
    printf( "val: %d, lo: %d, hi: %d\n", val, lo, hi );
  else
    fprintf( stderr, "USAGE: %s integer_value_with_even_number_of_digits\n", argv[0] );

  exit( 0 );
}

Some sample runs:

[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 1
USAGE: ./splitter integer_value_with_even_number_of_digits
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 12
val: 12, lo: 1, hi: 2
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -12
val: -12, lo: 1, hi: 2
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -123
USAGE: ./splitter integer_value_with_even_number_of_digits
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -1234
val: -1234, lo: 12, hi: 34
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 12345678
val: 12345678, lo: 1234, hi: 5678
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -1234567890
val: -1234567890, lo: 12345, hi: 67890
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 012
val: 12, lo: 1, hi: 2
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 00123456
val: 123456, lo: 123, hi: 456
[fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 001234567
USAGE: ./splitter integer_value_with_even_number_of_digits

You didn't mention whether values had to be positive or not, or whether leading zeros count against the number of digits (since it's read as an integer value and not a string, there are no leading zeros after the conversion).

To me, this code has the virtue of simplicity. We're essentially treating the number as a string of digits to split down the middle, so (in my mind at least), using string operations seemed the most straightforward. Performance-wise, this shouldn't be any slower than using log to get the digits and looping through them.

John Bode
  • 119,563
  • 19
  • 122
  • 198