Problem in the convertion of any number base B to decimal

S

sdlt85

Hi, the program is asking the user for a number ant he base of the
number, then it will convert the number to decimal.
But is running right only with base 2, 3, 4, 5, 6, 7, 8 but if I try
16 it is not working.
can some one help me please.
Thanks

#include <iostream>
#include <iomanip>
using namespace std;

const int n = 100;
void HornerD(char[], int, int);

int main()
{
int x;
char P[n];

cout<<"Enter a number: ";
cin>>P;
int n=strlen(P);
cout<<"Enter the base: ";
cin>>x;

HornerD(P, n, x);
return 0;
}

void HornerD(char *a, int n, int x)
{
int *p;

p=new int[n];
p[0]=a[0]-48;

for(int i=0; i<n; i++)
p[i+1]=p*x + (a[i+1]-48);
cout << "Result in decimal is: "<<p[n-1]<<endl;
}
 
J

Jim Langston

Hi, the program is asking the user for a number ant he base of the
number, then it will convert the number to decimal.
But is running right only with base 2, 3, 4, 5, 6, 7, 8 but if I try
16 it is not working.
can some one help me please.
Thanks

#include <iostream>
#include <iomanip>
using namespace std;

const int n = 100;
void HornerD(char[], int, int);

int main()
{
int x;
char P[n];

cout<<"Enter a number: ";
cin>>P;
int n=strlen(P);
cout<<"Enter the base: ";
cin>>x;

HornerD(P, n, x);
return 0;
}

void HornerD(char *a, int n, int x)
{
int *p;

p=new int[n];
p[0]=a[0]-48;

for(int i=0; i<n; i++)
p[i+1]=p*x + (a[i+1]-48);
cout << "Result in decimal is: "<<p[n-1]<<endl;
}


Because of the character set. ASCII 48 is 0. ASCII 49 is 1 through ASCII
57 which is 9. Hexidecimal uses 'A' to represet binary 10. Using yoru code
it would have to have the hexidecimal value of 58, but it doesn't. ASCII 58
is :. 59 is ; etc... ASCII 65 is A. You need two groups, '0' through '9'
and 'A' through 'Z' ( Z coudl be used in base 36). This is the line that is
causing the problem:

p[i+1]=p*x + (a[i+1]-48);
a[i+1] - 48
which could be written better as
a[i+1] - '0'
A quick fix (a kludge really) would be to look at the value and then decide
which to use. In pseudo code:
if a[i+1] is '0' through '9', subract 48 or '0', othersise, subtract 'A'.
( this only handles 'A' thourgh 'Z', not 'a' throguh 'z' ). A quick kludge
would be:

p[i+1] = p * x + ( a[i+1] - a[i+1] < 'A' ? '0' : 'A' );
which uses the ternary operator.

Consider if it's 'a' through 'z' though.

1. Instead of using a character array (c-style string) use a std::string.
You won't have to allocate it to some arbitrary length.
2. It seems the only reaso you are creating an array of ints is to store the
previous value, which you don't need to do. Consier, what does:
int p;
// ...
p = p * x + a[i+1]-'0';
do? That is legal code (as long as p is an int or such). You can use p in
a mathematical equation and change it's value at the same time. Yes, it's
not legal algebraically, but it is legal programically.
3. You are using s special case for the first character, why? 0 * x = 0.
Consider something like:
int p = 0;
for (int i=0; i<n; i++)
p = p * x + (a - '0');
4. You are going to n. n is a constant at 100. But what if they didnt'
enter 100 characters? Then it will read some garbage data (whatever
happened to be in the memory/array before that. You either need to stop at
the null terminator (if isuing a c-style string), use strlen (if using a
c-style string) or use .size() or length() (if using a std::string).

for ( int i = 0; i < strlen( a ); ++i ) // c-style string
for ( int i = 0; a != '\0'; ++i ) // c-style string
for ( int i = 0; i < a.length(); ++i ) // std::string

Better for container sizes, hower, is the type size_type as in
std::string::size_type

for ( std::string::size_type i = 0; i < a.length(); ++a )

truthfully, I get lazy typing std::string::size_type all the time and use
size_t which is the same no my system (not sure if on all).

There are a few more pointers, but honestly I don't know if this is homework
or not give you my code showing how I would do it using the same algorithm
you are using.
 
G

Gennaro Prota

Hi, the program is asking the user for a number ant he base of the
number, then it will convert the number to decimal.

Hi,

just some quick "didactic" remarks:
But is running right only with base 2, 3, 4, 5, 6, 7, 8 but if I try
16 it is not working.

At a glance the case base = 9 shouldn't be any different, though I
haven't run the program.

[...]
#include <iostream>

Strictly speaking you're better off also #including <ostream> and
#include <iomanip>

AFAIK, you're not using anything from this header (std::endl is
declared in said:
using namespace std;

As a rule of thumb try avoiding using directives. And always avoid
them at global or namespace scope in a file which gets #included
(because, that way, you inject a bunch of names in an unknown context:
whatever file happens to make the inclusion).
const int n = 100;
void HornerD(char[], int, int);

In C++ you have better alternatives here than char pointer (note, too,
that even using a char pointer it would have been much better to
declare it as

const char *

)
int main()
{
int x;

Move this as close as possible to where it is first assigned to (i.e.
the cin >> x; statement). I'd also heartedly recommend to use a name
such as 'base'. Do not underestimate the importance of names.
char P[n];

A comment similar to the one above. Prefer std::string. Also avoid
all-uppercase names for variables, because they are generally used for
macros (though, being this a one-letter, it shouldn't be defined as a
macro either by any sane code)
cout<<"Enter a number: ";
cin>>P;
int n=strlen(P);

Now you are shadowing the constant defined above (which has no reason
to exist, in fact). Also you don't include any header for strlen. But
you don't need strlen at all if you use std::string.
cout<<"Enter the base: ";
cin>>x;

HornerD(P, n, x);
return 0;
}

void HornerD(char *a, int n, int x)
{
int *p;

p=new int[n];

Memory leak. You never delete the pointed to array. And there's no
reason to separate the declaration: just write (when you really need
to new[]) int * p = new int[ count ];
p[0]=a[0]-48;

Wrong. For characters through '0'-'9' you are guaranteed that the
numerical value of c - '0' corresponds to c. So, had you written

p[ 0 ] = a[ 0 ] - '0';

that would have been correct, but *only* for characters in '0'-'9'.
This is of course the main reason why the program gives incorrect
results for base 16.

Note, too, that in a base b you can only enter digits between 0 and
b-1, so you might want to validate the input (and probably ask the
user to enter the base first, then the number)
for(int i=0; i<n; i++)
p[i+1]=p*x + (a[i+1]-48);


Same error as above. (Also, never hardcode constants)
cout << "Result in decimal is: "<<p[n-1]<<endl;

Note, too, that you are mixing two responsibilities in the HornerD
function: 1) calculating the number (decimal representation) 2)
displaying it.

