C programming language (K&R Second Edition): exercise 3-4

Title: in the complement representation of number to two, the itoa function we write cannot handle the largest negative number, that is, n is equal to - (2 ^ (word length - 1))

The situation. Please explain why. Modify the function so that it prints the correct value when running on any machine.

The itoa function in the book is as follows:

#include <stdio.h>
#include <string.h>
 
void itoa(int n, char s[])
{
    int i, sign;
    
    if((sign = n) < 0)
        n = -n;
    i = 0;
    do
    {
        s[i++] = n % 10 + '0';
    }
    while((n /= 10) > 0);
    if(sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}

void reverse(char s[])
{
    int c, i, j;
    
    for(i = 0, j = strlen(s) - 1; i < j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

Use the following code to test the maximum negative number

int main()
{
    char s1[20] = {'\0'};
    itoa(-2147483648, s1);
    printf("%s\n", s1);
}

The test results are:

-(

Self answer:

For the case of the maximum negative number, the complement of a = -2147483648 is expressed as 1000000000000000

The process of finding the opposite number is "reverse by bit plus 1", that is, 011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111=  

1000000000000000000000000000. So the value of - a printed out is the same as a- The measured result of a% 10 is - 8. Therefore, the first character converted is - 8 + '0', which is "("

Improve the program to run on any computer:

The first idea is to extend long int to int data, but the bit width of long int and int may be the same, and considering that the bit width occupied by different data types in different computer systems may also be different, I don't think this is a good method.

The second idea is to deal with the minimum negative value separately. In limit.h, it is defined that the minimum negative value of int type is INT_MIN. when it is the minimum negative value, add 1 to it, and after converting it into characters, add 1 to the first element in the array.

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

void reverse(char s[]);
 
void itoa(int n, char s[])
{
    int i, sign, temp;
    
    temp = n;
    if(n == INT_MIN)
        n = n + 1;
    if((sign = n) < 0)
        n = -n;
    i = 0;
    do
    {
        s[i++] = n % 10 + '0';
    }
    while((n /= 10) > 0);
    if(temp == INT_MIN)
        s[0] = s[0] + 1;
    if(sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}

void reverse(char s[])
{
    int c, i, j;
    
    for(i = 0, j = strlen(s) - 1; i < j; i++, j--)
    {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

int main()
{
    char s1[20] = {'\0'};
    int a = -2147483648;
    itoa(a, s1);
    printf("%s\n", s1);
}

The operation result is:

-2147483648

Reference answer:

/* itoa: convert n to characters in s - modified    */ 
void itoa(int n, char s[])
{
    int i, sign;
    
    sign = n;       /* record sign                  */
    i = 0;
    do              /* generate digits in reverse order */
    {
        s[i++] = abs(n % 10) + '0'; /* get next digit  */
    }
    while((n /= 10) != 0);          /* delete it        */
    if(sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}

  First, we must understand one fact:

-(2 ^ (word length - 1))

It cannot be converted to a positive number by n = -n; because the maximum integer that can be represented by the complement of 2 can only be

2 ^ (word length - 1) - 1

The idea of solving this exercise is to find the numbers in reverse order, and then use the function reverse (see exercises 1-19) The final result is obtained by inverting the characters in the string s. specifically, in this itoa function, we use the variable sign to save the initial value of n, and use the macro abs to calculate the absolute value of n%10. Just convert the result of the analog operation to a positive number, so that we can bypass the inability to convert negative numbers

-(2 ^ (word length - 1)) is converted to a positive number.

In addition, we also change the conditional expression in the do while statement from the original one

(n /= 10) > 0

Modified to (n / = 10)! = 0

This is to avoid putting itoa into an infinite loop because n is a negative number.

remarks:

The reference answer is based on the correct result obtained by finding the remainder of a negative number to 10, e.g. - 18% 10 = - 8

In the reference answer, the operation of directly finding the opposite number of n is avoided by finding the absolute value of n%10, which actually provides a solution for similar situations, that is, divide by 10 to reduce the value of data.

In addition, when n is a negative number, it will not fall into an infinite loop, but will only cycle once

Tags: C Back-end

Posted on Mon, 22 Nov 2021 00:38:06 -0500 by kwong