# Re: Formatting a number in a different way

Discussion in 'C Programming' started by Noob, Jan 20, 2011.

1. ### NoobGuest

pozz wrote:

> I want to create a function, sprintfnum(), with the prototype:
> void sprintfnum(char *str, const char *fmt, int x, int div);
>
> I tried to write this function, but I encounter many difficulties.
> Someone can help me?

for us to send our submissions directly to him?

Noob, Jan 20, 2011

2. ### pozzGuest

On 20 Gen, 10:25, Noob <r...@127.0.0.1> wrote:
> Could you provide the email address of your instructor, in order
> for us to send our submissions directly to him?

I'm sorry you think this is a school test. Firstly I don't remember
the last time I had an instructor.
And the most sad thing is that you are thinking the problem is
very simple, but I'm not able to find a good solution for it.

My implementation is long and complex and for simplicity I separated
prefix and suffix. Is there a simpler solution?

void
sprintfnum(char *str,
const char *prefix,
const char *num_fmt,
const char *suffix,
int x,
int div)
{
int n, nn;
int sign = 0, zero = 0, width = 0;

n = sprintf(str, "%s", prefix);
nn = 1;
if (num_fmt[nn] == '+') {
sign = 1;
nn++;
}
if (num_fmt[nn] == '0') {
zero = 1;
nn++;
}
width = strtol(&num_fmt[nn], NULL, 10);
if (!width) {
width = 1;
}
if (div > 0) {
char fmt[7];
if(!x && !zero) {
sprintf(fmt, "%%%s%dd",
sign ? "+" : "", width);
n += sprintf(&str[n], fmt, 0);
} else {
sprintf(fmt, "%%%s%s%dd",
sign ? "+" : "", zero ? "0": "", width - div);
n += sprintf(&str[n], fmt, x);
/* Aggiunge tanti zeri quanto è div */
while(div--) {
str[n++] = '0';
}
}
str[n] = '\0';
} else if (div == 0) {
n += sprintf(&str[n], num_fmt, x);
} else if (div < 0) {
char fmt[7];
div = -div;
sprintf(fmt, "%%%s%s%dd",
sign ? "+" : "", zero ? "0": "",
width - 1 < div + 1 + sign ? div + 1 + sign : width - 1);
n += sprintf(&str[n], fmt, x);
str[n + 1] = '\0';
while (div--) {
if (str[n - 1] == ' ') {
str[n] = '0';
} else if ((str[n - 1] == '+') || (str[n - 1] == '-')) {
str[n] = '0';
str[n - 2] = str[n - 1];
} else {
str[n] = str[n - 1];
}
n--;
}
str[n] = '.';
if (str[n - 1] == ' ') {
str[n - 1] = '0';
} else if ((str[n - 1] == '+') || (str[n - 1] == '-')) {
str[n - 2] = str[n - 1];
str[n - 1] = '0';
}
}
strcat(str, suffix);
}

pozz, Jan 20, 2011

3. ### Mark BluemelGuest

On 01/20/2011 09:57 AM, pozz wrote:
> On 20 Gen, 10:25, Noob<r...@127.0.0.1> wrote:
>> Could you provide the email address of your instructor, in order
>> for us to send our submissions directly to him?

>
> I'm sorry you think this is a school test. Firstly I don't remember
> the last time I had an instructor.
> And the most sad thing is that you are thinking the problem is
> very simple, but I'm not able to find a good solution for it.
>
> My implementation is long and complex and for simplicity I separated
> prefix and suffix. Is there a simpler solution?

I find the basic idea below easier to comprehend. I haven't tried to
achieve all you have, but I think the idea is clear enough and could
be extended to do what you want.

#include <stdio.h>
#include <stdlib.h>

void split(int num, int div, char *right, char *left);

int main(void) {
int div;
for (div = -3; div < 4; div++) {
char left[10]; /* arbitrary size, I'm afraid */
char right[10];
split(123456,div,right,left);
printf("%s.%s\n",right,left);
}
}

