prints out an unsigned long in decimal

M

Matt

Given only putchar (no sprintf, itoa, etc.) write a routine putlong
that prints out an unsigned long in decimal. No array allowed.

I have no idea if we can't use array to solve the problem.
 
J

Joona I Palaste

Matt said:
Given only putchar (no sprintf, itoa, etc.) write a routine putlong
that prints out an unsigned long in decimal. No array allowed.
I have no idea if we can't use array to solve the problem.

Hey come on. This problem is really quite easy. I'll leave you with a
skeleton of the solution.

void writeLong(unsigned long l) {
putchar( /* what goes here? */ );
if (l) {
writeLong( /* what goes here? */ );
}
}

I managed to solve the problem in a way similar to the above without
using arrays, or indeed other variables than l, at all. No need for
sprintf, itoa, etc either.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Life without ostriches is like coffee with milk."
- Mika P. Nieminen
 
I

Ivan Vecerina

Matt said:
Given only putchar (no sprintf, itoa, etc.) write a routine putlong
that prints out an unsigned long in decimal. No array allowed.

I have no idea if we can't use array to solve the problem.

One idea is to go with something like:
unsigned long exp = 10;
while(exp<val) exp*=10;
while( exp/=10 ) putchar( '0'+(val/exp)%10 );

Bug left in on purpose, and optimizations are possible.

Cheers,
Ivan
 
R

Richard Heathfield

Ivan Vecerina said:
One idea is to go with something like:
unsigned long exp = 10;
while(exp<val) exp*=10;
while( exp/=10 ) putchar( '0'+(val/exp)%10 );

Bug left in on purpose, and optimizations are possible.

Which bug? I count at least two.
 
J

Joe Wright

Matt said:
Given only putchar (no sprintf, itoa, etc.) write a routine putlong
that prints out an unsigned long in decimal. No array allowed.

I have no idea if we can't use array to solve the problem.

Because it's an example program on page 64 or K&R2 which uses an array
as temporary storage. The alogrithm to convert binary to 'decimal'
generates digits, least significant first. Then the array is reversed
(another example of how to reverse a string). They don't want you to
copy the example from the book.

You can do it without an array. Think recursion. Good luck.
 
R

Richard Heathfield

Ivan Vecerina said:
shush! ;) Is a portability problem included in your count?

Well, the first is that it basically gives the wrong answer sometimes. The
second is a namespace issue.
 
I

Ivan Vecerina

| "Ivan Vecerina" <ivecATmyrealboxDOTcom> wrote:
| > | >> "Ivan Vecerina" <ivecATmyrealboxDOTcom> wrote:
| >> > | >> >> Given only putchar (no sprintf, itoa, etc.) write a routine putlong
| >> >> that prints out an unsigned long in decimal. No array allowed.
| >> >>
| >> >> I have no idea if we can't use array to solve the problem.
| >> >
| >> > One idea is to go with something like:
| >> > unsigned long exp = 10;
| >> > while(exp<val) exp*=10;
| >> > while( exp/=10 ) putchar( '0'+(val/exp)%10 );
| >> >
| >> > Bug left in on purpose, and optimizations are possible.
| >>
| >> Which bug? I count at least two.
| >
| > shush! ;) Is a portability problem included in your count?

Hi Richard,

| Well, the first is that it basically gives the wrong answer sometimes.
Yes - a classic bounds problem I left for Matt to eventually find.

| The second is a namespace issue.
I am not sure what you mean by this. I assume you refer
to C name spaces, and not C++ namespace-s.
A conflict with the exp() function if using <math.h> ?


What I though of as a portability problem was the '0'+....
It could be replaced with "0123456789"[...],
or ...["0123456789"] ;)


Also, note that the code I posted in this thread is not
a recommendation, just a hint at a possible approach.

Regards,
Ivan
 
M

Martijn

Ivan said:
I am not sure what you mean by this. I assume you refer
to C name spaces, and not C++ namespace-s.
A conflict with the exp() function if using <math.h> ?

That, plus val not being declared... :)
 
C

CBFalconer

Richard said:
Well, the first is that it basically gives the wrong answer
sometimes. The second is a namespace issue.

How about (untested):

unsigned long xp = 1;

while ((val / xp) >= 10) xp *= 10;
do {
putchar('0' + (val/xp) % 10);
} while (xp /= 10);

which may be easier on resources than the recursive method.
 
D

Dan Pop

In said:
Well, the first is that it basically gives the wrong answer sometimes. The
second is a namespace issue.

