tags:

views:

800

answers:

6

My program prints out HUGE numbers - like 100363443, up to a trillion -- and it sort of hard to read them, so I would like to print any number in easy to read form.

right now I use

printf ("%10ld", number);

format

I would appreciate a resulting number using printf. Most of my code is c++ yet I don't want to introduce std::cout, as I already have printf

thanks

+7  A: 

Easy way might be to convert to a double just before output and use %e which will print them in exponential scientific notation. Try this:

double n = (double)number;
printf("%10.0e", n);
Daniel Bingham
+1 for me. This would be the easiest way to view them. The only thing I would add is to set a break point. Anything lower than the break point, you should format like a regular number.
Aaron M
+6  A: 

You could use humanize_number() which uses suffixes like k, m, etc., to leave out low order digits. This is not a standard routine, so you should d/l the source I have linked to. (2-clause BSD license, allows any kind of use.)

Humanize_number man page.

Humanize_number source code from NetBSD.

HUMANIZE_NUMBER(3)      NetBSD Library Functions Manual     HUMANIZE_NUMBER(3)

NAME
     dehumanize_number, humanize_number -- format a number into a human read-
     able form and viceversa

SYNOPSIS
     #include <stdlib.h>

     int
     dehumanize_number(const char *str, int64_t *result);

     int
     humanize_number(char *buf, size_t len, int64_t number,
         const char *suffix, int scale, int flags);

This works by appending suffixes as follows:

       Prefix    Description    Multiplier
       k         kilo           1024
       M         mega           1048576
       G         giga           1073741824
       T         tera           1099511627776
       P         peta           1125899906842624
       E         exa            1152921504606846976
DigitalRoss
This is probably better. My little trick only works I guess if you're weird enough to consider scientific notation "human readable". ;)
Daniel Bingham
One REALLY minor quibble: "prefixes" go before things (that's what "pre-" means). "Suffixes" go after things. 110K uses a K suffix to mean 110,000.
John R. Strohm
Oh, heh. Fixing it...
DigitalRoss
I really love the "dehumanize" function name :)
peterchen
+6  A: 
std::cout << std::setprecision(5) << std::scientific << 100363443.0;

note that the number is a float

EDIT: or if you don't like scientific I found this on the net:

struct comma : public std::numpunct<char>
{ 
    protected: std::string do_grouping() const { return "\003" ; } 
};

std::cout.imbue( std::locale( std::cout.getloc(), new comma ) );
std::cout << 100363443 << std::endl;

EDIT 2: As pointed out by Jerry you don't need the comma class as above, this seems sufficient by itself (although there are presumably locales which don't format large numbers at all?):

std::cout.imbue( std::locale( "" ) );
std::cout << 100363443 << std::endl;
Patrick
Yep. Using local is the consistent way to do it.
Martin York
Good idea, but you should be lazier:std::cout.imbue(std::locale(""));std::cout << 123456789 << std::endl;The locale without a name uses whatever locale the user has configured, so (for example) a user with their computer configured for US conventions would get:123,456,789but one using German conventions would get:123.456.789and so on. In some locales (e.g. India, IIRC) you don't even normally see groups of three -- it something like the first five (least significant) digits as one group, and then in groups of two from there.In C, look up localeconv; it's better than nothing.
Jerry Coffin
+3  A: 

Remember localization (especiallyif you are writing a library).
In europe (except the UK) it would be 1.000.000 rather than 1,000,000

Martin Beckett
+7  A: 

Use the non-standard apostrophe flag in the printf format string, if you have that option available and don't mind losing a little bit of portability.

According to my documentation, the ' flag is available for POSIX systems since 1997.

If you are on Unix, Linux, Mac, ... you should have no problem
If you are on Windows, DOS, iSeries, Android, ... all bets are off (but maybe you can install a POSIX layer to your system).

#include <locale.h>
#include <stdio.h>