void split(int num, int div, char *right, char *left) {
int lp = 0;
if (div < 0) { /* there is a fractional part, get it */
char buff[10];
int bp = 0;
while(div) {
buff[bp++] = '0' + (num % 10);
num /= 10;
div++;
}
/* reverse the digits ... */
while (bp) {
left[lp++] = buff[--bp];
}
}
left[lp] = '\0';

while(div) { /* if there was a fractional part,
* div will now be zero
*/
num *= 10;
div --;
}
sprintf(right,"%d",num);
}

Mark Bluemel, Jan 20, 2011
4. ### Malcolm McLeanGuest

On Jan 20, 11:25 am, Noob <r...@127.0.0.1> wrote:
>
> Could you provide the email address of your instructor, in order
> for us to send our submissions directly to him?
>

You can usually detect what's real problem and what's a learning
exercise.

This one has all the feel of a real problem about it. You can fake up
floating point on an integer-only machine by storing a decimal place
separately, but you then need to output the numbers for human
consumption. The fact he needs field widths and signs and padding
suggests he wants the output for real - it's not a good exercise
because it's fiddly rather than testing understanding of concepts.

Malcolm McLean, Jan 20, 2011
5. ### Kenny McCormackGuest

In article <ih92ea\$3al\$-september.org>,
Richard <> wrote:
>Noob <root@127.0.0.1> writes:
>
>> pozz wrote:
>>
>>> I want to create a function, sprintfnum(), with the prototype:
>>> void sprintfnum(char *str, const char *fmt, int x, int div);
>>>
>>> I tried to write this function, but I encounter many difficulties.
>>> Someone can help me?

>>
>> Could you provide the email address of your instructor, in order
>> for us to send our submissions directly to him?
>>

>
>This is a help group. If you can help please do else get lost with your

You raise an interesting question. Is comp.lang.c a "help group"?
Why do you (rgrdev_) think that it is? Do others agree with you?

I ask these questions because I think that at least some, probably most,
of the "regs" would disagree with you, saying that it is a discussion
group, not a form of an unpaid corporate help desk. They are lying, of
course, but that is what they will say.

--
Just for a change of pace, this sig is *not* an obscure reference to
comp.lang.c...

Kenny McCormack, Jan 20, 2011
6. ### Mark BluemelGuest

On 01/20/2011 09:57 AM, pozz wrote:
> On 20 Gen, 10:25, Noob<r...@127.0.0.1> wrote:
>> Could you provide the email address of your instructor, in order
>> for us to send our submissions directly to him?

>
> I'm sorry you think this is a school test.

Given that you simply gave the problem specification and then said "I
tried to write this function, but I encounter many difficulties.", I'm
not totally surprised you got this reaction.

A summary of what you'd tried and the sorts of problems you encountered
would help people to give you relevant assistance. Otherwise, it sounds
rather like you want them to give you a fully worked solution from scratch.

Mark Bluemel, Jan 20, 2011
7. ### Mark BluemelGuest

On 01/20/2011 10:23 AM, Richard wrote:

> This is a help group.

Given the lack of a formal charter, it's a bit optimistic to state that
so unequivocally...

> If you can help please do else get lost with your

Have you considered leading by example?

Mark Bluemel, Jan 20, 2011
8. ### Mark BluemelGuest

On 01/20/2011 03:40 PM, Kenny McCormack wrote:
> In article<ih92ea\$3al\$-september.org>,
> Richard<> wrote:

>> This is a help group. If you can help please do else get lost with your

>
> You raise an interesting question. Is comp.lang.c a "help group"?
> Why do you (rgrdev_) think that it is? Do others agree with you?
>
> I ask these questions because I think that at least some, probably most,
> of the "regs" would disagree with you, saying that it is a discussion
> group, not a form of an unpaid corporate help desk. They are lying, of
> course, but that is what they will say.

"Lying" is a rather strong term - it's hard to lie about the
nature/purpose of comp.lang.c when there is no formal definition of it.

Empirically I'd suggest the observable nature of the newsgroup is more
discursive than problem-solving.

Mark Bluemel, Jan 20, 2011
9. ### SeebsGuest

On 2011-01-20, Mark Bluemel <> wrote:
> "Lying" is a rather strong term

But in context, self-referential.

> it's hard to lie about the
> nature/purpose of comp.lang.c when there is no formal definition of it.

You could easily lie about it; all you'd have to do is have an opinion
about the nature or purpose of the group, then say something contrary to
that opinion.