This surprises the user (would you suppose that a function called
HornerD displayed something?) and prevents code reuse.

For starters, change it to something like

int HornerD( const std::string & representation,
int base );

(supposing that an int is large enough for storing the result: that's
a consideration you should make in advance)
 
G

Gennaro Prota

for(int i=0; i<n; i++)
p[i+1]=p*x + (a[i+1]-48);


Just noticing this now, BTW: why do you use an array? You might just
accumulate the result (a[0] + base*a[1] +....) into a non-array
variable. That would be the equivalent of your p[ n - 1 ].
 
J

James Kanze

Hi, the program is asking the user for a number ant he base of the
number, then it will convert the number to decimal.
#include <iostream>
Strictly speaking you're better off also #including <ostream> and
<istream>.

That used to be the case, but at the last meeting, the committee
approuved a resolution to make <iostream> sufficient.

[...]
p[0]=a[0]-48;

Wrong. For characters through '0'-'9' you are guaranteed that the
numerical value of c - '0' corresponds to c. So, had you written
p[ 0 ] = a[ 0 ] - '0';
that would have been correct, but *only* for characters in '0'-'9'.
This is of course the main reason why the program gives incorrect
results for base 16.
Note, too, that in a base b you can only enter digits between 0 and
b-1, so you might want to validate the input (and probably ask the
user to enter the base first, then the number)

Determining the digit and validating it typically go together:

std::string const
digits( "0123456789ABCDEFGHIJKLMNOPQRSTUVWXZY" ) ;
std::string::const_iterator
d = std::find( digits.begin(), digits.end(),
toupper( (unsigned
char)a[ 0 ] ) ) ;
if ( d - digits.begin() > base ) // ...

You will, of course, have validated beforehand that base >= 2 &&
base <= 36.
for(int i=0; i<n; i++)
p[i+1]=p*x + (a[i+1]-48);

Same error as above. (Also, never hardcode constants)

At least not these:). I wouldn't object about the 2 in base >=
2, or even too much about the 36 in base <= 36, above.
 
S

sdlt85

Ok, I got it know.
But how about if the user enter 1011.101 base 2.

Code:
#include <iostream>
#include <iomanip>
using namespace std;

const int c = 100;
void HornerD(char[], int, int);

int main()
{
       int x;
       char P[c];

       cout<<"Enter a number: ";
       cin>>P;
       int n=strlen(P);
       cout<<"Enter the base: ";
       cin>>x;

       HornerD(P, x, n);
       return 0;
}

void HornerD(char *a, int x, int n)
{
	int p = 0;

	if(x > 0 && x <= 9)
	{
		for (int i=0; i<n; i++)
		{
			p = p * x + (a[i] - '0');
		}
	}
	else
	{
		for (int i=0; i<n; i++)
		{
			 if(a[i]>='A')
                p = p * x + (a[i] - 'A'+10);
            else
                p=p*x+(a[i]-'0');
		}
	}

	cout << "Result in decimal is: "<<p<<endl;
}
 
