Link to home
Start Free TrialLog in
Avatar of adinkins
adinkins

asked on

C++ Read Two Numbers in Base, Compute sum, print out

My starting code is in binary.  I just wanted to make it octal and add the numbers.

*/

#include <stdio.h>

short decimal2binary(unsigned long decimal_value, char

binary_value[32])
{
short index,significant_digits=0;
unsigned long temp_value;
for(index=31;index>=0;index--)
{
 // temp_value=decimal_value/pow(2,index)
 temp_value=decimal_value/(1<<index);
 if(temp_value>0)
 {
  binary_value[index]=(char)('0'+temp_value);
  // decimal_value=decimal_value%pow(2,index)
  decimal_value=decimal_value%(1<<index);
  if(!significant_digits)
   significant_digits=index;
 }
 else
 {
  binary_value[index]='0';
 }
}
return significant_digits;
}

short decimal2hex(unsigned long decimal_value, char hex_value[8])
{
short index,significant_digits=0;
unsigned long temp_value;
for(index=7;index>=0;index--)
{
 // temp_value=decimal_value/pow(16,index)
 temp_value=decimal_value/(1<<(index<<2));
 if(temp_value>9)
 {
  hex_value[index]=(char)('A'-10+temp_value);
  // decimal_value=decimal_value%pow(16,index)
  decimal_value=decimal_value%(1<<(index<<2));
  if(!significant_digits)
   significant_digits=index;
 }
 else if(temp_value>0)
 {
  hex_value[index]=(char)('0'+temp_value);
  // decimal_value=decimal_value%pow(16,index)
  decimal_value=decimal_value%(1<<(index<<2));
  if(!significant_digits)
   significant_digits=index;
 }
 else
 {
  hex_value[index]='0';
 }
}
return significant_digits;
}

void main()
{
short significant_digits,index;
char hex_value[8];
char binary_value[32];
/*
 * Hex conversion
 */
significant_digits=decimal2hex(0x0123FEDC,hex_value);
printf("0x0123FEDC = 0x");
/*
 * With leading zeros ...
 * for(index=8;index>=0;index--)
 */
for(index=significant_digits;index>=0;index--)
 printf("%c",hex_value[index]);
/*
 * Binary conversion next
 */
significant_digits=decimal2binary(0x0123FEDC,binary_value);
printf(" = 0b");
/*
 * Leading zeros...
 * for(index=31;index>=0;index--)
 */
for(index=significant_digits;index>=0;index--)
 printf("%c",binary_value[index]);
printf("\n");
}
ASKER CERTIFIED SOLUTION
Avatar of Salte
Salte

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of adinkins
adinkins

ASKER

That is still beyond me.  I'm a newbie.

A working code I came struggled with is below.  Now how would I do addition, example input two numbers in base 8 and then print the results?  I'm not sure whether I have to convert the numbers first.  Any suggestions..


 #include<stdio.h>

int main()
{
   int octal, number, decimal = 0;
   int highBit = 512, factor = 10000;

   printf( "Enter two numbers ( no more than 4 digits ) in base 8: " );
   scanf( "%o", &octal );

   number = octal;

   while ( highBit >= 7 )
   {
      decimal += octal / factor * highBit;
      highBit /= 8;
      octal %= factor;
      factor /= 10;
   }

   printf( "The decimal equivalent of %d is %d\n", number, decimal );

   return 0;
}

That is still beyond me.  I'm a newbie.

A working code I came struggled with is below.  Now how would I do addition, example input two numbers in base 8 and then print the results?  I'm not sure whether I have to convert the numbers first.  Any suggestions..


 #include<stdio.h>

int main()
{
   int octal, number, decimal = 0;
   int highBit = 512, factor = 10000;

   printf( "Enter two numbers ( no more than 4 digits ) in base 8: " );
   scanf( "%o", &octal );

   number = octal;

   while ( highBit >= 7 )
   {
      decimal += octal / factor * highBit;
      highBit /= 8;
      octal %= factor;
      factor /= 10;
   }

   printf( "The decimal equivalent of %d is %d\n", number, decimal );

   return 0;
}

oops!! i need to go back and review my math
The question of if you should convert to int before you add depends on how large the numbers are.

If the numbers will fit inside an int both before and after the add, then the easiest is to convert to int, do the math, convert back to string and output result.

If the numbers are big numbers then you can convert to a "bignum" which is an array of int values each holding a digit of the number in a radix R. The radix R is largely of your own choosing and you COULD let it be 10 and then essentially do the arithmetic on the strings directly.

Be aware that ASCII math is kinda complicated and inefficient though.

