2

What I want to do in C is swap two digits in a double.

For example, if the input is 54321.987 and I want to swap the 2nd with the 4th digit, the output should be 52341.987.

Example when too small: 12.34 would output 1002.34.

ryachza
  • 4,460
  • 18
  • 28
  • 11
    Stringify it. Swap the chars, unstringify it. sprintf(), sscanf(). – Martin James Oct 04 '17 at 12:50
  • If it is a programming assignment and you don't want to stringify it. First extract all digits using the modulo 10 function on reminders. Then check for 2nd and 4th digit accordingly. For example: In a number n=12345.678. Extract decimal part using `n-n%1` Get last digit with `n-n%10` and then divide n with 10, similarly get next digit and so on. – Om Sao Oct 04 '17 at 12:53
  • 1
    ..or you could do some explicit, nasty loopy/recursivey thing with mult/div by 10 repeatedly. – Martin James Oct 04 '17 at 12:53
  • @OmSao `n%1` would break the constraint ["The operands of the % operator shall have integer type."](http://port70.net/~nsz/c/c11/n1570.html#6.5.5p2), unless you've omitted something. – Ilja Everilä Oct 04 '17 at 12:57
  • @llja: Eeee.. missed the point in hurry. Thanks mate for pointing out !! – Om Sao Oct 04 '17 at 12:58
  • 1
    ... but there is, of course, the standard `fmod()` function for floating-point modulus. – John Bollinger Oct 04 '17 at 13:03
  • With many initial `double`, the constructed `double` will not meet expectations due to rounding. – chux - Reinstate Monica Oct 04 '17 at 14:08

7 Answers7

1

Using stringification approach:
There are more elegant ways, but you can see the steps (and improve on) this pseudo code to stringify, move values, and convert back to number.

char buf1[20];
char buf2[20];
char *dummy;
double val = 54321.987;

sprintf(buf1, "%9.3f", val );
//Now the number is in string form: "54321.987".  Just move the two elements  
buf2[0]=buf1[0];
buf2[1]=buf1[3];
buf2[2]=buf1[2];
buf2[3]=buf1[1]; //and so on
//now convert back:

val = strtod(buf2, &dummy);
printf("%9.3f\n", val);

Or, a function could be used to do essentially the same thing: (still stringification)

double swap_num_char(double num, int precision, int c1, int c2); //zero index for c1 and c2


int main(void)
{

    double val = 54321.987;

    printf("%9.3f\n", swap_num_char(val, 3, 1, 3));

    return 0;   
}

double swap_num_char(double num, int precision, int c1, int c2)
{
    char buf[25]; 
    char format[10];
    char *dummy;
    char c;

    sprintf(format, "%s0.%df", "%", precision);

    sprintf(buf, format, num);

    c = buf[c1];
    buf[c1] = buf[c2];
    buf[c2] = c;

    num = strtod(buf, &dummy);

    return num;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
0

If you want input number to be double then you can do something like this:

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

    int main()
    {
        double numbergiven = 56789.1234;
        double dummy;
        double _4th_digit = (10*modf(numbergiven/10000, &dummy)) - modf(numbergiven/1000, &dummy);
        double _2th_digit = (10*modf(numbergiven/100, &dummy)) - modf(numbergiven/10, &dummy);
        numbergiven = numbergiven - (_4th_digit * 1000) + (_2th_digit * 1000);
        numbergiven = numbergiven + (_4th_digit * 10) - (_2th_digit * 10);
        printf("%lf",numbergiven);
        return 0;
    }

If you are not familiar with modf then you can simply do it this way:

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

    int main()
    {
        double numbergiven = 56789.1234;
        int number = numbergiven;
        int _4th_digit = (number/1000) - (10*(number/10000));
        int _2th_digit = (number/10) - (10*(number/100));
        numbergiven = numbergiven - (_4th_digit * 1000) + (_2th_digit * 1000);
        numbergiven = numbergiven + (_4th_digit * 10) - (_2th_digit * 10);
        printf("%lf",numbergiven);
        return 0;
    }
Mandar Sadye
  • 689
  • 2
  • 9
  • 30
0

You can get the two digits you're interested in with simple operations:

You can do so with

double x = 54321.987;
double tens = ((int)(x / 10)) % 10;        // Result is 2
double thousands = ((int)(x / 1000)) % 10; // Result is 4

Then you can subtract out the digits from their original place, and add them back in a new place:

x = x - (tens * 10.0) - (thousands * 1000.0); // result is 50301.987
x = x + (tens * 1000.0) + (thousands * 10.0); // result is 52341.987

Now just reduce the expression:

x = x + tens * (1000.0 - 10.0) - thousands * (1000.0 - 10.0);

This leaves you with a final expression:

x += (tens - thousands) * 990.0;

Or, if you don't want the intermediate variables:

x += (((int)(x/10))%10 - ((int)(x/1000))%10) * 990;
abelenky
  • 63,815
  • 23
  • 109
  • 159
0

One solution would be to extract the digits, then swap them.

You extract the digits (from positive numbers, at least) by using floor():

int place1 = 1; /* 0-based*/
double desiredPowerOf10 = powersOf10[place1];
double nextPowerOf10 = powersOf10[place1 + 1];
double digit1 = floor(number / desiredPowerOf10) - floor(number/nextPowerOf10) * 10;

You can then subtract the digits and add them back with the different powers:

double digitsRemoved = number - (digit1 * power1 + digit2 * power2);
double digitsSwapped = digitsRemoved + digit1 * power2 + digit2 * power1;

This may be susceptible to loss of precision with very large numbers, though.

0

1 - Use modf() to break the number into whole and fractional parts.

double modf(double value, double *iptr);

The modf functions break the argument value into integral and fractional parts, C11 §7.12.6.12

2 - Print the whole number part as a string and do the swap.

3 - Reconstruct

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

double swap2_4digit(double x) {
  if (signbit(x)) {
    return -swap2_4digit(-x);
  }
  printf("Before %f\n", x);
  double ipart;
  double fpart = modf(x, &ipart);
  //       ms_digit    digits  '.'  '\0'  min_size  
  char buf[1 + DBL_MAX_10_EXP + 1 +  1   + 4];  // Insure buffer is big enough

  strcpy(buf, "0000");  // Handle small numbers
  sprintf(buf + strlen(buf), "%.0f", ipart);
  size_t len = strlen(buf);
  char ch = buf[len - 2];
  buf[len - 2] = buf[len - 4];
  buf[len - 4] = ch;

  x = atof(buf) + fpart;
  printf("After  %f\n", x);
  return x;
}

int main(void) {
  swap2_4digit(54321.987);
  swap2_4digit(12.34);
}

Output

Before 54321.987000
After  52341.987000
Before 12.340000
After  1002.340000

Something left for OP. Make general for other digit positions.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Double is stored in a memory as a sequence of bits, but you want to operate with decimal digits. Doing this with double variable you may not receive the original digits because of floating-point arithmetic.

Therefore, you should manipulate with string representation of double. The main aspect is how many digits string will contain. But it's obvious that you get number from input. Scan it as string, not as double.

There is a working code:

#include <stdio.h>
#include <stddef.h>

#define BUFSIZE 255

void swap_digits(char *str, int n, int m) {
    char *digit1 = NULL;
    char *digit2 = NULL;

    int count = 0;
    while (*str && (!digit1 || !digit2)) {
        if (*str != '.') {
            count++;
            if (count == n) {
                digit1 = str;
            }
            if (count == m) {
                digit2 = str;
            }
        }

        str++;
    }

    if (digit1 && digit2) {
        char tmp = *digit1;
        *digit1 = *digit2;
        *digit2 = tmp;
    }
}

int main(void) {
    char buffer[BUFSIZE];
    scanf("%s", buffer);

    // it is preferably to validate input

    swap_digits(buffer, 2, 4);
    printf(buffer);
    return 0;
}
boriaz50
  • 860
  • 4
  • 17
0

or use fmod() @John Bollinger.

The fmod functions compute the floating-point remainder of x/y.

Extract the 2 digits each with the difference of modding with 10place and modding with 10place-1.

Subtract the 2 digits and then add them back swapped.

double swap_digit(double x, unsigned a, unsigned b) {
  printf("Before %f\n", x);
  double a_place = pow(10.0, a);
  double b_place = pow(10.0, b);
  double scaled_digit_a = fmod(x, a_place) - fmod(x, a_place/10);
  double scaled_digit_b = fmod(x, b_place) - fmod(x, b_place/10);
  x -= scaled_digit_a + scaled_digit_b;
  x += scaled_digit_a/a_place*b_place + scaled_digit_b/b_place*a_place;
  printf("After  %f\n", x);
  return x;
}

int main(void) {
  swap_digit(54321.987,2,4);
  swap_digit(12.34,2,4);
}

Output

Before 54321.987000
After  52341.987000
Before 12.340000
After  1002.340000
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256