> Empirically I'd suggest the observable nature of the newsgroup is more
> discursive than problem-solving.

I'd mostly think so, but...

I guess I'd say I think it's perfectly appropriate to ask for help in a
discussion group. I don't think a group being a discussion group (which
all Usenet groups are by default unless stated otherwise, giving us our
clear answer) precludes straight requests for help from being appropriate.

However... Many of us are experienced programmers. One of the things
experienced programmers have usually learned is that the words in the
specification are frequently incorrect, because the person asking has
misunderstood the problem they need solved. As a result, if you come here
asking for help, it is reasonably well justified for people to second-guess

For a specific example, if something looks like homework, most experienced
programmers will conclude that, though the STATED problem was "I want someone
to do this for me", the REAL problem is "I need to learn how to do this so
I can not just get a passing grade but get one honestly".

That said, I didn't think the original looked like homework. It did, however,
look like a fairly arcane spec, and I'm still not sure what the intended
functionality is.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach /
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.

Seebs, Jan 20, 2011
10. ### Kenny McCormackGuest

In article <ih9lqc\$fnv\$-september.org>,
Mark Bluemel <> wrote:
>On 01/20/2011 03:40 PM, Kenny McCormack wrote:
>> In article<ih92ea\$3al\$-september.org>,
>> Richard<> wrote:

>
>>> This is a help group. If you can help please do else get lost with your

>>
>> You raise an interesting question. Is comp.lang.c a "help group"?
>> Why do you (rgrdev_) think that it is? Do others agree with you?
>>
>> I ask these questions because I think that at least some, probably most,
>> of the "regs" would disagree with you, saying that it is a discussion
>> group, not a form of an unpaid corporate help desk. They are lying, of
>> course, but that is what they will say.

>
>"Lying" is a rather strong term - it's hard to lie about the
>nature/purpose of comp.lang.c when there is no formal definition of it.

Well, there is a semantic difference between "lying" and "being wrong".
One, they say, is curable, the other is not.

I think that what you wrote would make more sense if I had said (and you had
quoted me as saying) that they (the "regs") were "wrong".

But (my use of) the term "lying" implies deceit and/or hypocrisy, which
is the target at which I was shooting. I guess my point is that if it
is a help group, it does a poor job of it (as shown by the frequent
requests for instructor's email addresses - a clear cut copout) but if
it is supposed to be a "discussion" group then it fails there because,
as I've shown elsewhere, nothing is "on topic" in comp.lang.c

>Empirically I'd suggest the observable nature of the newsgroup is more
>discursive than problem-solving.

It is many things, but none of them good.

--

Some of the more common characteristics of Asperger syndrome include:

* Inability to think in abstract ways (eg: puns, jokes, sarcasm, etc)
* Difficulties in empathising with others
* Problems with understanding another person's point of view
* Hampered conversational ability
* Problems with controlling feelings such as anger, depression
and anxiety
* Adherence to routines and schedules, and stress if expected routine
is disrupted
* Inability to manage appropriate social conduct
* Delayed understanding of sexual codes of conduct
* A narrow field of interests. For example a person with Asperger
syndrome may focus on learning all there is to know about
baseball statistics, politics or television shows.
* Anger and aggression when things do not happen as they want
* Sensitivity to criticism
* Eccentricity
* Behaviour varies from mildly unusual to quite aggressive
and difficult

Kenny McCormack, Jan 20, 2011
11. ### David HuttoGuest

On Jan 20, 12:24 pm, Seebs <> wrote:
> On 2011-01-20, Mark Bluemel <> wrote:
>
> > "Lying" is a rather strong term

>
> But in context, self-referential.
>
> > it's hard to lie about the
> > nature/purpose of comp.lang.c when there is no formal definition of it.

>
> You could easily lie about it; all you'd have to do is have an opinion
> about the nature or purpose of the group, then say something contrary to
> that opinion.
>
> > Empirically I'd suggest the observable nature of the newsgroup is more
> > discursive than problem-solving.

>
> I'd mostly think so, but...
>
> I guess I'd say I think it's perfectly appropriate to ask for help in a
> discussion group.  I don't think a group being a discussion group (which
> all Usenet groups are by default unless stated otherwise, giving us our
> clear answer) precludes straight requests for help from being appropriate..
>
> However...  Many of us are experienced programmers.  One of the things
> experienced programmers have usually learned is that the words in the
> specification are frequently incorrect, because the person asking has
> misunderstood the problem they need solved.  As a result, if you come here
> asking for help, it is reasonably well justified for people to second-guess
>
> For a specific example, if something looks like homework, most experienced
> programmers will conclude that, though the STATED problem was "I want someone
> to do this for me", the REAL problem is "I need to learn how to do this so
> I can not just get a passing grade but get one honestly".