1. You do the operation for each digit, you therefore normally want to have as few digits as possible. A byte can hold values as high as 100 in a decimal based radix (1000 would be too much for a char type) but if you don't mind using non decimal based radix you can use radix 256 for a char type or even better use radix 65536 for a unsigned short type or 2^32 (2 raised to the power of 32) for an unsigned int (assuming sizeof(int) == 4).

2. ASCII holds the value with a bias of '0'. I.e. '1' isn't the same as 1 but is equal to '0' + 1. '9' == '0' + 9.

This means that '1' + '2' is not the same as '3' but is equal to '3' + '0'. so to add two values holding ascii digits you need to remember that '0' everywhere:

c = a + b - '0';

will almost correctly compute the sum of a and b if a and b are ascii digits.

The almost part is due to overflow, if a and b are '3' and '5' respectively, the above will correctly compute '8' but if a and b are '7' and '8' the result will be:

c = '7' + '8' - '0' == '?'

and obviously non-sense, so you need to check if the result c > '9' then you subtract 10 and add a carry of 1. This also means you should add the carry in in the first place:

c = a + b - '0' + carry;
carry = 0;

if (c > '9') {
   c -= 10;
   carry = 1;
}
and then you can compute the next digits.

This is for adding, for subtraction it is very much the same. When you do subtraction by hand you first compare if the value a is less than b and you then borrow if a is less than b and do not borrow if a >= b. This is not so easy to do by computer, it is much easier to always borrow and then get a carry if it is too much. That carry will cancel the borrow so you get correct result. For this reason it is good to start the subtraction by setting borrow to 1 before you start the loop.

c = a + 10 - 1 - b + carry;

The +10 is for the borrow from next higher digit, the -1 is for the reason that we did a borrow of +10 in previous lower digit and now we need to subtract a 1 for that. If we did get a carry from previous round it meant that we shouldn't have done that borrow and so we add the carry to cancel the borrow of -1. If the A operand (all digits) is >= B then you should get a final carry that would cancel the fact that we did a borrow of +10 on the highest digit which we did by borrowing 1 from the non-existent digit above the highest. Since that digit doesn't exist we should get a carry to cancel that borrow.

However, if A < B then we won't get a carry but in that case we subtract a large number from a smaller and so we should really switch it around and do (B - A) and mark the result as negative. Luckily the result is almost what we have. The only problem is that our result is R-complement of the true result. Let's use R == 10 and use the algorithm on 27 - 34 to illustrate:

carry = 1;
c0 = a0 + 10 - 1 + carry - b0 == 7 + 10 - 1 + 1 - 4 == 13
c0 = c0 - 10 == 3, carry = 1
c1 = a1 + 10 - 1 + carry - b1 == 2 + 10 - 1 + 1 - 3 == 9

the result is '93' and a carry of 0.

The carry of 0 indicate that A < B and the true result should have been: -(B-A) == -(34-27) == -7

If you add 7 and 93 you get exactly 100 and that is no coincidence. 93 is the '10-complement of 7' + 1 in 2 digits. In three digits it would have been 993 etc..

The 10 complement of 7 is 92 and +1 gets 93.

So this gives us a way to compute the right result in this case:

if (carry == 0) {
   replace each digit c with 9 - c.
   compute C = C + 1.
   correct result is -C.
}
The replace each digit c with 9-c and then add 1 can be done in one combined operation:

Scan from least significant digit and skip all '0'.

Since we got a negative result with carry == 0 at least one digit must differ from '0'.

The least digit c that is not '0' is then changed to 10-c:

c = 10 - (c - '0') + '0' == 10 + '0' + '0' - c;

Don't worry about the constants added together, a compiler will typically add them together at compile time so you get a decent one constant value in the final code. (This is usually referred to as constant folding).

For any digits higher than this least non '0' digit we compute:
c = 9 - (c - '0') + '0' == 9 + '0' + '0' - c;

and then mark the result as 'negative'.

if the value is stored in a string of length n then:

result_is_negative = (carry == 0);

if (result_is_negative) {
   int k = n;
   while (val[--k] == '0');
   // val[k] != '0'
   val[k] = 10 + '0' + '0' - val[k];
   while (--k >= 0)
      val[k] = 9 + '0' + '0' - val[k];
}

That code turns the '93' in our example to -7.

Aside from the fact that those '0' can be tricky to keep track of is the fact that when you have a raw number as input from user or file, the number some times contain formatting. For example extra decoration in front or after the number for units etc etc, so you have to strip all that stuff off before you can do the math anyway, so why not use a non-ascii format that is more math friendly? Since you have to change the value anyway.

Alf