make a program using C,C++

P

pete

Peter said:
On my system, -2147483648 (INT_MIN) produced
-1111111111111111111111111111112.

Good catch!
Alternatively...

void itoa_b(int n, char *s)
{
unsigned m = 0;
unsigned u = n;

if (n == 0)
m = 1;
else if (n < 0)
{
*s++ = '-';
u = -u;
if (u == 0) /* INT_MAX == UINT_MAX && n == INT_MIN */
{ *s++ = '1'; m = -1u/2+1; }
}

if (!m)
for (m = -1u/2+1; m && !(u & m); m >>= 1)
;

for (; m; m >>= 1)
*s++ = '0' + !!(u & m);

*s = 0;
}

That works for me.
 
A

August Karlstrom

Keith said:
August Karlstrom said:
Here is my version (for the general case):

#include <assert.h>

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num, power = 1, k = 0, digit;

assert((base >= 2) && (base < 10 + 'Z' - 'A'));
while (rem / (power * base) > 0) { power *= base; }
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}


I see at least two significant flaws.

You are quite right.

The calculations in the implementation above will easily overflow and
`base < 10 + 'Z' - 'A'' should really be `base <= '9' - '0' + 1 +
'Z' - 'A'' (to be explicit), so my implementation works up to base 36.
Of course I assume ASCII correspondence between characters and ordinals.

The following version is more likely to be correct:

#include <assert.h>

#define BASE_MAX ('9' - '0' + 1 + 'Z' - 'A' + 1)

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num / base, power = 1, k = 0, digit;

assert((base >= 2) && (base <= BASE_MAX));
while (rem > 0) { /* loop invariant: power * base <= num */
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}
If they were unintentional, I'll point them out; if they're deliberate (because it's probably a homework problem), they're likely to
get past the instructor.

Good or bad depending on how you see it ;-)


August
 
A

Anup Bishnoi

Richard said:
Forgive me, but I don't quite see how you are protecting against your user
typing ONE ONE ONE ZERO ZERO ONE ONE ONE ZERO ONE as input.

actually it requires you to enter some other (other than 0 and 1)
number after you have finished entering the binary number.

input like : ONE ZERO ZERO ONE ONE NINE

this would give output 19
 
K

Keith Thompson

August Karlstrom said:
The calculations in the implementation above will easily overflow and
`base < 10 + 'Z' - 'A'' should really be `base <= '9' - '0' + 1 +
'Z' - 'A'' (to be explicit), so my implementation works up to base
36. Of course I assume ASCII correspondence between characters and
ordinals.

Why do you assume ASCII?
 
A

August Karlstrom

Keith said:
Why do you assume ASCII?

I was thinking that there may be some unheard of encoding in which '0'
to '9' and 'A' to 'Z' respectively are not represented by consecutive
integers.


August
 
L

Lew Pitcher

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

August said:
I was thinking that there may be some unheard of encoding in which '0'
to '9' and 'A' to 'Z'

FWIW, all variants of EBCDIC leave big gaps in 'A' to 'Z', interposing
other characters in those gaps. So, for EBCDIC, 'A' to 'Z' means
something like
respectively are not represented by consecutive
integers.


August


- --

Lew Pitcher, IT Specialist, Enterprise Data Systems
Enterprise Technology Solutions, TD Bank Financial Group

(Opinions expressed here are my own, not my employer's)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)

iD8DBQFDznFeagVFX4UWr64RAs/zAKCNK6YK/nmQp2MqNQygFOXMifnt8wCePjgL
7O+htqrlQNzGOfN7SDCX//I=
=FSDo
-----END PGP SIGNATURE-----
 
K

Keith Thompson

August Karlstrom said:
I was thinking that there may be some unheard of encoding in which '0'
to '9' and 'A' to 'Z' respectively are not represented by consecutive
integers.

Right, that was my point. The C standard guarantees that '0' .. '9'
are consecutive, but it makes no such guarantee about 'A' .. 'Z' (or
about any other letters).
 
T

Thad Smith

August said:
Keith said:
August Karlstrom said:
Here is my version (for the general case):

#include <assert.h>

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num, power = 1, k = 0, digit;

assert((base >= 2) && (base < 10 + 'Z' - 'A'));
while (rem / (power * base) > 0) { power *= base; }
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}

I see at least two significant flaws.

You are quite right.

The calculations in the implementation above will easily overflow and
`base < 10 + 'Z' - 'A'' should really be `base <= '9' - '0' + 1 +
'Z' - 'A'' (to be explicit), so my implementation works up to base 36.

You are still off by one in your base check, assuming ASCII. If EBCDIC,
it's worse. I am ignoring the superfluous trailing apostrophe for now.
Of course I assume ASCII correspondence between characters and ordinals.

The following version is more likely to be correct:

#include <assert.h>