No namespace issue, as long as exp has block scope.

Dan
 
R

Richard Heathfield

Ivan said:
| "Ivan Vecerina" <ivecATmyrealboxDOTcom> wrote:
| > | >> "Ivan Vecerina" <ivecATmyrealboxDOTcom> wrote:
| >> > | >> >> Given only putchar (no sprintf, itoa, etc.) write a routine
| >> >> putlong that prints out an unsigned long in decimal. No array
| >> >> allowed.
| >> >>
| >> >> I have no idea if we can't use array to solve the problem.
| >> >
| >> > One idea is to go with something like:
| >> > unsigned long exp = 10;
| >> > while(exp<val) exp*=10;
| >> > while( exp/=10 ) putchar( '0'+(val/exp)%10 );
| >> >
| >> > Bug left in on purpose, and optimizations are possible.
| >>
| >> Which bug? I count at least two.
| >
| > shush! ;) Is a portability problem included in your count?

Hi Richard,

| Well, the first is that it basically gives the wrong answer sometimes.
Yes - a classic bounds problem I left for Matt to eventually find.

| The second is a namespace issue.
I am not sure what you mean by this. I assume you refer
to C name spaces, and not C++ namespace-s.
A conflict with the exp() function if using <math.h> ?

Well, that's what I had in mind, yes, but see Dan Pop's rebuttal elsethread.
What I though of as a portability problem was the '0'+....

No, that bit's fine, because '0' + (0 through 9) is guaranteed to give you
'0' through '9'. The Standard says:

"In both the source and execution basic character sets, the value of each
character after 0 in the above list of decimal digits shall be one greater
than the value of the previous."
 
I

Ivan Vecerina

Richard Heathfield said:
Well, that's what I had in mind, yes, but see Dan Pop's rebuttal
elsethread.
Yes, the name of a global function should not interfere with a local
variable. (yes, for those who doubted of it, the 3 code lines are
intended to be within the body of a function...).

But things get nastier with the C99 standard: the standard <tgmath.h>
header is intended to define a bunch of macros providing type-generic
math functions -- kind of like C++ function overloads -- including
an exp() macro.

This said, if exp is a function-like macro (and it shall be IIUC),
the code will still be ok even after the inclusion of <tgmath.h>:
function-like macros are only substituted when they are
followed by a '(' (std 6.10.3/10).

Anyway, this goes beyond the scope of my initial post...
No, that bit's fine, because '0' + (0 through 9) is guaranteed to give you
'0' through '9'. The Standard says:

"In both the source and execution basic character sets, the value of each
character after 0 in the above list of decimal digits shall be one greater
than the value of the previous."
5.2.1/3 in C99.
Thank you, it is good to see this formally confirmed.
So this isn't like the latin alphabet characters, which can
be non-contiguous in non-ASCII encodings, e.g. EBDIC.


Kind regards,
Ivan
 
R

Richard Heathfield

Ivan Vecerina said:
5.2.1/3 in C99.
Thank you, it is good to see this formally confirmed.
So this isn't like the latin alphabet characters, which can
be non-contiguous in non-ASCII encodings, e.g. EBDIC.

Correct. The alphabet is a horse of a different kettle (or possibly a fish
of a different colour), and you need to go the extra mile if you need
portability. But you're fine with digits.
 
M

Morris Dovey

Matt said:
Given only putchar (no sprintf, itoa, etc.) write a routine putlong
that prints out an unsigned long in decimal. No array allowed.

I have no idea if we can't use array to solve the problem.

Matt...

You might try something like:

#include <stdio.h>

void putlong(unsigned long x)
{ if (x > 10) putlong(x / 10);
putchar(x % 10 + '0');
}

HTH
 
P

Peter Nilsson

No namespace issue, as long as exp has block scope.

But there is a conflict if <math.h> is included...

7.1.3p5:
... If the program declares or defines an identifier in a context in
which it is reserved (other than as allowed by 7.1.4), or defines a
reserved identifier as a macro name, the behavior is undefined.
 
D

Dan Pop

In said:
But there is a conflict if <math.h> is included...

7.1.3p5:
... If the program declares or defines an identifier in a context in
which it is reserved (other than as allowed by 7.1.4), or defines a
reserved identifier as a macro name, the behavior is undefined.

Could you, please, point out where the conflict is? After including
<math.h>, exp is NOT a reserved identifier if defined with block scope.

And if <math.h> defines an exp macro, it has to be a function-like macro,
therefore there is still no conflict with

unsigned long exp = 10;

Dan
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top