S

sdlt85

Sorry this is my new code.
But how about if the user enter 1011.101 base 2.

#include <iostream>
#include <iomanip>
using namespace std;

const int c = 100;
void HornerD(char[], int, int);

int main()
{
int x;
char P[c];

cout<<"Enter a number: ";
cin>>P;
int n=strlen(P);
cout<<"Enter the base: ";
cin>>x;

HornerD(P, x, n);
return 0;
}

void HornerD(char *a, int x, int n)
{
int p = 0;

for (int i=0; i<n; i++)
{
if(a>='A')
p = p * x + (a - 'A'+10);
else
p=p*x+(a-'0');
}

cout << "Result in decimal is: "<<p<<endl;
}
 
B

BobR

Sorry this is my new code.
But how about if the user enter 1011.101 base 2.

Then tell your user NOT to enter *that* data! said:
#include <iostream>
#include <iomanip> // > using namespace std;

const int c = 100;
void HornerD(char[], int, int);

int main(){
using std::cout;
using std::cin; // if you simply must!
cout<<"Enter a number: ";
char P[c];
cin>>P;

How do you know 'P' is valid here?
int n = strlen( P );
cout<<" You entered "<<P<<"\nEnter the base: ";
// > int x;
int x( 0 ); // init it (or be sorry)!

How do you know 'std::cin' is still valid here?

if( not x ){
std::cerr"The RedCoats are coming!!"<<std::endl;
return EXIT_FAILURE;
} // if(!x)
HornerD(P, x, n);
return 0;
} // main()

void HornerD( char *a, int x, int n ){
int p = 0;
for( int i=0; i < n; ++i ){

if( a[ i ] == '.' ){
std::cerr<<"Son-of-a-bitch!!!! What now!?!"<<std::endl;
std::cerr<<"Homey don't play dat!!"<<std::endl;
break;
} if('.')
if( a[ i ] >= 'A' )
p = p * x + ( a[ i ] - 'A' + 10 );

What is '10', other than a "magic-number"? I bet it would like a name!
What if x == 3458967328-67398?
else
p = p * x + ( a[ i ] - '0' );
} // for(i)

cout << "Result in decimal is: "<<p<<endl;
}
 
R

Robert Bauck Hamar

BobR said:
// > using namespace std;

This is good advice. Namespace std contains many names, and suddenly one of
them will bite you. Even if you can name everything in std, you have no
guarantee that a name you have used will not be added to a later edition of
C++. This is one of the most important reasons why there is a namespace
std.
const int c = 100;
void HornerD(char[], int, int);

int main(){
using std::cout;
using std::cin; // if you simply must!

This is a much better practice. Name only the parts you need. Inside
function bodies are the better choice, but you are allowed to think.
cout<<"Enter a number: ";
char P[c];


Remark: If P is a char array, this may result in a buffer overrun, which is
a common source of bugs that is exploited by viruses and malicious
software. If P is a string, this would be safe.
How do you know 'P' is valid here?

Hint: if (!cin) then input failed.
Else you can call
cin.exceptions(std::ios_base::badbit|std::ios_base::failbit) to make cin
throw an exception if input fails.
cout<<" You entered "<<P<<"\nEnter the base: ";
// > int x;
int x( 0 ); // init it (or be sorry)!

No need to initialize x. But make sure you check the iostate of cin before
using it. Nevertheless, initializing variables is a good idea anyway. For
example som compilers initialize variables in debug build, which may result
in hard to find bugs that occur only in release build.
How do you know 'std::cin' is still valid here?


if( not x ){

Is this guaranteed to be correct if x was 0 before input? IMO testing cin
instead is a better practice, and it shows more clearly what's happening.
std::cerr"The RedCoats are coming!!"<<std::endl;
return EXIT_FAILURE;
} // if(!x)

Either before this call or in HornerD, you should test if the input is
correct.
return 0;
} // main()

void HornerD( char *a, int x, int n ){
int p = 0;
for( int i=0; i < n; ++i ){

if( a[ i ] == '.' ){

In this situation, as in many other, you should concentrate on asserting
that a is valid instead of checking against every invalid choice.
std::cerr<<"Son-of-a-bitch!!!! What now!?!"<<std::endl;
std::cerr<<"Homey don't play dat!!"<<std::endl;
break;
} if('.')
if( a[ i ] >= 'A' )
p = p * x + ( a[ i ] - 'A' + 10 );

What is '10', other than a "magic-number"? I bet it would like a name!

I disagree. 10 and 'A' is not exactly very magic, but you should leave a
comment about what is happening. Also note that this might not work on
system where characters are not based on ASCII:
* This fails if '0' > 'A'.
* This fails if the letters are not adjacent.
What if x == 3458967328-67398?
else
p = p * x + ( a[ i ] - '0' );

And as a remark to my previous note: Providing a is a digit, this is
guaranteed to work correctly (assuming no overflow).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top