CS 162 Introduction to Computer Science Chapter 5 ASCII to Integer Conversion Herbert G. Mayer, PSU Status 11/9/2014 1 Syllabus #include <stdio.h> for getchar() Convert Decimal Digits to int Account for Sign Check integer Overflow on 16-Bit Maxint on 32-Bit 2 Specify a2i() Conversion Reading one input char at a time, assuming the character is a decimal digit ‘0’..’9’ Convert this ASCII string of decimal digits to its corresponding integral value For example, the incoming string “123” is converted to the integer hundred-and-twenty-three, i.e. 12310 Be aware that this input is indeed a sequence of ASCII character, not an integer value So we have to convert the digit ‘5’ for example to the integer value 5, by subtracting from character ‘5’ the value character ‘0’, and the difference is 5 Int value of ‘5’ is: ‘5’ – ‘0’ 3 Implement a2i() Conversion int a2i( void ) { // a2i int number = 0; while( ( ( c = getchar() ) >= '0' ) && ( c <= '9' ) ) { number = number * 10 + ( c - '0' ); } //end while return number; } //end a2i int main() { // main cout << “Enter a decimal number: ” << endl; cout << "The number was:” << a2i() << endl; return 0; } //end main 4 Discuss Code for a2i() Conversion The assumption in the code is that a sequence of decimal digits can be read However, if not a single digit is entered, the correct result of 0 is generated, due to initialization of number; see “int number = 0;” A crucial test is: ( c = getchar() ) >= '0' ... Here a side-effect happens: A character is read from standard in, and it is tested. Test becomes more complex, but no further input happens The current number is shifted left by 1 decimal position (multiply by 10) and the digit value is added 5 Account for Sign in a2i() Before reading one decimal digit at a time, check for optional negative sign ‘-’ or a redundant positive sign ‘+’ Former ‘-’ will change the resulting value, by inverting the sign State of ‘-’ has to be remembered; see variable neg The latter ‘+’ is silently skipped Once the sign is handled, proceed as before with the decimal digits that make the number 6 Implement Sign in a2i() int is_digit( char c ) { // is_digit return ( c >= '0' ) && ( c <= '9' ); } //end is_digit int a2i0( void ) { // a2i0 int number = 0; int neg = 0; if ( c == '-' ) { neg = 1; c = getchar(); }else if ( c == '+' ) { c = getchar(); } //end if while ( is_digit( c ) ) { number = number * 10 + ( c - '0' ); c = getchar(); } //end while return neg ? -number : number; } //end a2i0 7 Discuss Sign in a2i State variable neg is solely used to determine at the end, whether sign inversion happens Here we us a conditional expression: return neg ? -number : number; For the initial state of neg = 0, the decimal computed so far is returned But if neg is set to a non-zero state, the sign is inverted, all accomplished in a single conditional expression Note separation of the 2 options via the : and ? operators! 8 Specify Overflow in a2i() on 16-Bit Delicate programming matter, analyzed by sample of a fictitious 16-bit architecture On 16-bit computer the largest possible integer = 32767 On a two’s-complement architecture, the largest negative value = -32768 Both cases have to be handled, without the overflow actually occurring, so we probe the growing integer value, before the next multiply by 10, MAX10 = 3276 Also track, whether scanning a negative int literal, in which case the largest next decimal digit for 3276 is 8, versus the positive literal, for which largest next decimal digit fir 3276 is 7 9 Specify Overflow in a2i() on 16-Bit Scanning a positive decimal int literal: If number scanned so far is less than 3276, which is max 32767 / 10, then scanning 1 more digit is safe, do number = number * 10 + ( c-'0’ ); But if number scanned so far is in critical range 3276, then only some digits are safe, namely ‘0’..’7’ Else there will be positive overflow Scanning a negative decimal int literal: If number scanned so far is less than 3276, which is max 32767 / 10, then scanning 1 more digit is safe, do number = number * 10 + ( c-'0’ ); But if number scanned so far is in critical range 3276, then only some digits are safe, namely ‘0’..’8’ Else there will be negative overflow 10 Check for Overflow in a2i() #define MAX 32767 #define MAX10 3276 // i.e. integer divide 32767 / 10 = 3276 . . . int a2i1( void ) { // a2i int number = 0; int neg = 0; if ( c == '-' ) { neg = 1; c = getchar(); }else if ( c == '+' ) { c = getchar(); // keep neg = 0 } //end if while ( is_digit( c ) ) { if ( number > MAX10 ) { printf( "Overflow 1. max = %d\n", MAX ); }else if ( number == MAX10 ) { if ( c == '9' ) { printf( "Overflow 2. max = %d\n", MAX ); }else if ( c == '8' ) { if ( neg ) { number = -32768; }else{ printf( "Overflow 3. max = %d\n", MAX ); } //end if }else{ number = number * 10 + ( c - '0' ); } //end if }else{ number = number * 10 + ( c - '0' ); } //end if c = getchar(); } //end while return neg ? -number : number; } //end a2i 11 Discuss Overflow in a2i The critical number = number * 10 + next digit is performed only in safe state: For positive state, if the next digit after 3276 is ‘0’..’7’ one more iteration of the multiply is safe; yielding <= 32767 For negative state, if the next digit after 3276 is ‘0’..’8’ one more iteration of the multiply is safe; yielding >= -32768 Similarly on a 32-bit or today’s 64-bit computer; the scanner for integer literals needs to be safe, and detect integer overflow before it happens Common to have computers ignore integer overflow, so it may be safe to simply experience it, but the numeric value has to be safely scanned 12 Maxint on 32-Bit #include <iostream.h> main() { // main int expo; // shift 1 32 times unsigned long int pow = 1; // multiply repeatedly by 2 for ( expo = 1; expo <= 32; expo++ ) { pow = pow * 2; cout << " 2**" << expo << " = " << pow-1 << endl; } // end for cout << 0+4294967295 << endl; cout << 0-4294967295 << endl; } //end main 13 Maxint Output 2**1 = 1 2**2 = 3 2**3 = 7 . . . 2**14 = 16383 2**15 = 32767 2**16 = 65535 2**17 = 131071 2**18 = 262143 2**19 = 524287 2**20 = 1048575 2**21 = 2097151 2**22 = 4194303 2**23 = 8388607 2**24 = 16777215 2**25 = 33554431 2**26 = 67108863 2**27 = 134217727 2**28 = 268435455 2**29 = 536870911 2**30 = 1073741823 2**31 = 2147483647 2**32 = 4294967295 4294967295 1 14