int main(void) {
  long int x = 130006714000000;

  setlocale(LC_NUMERIC, "en_US.utf-8"); /* important */
  while (x > 0) {
    printf("# %%'22ld: %'22ld\n", x); /* apostrophe flag */
    x *= 2; /* on my machine, the Undefined Behaviour for overflow
            // makes the number become negative with no ill effects */
  }
  return 0;
}

On my system this program produces:

# %'22ld:    130,006,714,000,000
# %'22ld:    260,013,428,000,000
# %'22ld:    520,026,856,000,000
# %'22ld:  1,040,053,712,000,000
# %'22ld:  2,080,107,424,000,000
# %'22ld:  4,160,214,848,000,000
# %'22ld:  8,320,429,696,000,000
# %'22ld: 16,640,859,392,000,000
# %'22ld: 33,281,718,784,000,000
# %'22ld: 66,563,437,568,000,000
# %'22ld: 133,126,875,136,000,000
# %'22ld: 266,253,750,272,000,000
# %'22ld: 532,507,500,544,000,000
# %'22ld: 1,065,015,001,088,000,000
# %'22ld: 2,130,030,002,176,000,000
# %'22ld: 4,260,060,004,352,000,000
# %'22ld: 8,520,120,008,704,000,000
pmg
This is the only answer that does exactly what Andrei wants, using exactly the tools he wants to use.
Massa
I wish this were standard.
Michael Burr
exactly what I wanted. I hope my profile nor name scares anyone...
vehomzzz
I get a warning - warning #269: invalid format string conversion:printf("\n\t %'12ld\n", total);
vehomzzz
@Andrei: sorry about that. Apparently you need to print to a string, format that string and finally output the formatted string.
pmg
it actually worked, albeit with the warning!
vehomzzz
@pmg what do you mean to a string format?
vehomzzz
I meant that new formatted string as something like Lance Rushing answer.
pmg
@Andrei - you're probably getting the warning because the apostophe modifier is non-standard. For example, MSVC doesn't support it. Your compiler is giving you a nice reminder, even if the library you're using does supoprt it.
Michael Burr
@Michae -- that is what I though, son.
vehomzzz
@Michael Burr: how many parsers will stumble over that?
peterchen
+1  A: 

Here is an example I wrote in straight C w/o using locale. Only works for positives. (Much help from "DiscoVlad")

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


void my_reverse ( char* s ) {
    int c, i, j;
    for (i=0, j= strlen(s)-1;i<j;i++,j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}


char* insert_commas(unsigned long long input ) {
    int i, intlen;
    char* buffer;
    char* formatted;

    intlen = (int) ceil(log10(input * 1.0));
    buffer = (char *) malloc((intlen + 1) * sizeof(char));

    sprintf(buffer, "%llu", input);  // build buffer
    formatted = (char *) malloc((intlen + (int) ceil(intlen/3.0)) * sizeof(char));  // malloc output buffer
    my_reverse(buffer);

    for(i=intlen; i>=0; i--) {
        formatted[strlen(formatted)] = buffer[i];
        if (i%3 == 0 && i<intlen && i > 0) {
            formatted[strlen(formatted)] = ',';
        }
    }
    free(buffer);

    return formatted;
}


int main() {
    char* formatted;

    // don't forget to free(formatted) after each call.
    formatted = insert_commas(123);
    printf("output %s\n", formatted);
    // output 123

    formatted = insert_commas(1234);
    printf("output %s\n", formatted);
    // output 1,234

    formatted = insert_commas(123456);
    printf("output %s\n", formatted);
    // output 123,456

    formatted = insert_commas(1234567);
    printf("output %s\n", formatted);
    // output 1,234,567

    formatted = insert_commas(123456789);
    printf("output %s\n", formatted);
    // output 123,456,789

    formatted = insert_commas(12345678901234567890ull);
    printf("output %s\n", formatted);
    // output 12,345,678,901,234,567,890

}
Lance Rushing