But this is assuming that all individuals here that ask a basic
question are in school. We're all self learners, even when in class we
have to comprehend the outer layers of education in the current
curriculum. So don't always assume a basic question is 'school' level,
when it might be just 'tutorial' level.

>
> That said, I didn't think the original looked like homework.  It did, however,
> look like a fairly arcane spec, and I'm still not sure what the intended
> functionality is.
>
> -s
> --
> Copyright 2010, all wrongs reversed.  Peter Seebach / ://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
> I am not speaking for my employer, although they do rent some of my opinions.

David Hutto, Jan 20, 2011
12. ### SeebsGuest

On 2011-01-20, David Hutto <> wrote:
>> For a specific example, if something looks like homework, most experienced
>> programmers will conclude that, though the STATED problem was "I want someone
>> to do this for me", the REAL problem is "I need to learn how to do this so
>> I can not just get a passing grade but get one honestly".

> But this is assuming that all individuals here that ask a basic
> question are in school.

No, it isn't. I didn't state that "basic questions" were the same category
as "looks like homework".

> We're all self learners, even when in class we
> have to comprehend the outer layers of education in the current
> curriculum. So don't always assume a basic question is 'school' level,
> when it might be just 'tutorial' level.

Right...

>> That said, I didn't think the original looked like homework.

See?

Not all newbie questions look like homework. In fact, in my experience,
not that many do; homework problems have a characteristic artificiality to
them, in that they're built around a result you can easily verify without
using the computer, rather than something you'd actually need a computer
to do.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach /
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.

Seebs, Jan 20, 2011
13. ### BartcGuest

"pozz" <> wrote in message
news:ihack6\$1go\$...
> Il 20/01/2011 11:46, Mark Bluemel ha scritto:
>> I find the basic idea below easier to comprehend. I haven't tried to
>> achieve all you have, but I think the idea is clear enough and could
>> be extended to do what you want.
> > [...]

>
> This an interesting approach, but I couldn't find how I can achieve the
> zero-padding, the sign printing and the custom width.
>
> Also the split() function uses many divisions and multiplications in
> cycles (these are time consuming operations).
> I'd like to call just the sprintf() to have all the digits in textual form
> and operate only character shifting or similar things.

You might find that sprintf() also uses division internally.

You're making things a little harder (IMO) by using the C-style format
specification for sprintfnum(). This is fiddly to decipher.

Perhaps forget that to start with (it can be bolted on later), and
concentrate on the 3 parameters that the format would yield:

Width, Leadingzeros, and Plussign (W,Z and P)

You apply sprintf() (or even itoa()) to the data x, to give a string, and
then there is div, effectively a fourth parameter (DP), which just gives the
offset of the decimal point within that string.

Now the logic is a bit simpler: apply W, Z, P and DP to the plain string
version of x. This is not exactly trivial yet, depending on how many things
you want to take care of (what happens when W is too small, what if DP
yields a point outside the field, when to suppress the decimal point, and so
on.)

--
Bartc

Bartc, Jan 20, 2011
14. ### BartcGuest

"pozz" <> wrote in message
news:ihabfg\$e2\$...
> Il 20/01/2011 18:24, Seebs ha scritto:
>> [...] It did, however,
>> look like a fairly arcane spec, and I'm still not sure what the intended
>> functionality is.

>
> It is very simple. I'm using a basic 16-bit microprocessor with limited
> code memory. I don't want to use floating point variables, because they
> are very time and size consuming.

Your approach, using a signed integer plus (effectively) an exponent field,
*is* floating point...

