0

I am using the following portal to verify the results of my code (again sourced from the web):

RapidTables BaseConverter

My code is as shown below:

// C program to convert a number from any base 
// to decimal 
#include <stdio.h> 
#include <string.h> 
  
// To return value of a char. For example, 2 is 
// returned for '2'.  10 is returned for 'A', 11 
// for 'B' 
int val(char c) 
{ 
    if (c >= '0' && c <= '9') 
        return (int)c - '0'; 
    else
        return (int)c - 'A' + 10; 
} 
  
// Function to convert a number from given base 'b' 
// to decimal 
int toDeci(char *str, int base) 
{ 
    int len = strlen(str); 
    int power = 1; // Initialize power of base 
    int num = 0;  // Initialize result 
    int i; 
  
    // Decimal equivalent is str[len-1]*1 + 
    // str[len-1]*base + str[len-1]*(base^2) + ... 
    for (i = len - 1; i >= 0; i--) 
    { 
        // A digit in input number must be 
        // less than number's base 
        if (val(str[i]) >= base) 
        { 
           printf("Invalid Number\n"); 
           return -1; 
        } 
  
        num += val(str[i]) * power; 
        power = power * base; 
    } 
  
    return num; 
} 
  
// Driver code 
int main() 
{ 
    char str[] = "25a"; 
    int base = 36; 
    printf("Decimal equivalent of %s in base %d is " " %d ", str, base, toDeci(str, base)); 
    return 0; 
}

As shown inside main(), if use the value "25a" for str[], I get the following output:

Invalid Number
Decimal equivalent of 25a in base 36 is  -1

But if I change the value of str[] to "25A", I get the following output:

Decimal equivalent of 25A in base 36 is  2782

Using the portal link that I have provided above for result verification, I get the last result for both values.

So my question is, how can I modify my code to make the corresponding change?

TIA

Vinod

Vinod
  • 925
  • 8
  • 9
  • See the `'A'` in the `val` function? Do you know what that part is doing and does it not give you a good clue to what needs to be done to support lower case letters? – kaylum Jun 16 '21 at 04:08
  • @kaylum I know that it is the ascii value, but couldn't figure out the algo based on the code hence thought of posting – Vinod Jun 16 '21 at 04:10
  • Alternatively you can normalise the string to contain capital letters before using it in the `toDeci` or `val` function. – kaylum Jun 16 '21 at 04:10
  • `return (int)c - 'A' + 10;` should probably be `return toupper(c) - 'A' + 10;` – Jerry Jeremiah Jun 16 '21 at 04:12
  • @JerryJeremiah I am wary of introducing another header file because I had to indulge in this exercise to work around compilation errors in proprietary driver code due to stdlib.h inclusion arising from strtoul()..just saw this logic as const char OFFSET = 'a' - 'A'; as the generic workaround in another SO post; so want to try that first – Vinod Jun 16 '21 at 04:17
  • Just as a warning, the `int num` may overflow in case of bigger numbers. – JASLP doesn't support the IES Jun 16 '21 at 04:17
  • @JustASimpleLonelyProgrammer in actual code, I would have to replace with unsigned long long – Vinod Jun 16 '21 at 04:19

2 Answers2

1

Why don't you make use of strtoll() function:

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

int main()
{
    char str[] = "25a";
    int base = 36;
    unsigned long long todeci;

    todeci = strtoll(str, (char **)NULL, base);
    printf("Decimal equivalent of %s in base %d is %lld\n", str, base, todeci);
    return 0;
}

Output:

Decimal equivalent of 25a in base 36 is 2782
tshiono
  • 21,248
  • 2
  • 14
  • 22
0

If you can't or don't want to change the function signatures or use the proper library functions to perform the conversion, a simple change to the val function would allow the code to also manage the lower cases.

int val(char c) 
{ 
    if ( '0' <= c  &&  c <= '9') 
        return c - '0'; 
    else if ( 'A' <= c  &&  c <= 'Z' )
        return c - 'A' + 10;
    else if ( 'a' <= c  &&  c <= 'z' )
        return c - 'a' + 10;
    else
        return -1;
} 

A little change to the other function (using the Horner method to evaluate the polynomial) and we can also avoid a call to strlen.

int toDeci(char *str, int base) 
{ 
    unsigned long long int num = 0;
    
    while( *str != '\0' )
    {
        int digit = val(*str);
        if ( digit == -1  ||  digit >= base )
        {
            printf("Invalid digit.\n");
            return -1;
        }
        unsigned long long int n = num * base + digit;
        if ( n < num )
        {
            printf("The number is too big.\n");
            return -1;
        }
        num = n;
        ++str;
    }
    if ( num > INT_MAX )  // You'll have to include <limits.h>
    {
        printf("The number is too big to fit into an int.\n");
        return -1;
    }
    return num; 
}

Note that this code still can't process negative numbers or prefixes like 0 for octals and 0x for hexadecimal numbers. The error checking also follows OP's choice (returning -1 when something goes wrong) and needs to be rethinked.

Bob__
  • 12,361
  • 3
  • 28
  • 42