#define BASE_MAX ('9' - '0' + 1 + 'Z' - 'A' + 1)

I see you fixed it here.
void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num / base, power = 1, k = 0, digit;

assert((base >= 2) && (base <= BASE_MAX));
while (rem > 0) { /* loop invariant: power * base <= num */

Assume you start with num=1. The invariant is initially wrong.
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}

The code will now always generate a leading 0, which I would consider an
error. If you attempt to convert UINT_MAX-1, you will get a divide by 0.

Try again.
 
R

Richard Heathfield

Anup Bishnoi said:
actually it requires you to enter some other (other than 0 and 1)
number after you have finished entering the binary number.

input like : ONE ZERO ZERO ONE ONE NINE

this would give output 19

....but didn't. Care to think again?
 
D

David Bolt

On Tue said:
David Bolt wrote:

Well, there is just one little thing that I can see...
When number is converted to unsigned and number is negative, the
conversion will be done as if UINT_MAX to the value. On a 2's
complement machine (i.e. almost all machines these days) this will just
reinterpret the bits as unsigned. However, on a 1's complement or sign
& magnitude system (which the C standard still allows) it will change
the bit pattern. So, basically, your routine always prints the bit
pattern of the 2's complement representation of the number even if that
is not what the implementation uses.

Personally, for all of my real work (as opposed to picking nits here) I
would not worry about it.

Having never seen a 1's complement machine, this is another thing I
wouldn't have known.
With that attitude, I think you will do well in this group. So I'll let
you in to a trade secret...

Ooh, a secret. I like secrets :)
You can legally download copies of the drafts of the various version of
the C standard for free. This page has the appropriate links
http://clc-wiki.net/wiki/Basics_Of_The_C_Standard
OK, so it's not really a secret. However, it is reference material you
might find useful.

Having quickly skimmed through some of the info, including some of the
info linked from there, I can see it's going to be very useful. It might
even stop me making some stupid mistakes. No guarantees though.

It does matter if you use the value of the expression, i.e. these two
are different:
for (i=0; i<10; j=i++) {
/* j uninitialised fist time round then 1 less than i
on subsequent iterations */
}

for (i=0; i<10; j=++i) {
/* j uninitialised fist time round then the same as i
on subsequent iterations */
}

Okay, this is where I should have qualified the above to say that there
being no difference between post/pre only applied when there was no
other assignment.

This is good. Making honest errors on this group is fine, accepting
corrections is and learning from them is excellent.

And what a lot of learning I have to do. And after all the lurking I've
done, and all the things I've read here, I still managed to miss such a
simple error.
Just don't take my word as gospel until you've either verified it or at
least seen that no one else is pointing out that I've got it wrong.

Or, as with my case, watch to see if the person correcting you ends up
being corrected?


Regards,
David Bolt
 
A

August Karlstrom

Thad said:
You are still off by one in your base check, assuming ASCII. If EBCDIC,
it's worse. I am ignoring the superfluous trailing apostrophe for now.

Yes you are right, but I fixed it in my revised code (as you noticed).
There is no superfluous trailing apostrophe; the entire expression is
quoted by `...' (this is the convention used by TeX Info). Maybe `...`
is better, I don't know.
I see you fixed it here.



Assume you start with num=1. The invariant is initially wrong.

No, when num is one rem is zero, so the loop is never entered.
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power;
power /= base;
k++;
}
res[k] = '\0';
}


The code will now always generate a leading 0, which I would consider an
error.

I don't know what you mean. Do you have an example?
If you attempt to convert UINT_MAX-1, you will get a divide by 0.

Where would that happen? The denominators are `base' and `power', where
`base' is positive and division by `power' is guarded by
`power > 0'. Try and compile and run the complete program below. On my
32-bit machine i get the (expected) output FFFFFFFE.

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

#define BASE_MAX ('9' - '0' + 1 + 'Z' - 'A' + 1)

void get_num_in_base(char *res, unsigned num, unsigned base)
{
unsigned rem = num / base, power = 1, k = 0, digit;

assert((base >= 2) && (base <= BASE_MAX));
while (rem > 0) { /* loop invariant: power * base <= num */
power *= base;
rem /= base;
}
rem = num;
while (power > 0) {
digit = rem / power;
res[k] = ((digit < 10)? '0': 'A' - 10) + digit;
rem -= digit * power; /* digit * power <= rem */
power /= base;
k++;
}
res[k] = '\0';
}


int main(int argc, char *argv[])
{
char buf[32];

get_num_in_base(buf, UINT_MAX - 1, 16);
puts(buf);
return 0;
}


August
 
T

Thad Smith

August said:
No, when num is one rem is zero, so the loop is never entered.

Oops, I somehow read rem = num, not rem = num/base. You are right and I
withdraw my criticisms of your code. ;-)
 

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

Forum statistics

Threads
474,173
Messages
2,570,937
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top