However your 16+16-bit format yields 15 bits of precision, plus a too-big
exponent range, while normal 32-bit floating point typically gives 23 bits
of precision, and an 8-bit exponent range. And combined in a way to make it
easy to compare, assign and so on.

The format also differs from yours, in that the 'integer' part is usually
normalised to represent a number in the range 1.0 to 1.999999...

Your format I believe would have multiple representations for numbers:
(123,1) is 1230, but so is (1230,0).

So using an established standard format (IEEE floating point) would have
benefits, even if you don't do any actual floating point arithmetic on the
numbers.

(BTW if you don't care about the standard formats, but like to save memory,
then 16+8-bit format would work almost as well, if your microprocessor is

--
Bartc

Bartc, Jan 20, 2011
15. ### SeebsGuest

On 2011-01-20, pozz <> wrote:
> This is the reason why I use int variables to store the significant
> digits of all the signals even with different resolutions. But I need to
> know the resolution (divisor/multipler) together with the significant
> digits to output a human readable value.

> This is the reason to have a function that converts the couple (value,
> div) in a formatted string.

Makes sense! Hmm.

/* printnum: print a string of digits into a buffer,
* optionally with magnitude used as a fixed-point
* denominator.
* magnitude is the log(10) of the number; thus,
* 123, 1 => 1230
* 123, 0 => 123
* 123, -1 => 12.3
*/
int
printnum(char *buf, size_t size, int digits, int magnitude) {
size_t chars;
int i;

chars = snprintf(buf, size, "%d", digits);
if (chars > size) {
fprintf(stderr, "Number too big.\n");
return 1;
}
if (magnitude > 0) {
if (chars + magnitude > (size - 1)) {
fprintf(stderr, "Number plus multiplier too big.\n");
return 1;
}
for (i = 0; i < magnitude; ++i)
buf[chars + i] = '0';
buf[chars + i] = '\0';
return 0;
} else if (magnitude < 0) {
magnitude *= -1;
if (magnitude > chars) {
if (magnitude + 1 > (size - 1)) {
fprintf(stderr, "No space for leading zeroes.\n");
return 1;
}
memmove(buf + 1 + (magnitude - chars), buf, chars + 1);
buf[0] = '.';
for (i = 0; i < (magnitude - chars); ++i)
buf[i + 1] = '0';
return 0;
} else {
if (chars + 1 > (size - 1)) {
fprintf(stderr, "No space for decimal.\n");
return 1;
}
memmove(buf + chars - magnitude + 1, buf + chars - magnitude, magnitude + 1);
buf[chars - magnitude] = '.';
return 0;
}
} else {
return 0;
}
}

.... The rationale of this design is that it basically separates things into
the question of what the digits are, and the question of where the decimal
point goes. There's probably a prettier way to do this. I suppose you
could handle negative magnitudes quite nicely with:

int ten2the = 1;
for (i = 0; i < magnitude; ++i)
ten2the *= 10;
printf("%d.%0*d", (digits / ten2the), magnitude, (digits % ten2the));

That might be saner.

Anyway, there's a couple of ideas, maybe one of them will get you somewhere.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach /
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
I am not speaking for my employer, although they do rent some of my opinions.

Seebs, Jan 21, 2011
16. ### Ian CollinsGuest

On 01/21/11 05:45 PM, Seebs wrote:
> On 2011-01-20, pozz<> wrote:
>> This is the reason why I use int variables to store the significant
>> digits of all the signals even with different resolutions. But I need to
>> know the resolution (divisor/multipler) together with the significant
>> digits to output a human readable value.

>
>> This is the reason to have a function that converts the couple (value,
>> div) in a formatted string.

>
> Makes sense! Hmm.
>
> /* printnum: print a string of digits into a buffer,
> * optionally with magnitude used as a fixed-point
> * denominator.
> * magnitude is the log(10) of the number; thus,
> * 123, 1 => 1230
> * 123, 0 => 123
> * 123, -1 => 12.3
> */
> int
> printnum(char *buf, size_t size, int digits, int magnitude) {
> size_t chars;
> int i;
>
> chars = snprintf(buf, size, "%d", digits);
> if (chars> size) {
> fprintf(stderr, "Number too big.\n");
> return 1;
> }
> if (magnitude> 0) {
> if (chars + magnitude> (size - 1)) {
> fprintf(stderr, "Number plus multiplier too big.\n");
> return 1;
> }
> for (i = 0; i< magnitude; ++i)
> buf[chars + i] = '0';
> buf[chars + i] = '\0';
> return 0;
> } else if (magnitude< 0) {
> magnitude *= -1;
> if (magnitude> chars) {
> if (magnitude + 1> (size - 1)) {
> fprintf(stderr, "No space for leading zeroes.\n");
> return 1;
> }
> memmove(buf + 1 + (magnitude - chars), buf, chars + 1);
> buf[0] = '.';
> for (i = 0; i< (magnitude - chars); ++i)
> buf[i + 1] = '0';
> return 0;
> } else {
> if (chars + 1> (size - 1)) {
> fprintf(stderr, "No space for decimal.\n");
> return 1;
> }
> memmove(buf + chars - magnitude + 1, buf + chars - magnitude, magnitude + 1);
> buf[chars - magnitude] = '.';
> return 0;
> }
> } else {
> return 0;
> }
> }
>
> .... The rationale of this design is that it basically separates things into
> the question of what the digits are, and the question of where the decimal
> point goes. There's probably a prettier way to do this. I suppose you
> could handle negative magnitudes quite nicely with:
>
> int ten2the = 1;
> for (i = 0; i< magnitude; ++i)
> ten2the *= 10;
> printf("%d.%0*d", (digits / ten2the), magnitude, (digits % ten2the));
>
> That might be saner.

I tackled (without any library functions) this by first breaking down
the format string into one of these:

typedef struct format_t
{
const char* before;
const char* after;
int beforeSize;
int afterSize;
int width;
char sign;
} Format;

Then formatting the number thus:

char* formatNumber( int number, int exponent, const Format* format )
{
static char str[16];
char* p = str+sizeof(str)-1;

*p-- = '\0';

const char* const end = p;

if( exponent >= 0 )
{
while( exponent-- ) *p-- = '0';

while( number )
{
*p-- = '0'+(number%10);
number /= 10;
}
}
else /* negative exponent */
{
while( number )
{
*p-- = '0'+(number%10);
number /= 10;

if( ++exponent == 0 )
*p-- = '.';
}
}

return decorateNumber( p, end, format );
}

--
Ian Collins

Ian Collins, Jan 21, 2011
17. ### BartcGuest

"Bartc" <> wrote in message
news:ihahei\$im9\$-september.org...
>
> "pozz" <> wrote in message
> news:ihack6\$1go\$...

> You're making things a little harder (IMO) by using the C-style format
> specification for sprintfnum(). This is fiddly to decipher.
>
> Perhaps forget that to start with (it can be bolted on later), and
> concentrate on the 3 parameters that the format would yield:
>
> Width, Leadingzeros, and Plussign (W,Z and P)

How is one implementation that appears to work. Although your spec is rather
ambiguous. It directly prints the number rather than return a string; and
expects all the parameters (width, etc) to have been previously obtained
(since I think that parsing the format string properly is actually a bigger

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void emit(char c) { printf("%c",c);}

/* X is base number
Dp (Div) is x10 scale index (-2 -1 0 1 2 => /100 /10 *1 *10 *100)
Width is minimum width (no error if exceeded)
Plus is 0, or 1 or '+' to force sign
No decimal point unless dp is negative
Output goes directly to stdout via emit()
*/

void formatnum(int x,int dp, int width,int plus,int zeropad) {
int zerodot=0,dotzeros=0,trailzeros=0,middot=0,xlen;
char str[20];
int i,m;

xlen=sprintf(str,"%d",abs(x));

if (x<0 || (x>=0 && plus))

if (dp>0)
trailzeros=dp;
else if (dp<0) {
m=-dp;
if (m>=xlen) {
zerodot=1;
dotzeros=(m-xlen);
}
else
middot=m;
}

if (asign) emit(x<0?'-':'+');
if (bsign) emit(x<0?'-':'+');
if (zerodot) {emit('0'); emit('.');}
for (i=1; i<=dotzeros; ++i) emit('0');
for (i=0; i<xlen; ++i) {
emit(str);
if (middot && (xlen-i-1==middot)) emit('.');
}
for (i=1; i<=trailzeros; ++i) emit('0');
}

int main(void){
char* s;
int dp;

for (dp=-5; dp<5;++dp) {
printf("<");
formatnum(-123,dp, 10,0,0);
printf(">\n");
}

}

--
Bartc

Bartc, Jan 21, 2011
18. ### BartcGuest

"pozz" <> wrote in message
news:ihibmb\$rut\$...
> Il 20/01/2011 20:58, Bartc ha scritto:
>> Your approach, using a signed integer plus (effectively) an exponent
>> field,
>> *is* floating point...

>
> Hmmm..., I think my approach is fixed point rather than floating point.
> When I set the exponent of 10 (divisor or multiplier), the number is
> fixed-point.

No. With fixed point, you don't store the exponent, divisor, multiplier or
whatever you call it. The position of the decimal point is always in the
same (fixed) place for values of the same fixed point type.

As soon as you start adding a variable multiplier, then it becomes floating
point (because the position of the decimal point is no longer fixed).

Then that should have made it clearer.

> I understand this type of format has some reason in many cases, above all
> in embedded applications where FPU is not present... and this is my case.
> Also, the fixed-point representation isn't affected by the problem of
> representing fractional numbers (0.1, 0.01) without errors. With floating
> point this is not possible.

I think it is, assuming your fixed point repr still uses binary. I doubt
from your op that you were using decimal or BCD format. Binary fixed-point
still has a problem with 0.1.

Your original scheme is better for this purpose, as 0.1 is represented
exactly by (1,-1). (But we don't know what the source of your data is, how
accurate or noisy it is, and whether these matters have any significance.)

> Some software (like GNUCash) uses only fixed-point variables to avoid the
> problem of rounding.

Assuming that uses a decimal format, there will always be errors; what does
it store for 1/3?

>> So using an established standard format (IEEE floating point) would have
>> benefits, even if you don't do any actual floating point arithmetic on
>> the
>> numbers.

>
> Are you sure? Operations with floating point variables (even only the
> assignment) is very time-consuming on a low-end embedded processor without
> the FPU.

That sounds unlikely. Assigning 32-bits should be independent on whether
it's an int, a float, or comprises two shorts. *Especially* if there is no
FPU which the compiler might try and use.

> Also the compiler should include a relevant size library to manage
> floating point variables.

I did this stuff when I had no compiler help. The first floating point
format I programmed used 24-bits (1+7+16-bit) on an 8-bit microprocessor.
That didn't even have integer multiply or divide, so there wasn't that great
an advantage to using the inferior fixed point rather than floating point.

And of course a lot of corners needed to be cut to get any sort of speed (no
checking for underflow, overflow for example).

It sounds like possibly your compiler is calling in a hefty library as soon
as anything is declared as a float. Unless you want to program in assembler
however, then the fixed point or scaled format you have might be the best
bet.

(Also, the IEEE format I suggested uses binary format, making scaling by
powers of 10 diffcult -- ie. slow -- even when you do this in assembler. So
forget that. Although it's not that clear now exactly what your
representation is and whether it's binary or decimal).

> Moreover, with floating point variables I can't store the simple number
> 0.1.

You can also store it as a string: "0.1", which is a kind of decimal format.

> After thinking about fixed-point arithmetic, I found that a fixed-point
> number is a "two integers" number: integer and decimal parts.
> The fractional value 1.23 can be represented as
> 123 with a scale of -100 (-100 is the factor 1/100)
> or as
> 1 (integral part) and 23 (decimal part)
> If I can convert the first representation in the second, it'll be very
> simple to printout in a textual form the two parts.
>
> So I wrote this code:

> whole = exp > 0 ? (long int)x * exp : x / -exp;

I thought you said you had a lowly 16-bit processor. Divide is usually the
slowest operation.

With your original scheme, the 'exponent' merely involved counting along a
string.

> The first difference is that the divisor/multiplier is the real
> divisor/multiplier (10, 100, 1000) and not only the exponent (1, 2, 3).

Well if it's fast enough then that's probably OK.

--
Bartc

Bartc, Jan 23, 2011
19. ### pozzGuest

On 23 Gen, 21:50, "Bartc" <> wrote:
> >> Your approach, using a signed integer plus (effectively) an exponent
> >> field,
> >> *is* floating point...

>
> > Hmmm..., I think my approach is fixed point rather than floating point.
> > When I set the exponent of 10 (divisor or multiplier), the number is
> > fixed-point.

>
> No. With fixed point, you don't store the exponent, divisor, multiplier or
> whatever you call it. The position of the decimal point is always in the
> same (fixed) place for values of the same fixed point type.
>
> As soon as you start adding a variable multiplier, then it becomes floating
> point (because the position of the decimal point is no longer fixed).

Yes, you'd be right if I change the multiplier with arithmetic
operations. In my application multiplier is stored in a variable, but
it remains constant during execution.
Suppose the multiplier is 1/100 (read from a non volatile memory): it
will never change.
When x=5678, the real value is 56.78. If multiply by 2, x will be
11356 and the real value will be 113.56. The decimal point always
stays after the second digits (starting from the right).
With floating-point representation, the multiplier will change
accordingly with the operations (addition, multiplication and so on).

> > I understand this type of format has some reason in many cases, above all
> > in embedded applications where FPU is not present... and this is my case.
> > Also, the fixed-point representation isn't affected by the problem of
> > representing fractional numbers (0.1, 0.01) without errors. With floating
> > point this is not possible.

>
> I think it is, assuming your fixed point repr still uses binary. I doubt
> from your op that you were using decimal or BCD format. Binary fixed-point
> still has a problem with 0.1.
>
> Your original scheme is better for this purpose, as 0.1 is represented
> exactly by (1,-1). (But we don't know what the source of your data is, how
> accurate or noisy it is, and whether these matters have any significance.)

My representation is binary of course, but the multiplier is base 10,
not base 2.

> >> So using an established standard format (IEEE floating point) would have
> >> benefits, even if you don't do any actual floating point arithmetic on
> >> the
> >> numbers.

>
> > Are you sure? Operations with floating point variables (even only the
> > assignment) is very time-consuming on a low-end embedded processor without
> > the FPU.

>
> That sounds unlikely. Assigning 32-bits should be independent on whether
> it's an int, a float, or comprises two shorts. *Especially* if there is no
> FPU which the compiler might try and use.

Ok, it is time consuming only for operations, like sprintf("%f").

> > Also the compiler should include a relevant size library to manage
> > floating point variables.

>
> I did this stuff when I had no compiler help. The first floating point
> format I programmed used 24-bits (1+7+16-bit) on an 8-bit microprocessor.
> That didn't even have integer multiply or divide, so there wasn't that great
> an advantage to using the inferior fixed point rather than floating point.
>
> And of course a lot of corners needed to be cut to get any sort of speed (no
> checking for underflow, overflow for example).

The compiler I'm using has almost full support for floating point
variables. So I think I'd use it without writing myself library code
for floating point.

> It sounds like possibly your compiler is calling in a hefty library as soon
> as anything is declared as a float. Unless you want to program in assembler
> however, then the fixed point or scaled format you have might be the best
> bet.

Yes, you got it.

> (Also, the IEEE format I suggested uses binary format, making scaling by
> powers of 10 diffcult -- ie. slow -- even when you do this in assembler. So
> forget that. Although it's not that clear now exactly what your
> representation is and whether it's binary or decimal).

It is binary, with multiplier base 10, not base 2.
So 10.2 is 102 with multiplier 1/10.

> > Moreover, with floating point variables I can't store the simple number
> > 0.1.

>
> You can also store it as a string: "0.1", which is a kind of decimal format.

Actually I have (1,1/10) and I can't change it. So I need a way to
convert it in a textual form.

> > So I wrote this code:
> > whole = exp > 0 ? (long int)x * exp : x / -exp;

>
> I thought you said you had a lowly 16-bit processor. Divide is usually the
> slowest operation.
>
> With your original scheme, the 'exponent' merely involved counting along a
> string.

Yes, I know. Anyway, as you said in another message, sprintf() uses
divisions by 10 if you have binary values (like me). So this is
another division that simplify the algorithm. I'll measure some
benchmarks.

pozz, Jan 24, 2011