Re: Formatting a number in a different way

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

  1. Noob

    Noob Guest

    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?
    Noob, Jan 20, 2011
    #1
    1. Advertising

  2. Noob

    pozz Guest

    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
    #2
    1. Advertising

  3. Noob

    Mark Bluemel Guest

    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
    #3
  4. 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
    #4
  5. 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
    >smart arse answers.


    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
    #5
  6. Noob

    Mark Bluemel Guest

    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
    #6
  7. Noob

    Mark Bluemel Guest

    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
    > smart arse answers.


    Have you considered leading by example?
    Mark Bluemel, Jan 20, 2011
    #7
  8. Noob

    Mark Bluemel Guest

    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
    >> smart arse answers.

    >
    > 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
    #8
  9. Noob

    Seebs Guest

    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
    your request.

    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
    #9
  10. 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
    >>> smart arse answers.

    >>
    >> 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
    #10
  11. Noob

    David Hutto Guest

    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
    > your request.
    >
    > 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
    #11
  12. Noob

    Seebs Guest

    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
    #12
  13. Noob

    Bartc Guest

    "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
    #13
  14. Noob

    Bartc Guest

    "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
    byte-addressable,)

    --
    Bartc
    Bartc, Jan 20, 2011
    #14
  15. Noob

    Seebs Guest

    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
    #15
  16. Noob

    Ian Collins Guest

    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;
    char pad;
    } 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
    #16
  17. Noob

    Bartc Guest

    "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
    task):

    #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
    Zeropad is 1 to have leading zeros on left
    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 asign=0,bsign=0,padding=0;
    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 (zeropad) asign=1; else bsign=1;

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

    padding=width-(zerodot*2+dotzeros+bsign+(middot?1:0)+xlen+trailzeros)-asign;
    if (padding<0) padding=0;

    if (asign) emit(x<0?'-':'+');
    for (i=1; i<=padding; ++i) emit(zeropad?'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
    #17
  18. Noob

    Bartc Guest

    "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).

    > After reading Wikipedia article about fixed point,


    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
    #18
  19. Noob

    pozz Guest

    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
    #19
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    499
    John C. Bollinger
    Mar 17, 2005
  2. Lorentz
    Replies:
    4
    Views:
    1,131
    Lorentz
    Feb 27, 2004
  3. Michiel Overtoom
    Replies:
    1
    Views:
    335
    Niklas Norrthon
    Jul 22, 2008
  4. Replies:
    3
    Views:
    596
  5. francisco lopez
    Replies:
    2
    Views:
    166
    Dr John Stockton
    Dec 31, 2004
Loading...

Share This Page