преобразование астрономически больших чисел в удобочитаемую форму на языке C / C++
Моя программа печатает огромные числа - например, 100363443, до триллиона - и их трудно прочитать, поэтому я хотел бы напечатать любое число в удобочитаемой форме.
Прямо сейчас я использую
printf ("%10ld", number);
Формат
Я был бы признателен за итоговое число, используя printf. Большая часть моего кода-c++, но я не хочу вводить std:: cout, так как у меня уже есть printf
Спасибо
6 ответов:
Используйте нестандартный флаг
Согласно моей документации, флагapostrophe
в строке формата printf, если у вас есть эта опция и вы не против немного потерять переносимость.'
доступен для систем POSIX с 1997 года.Если вы находитесь на Unix, Linux, Mac, ... у вас не должно быть никаких проблем
Если вы находитесь на Windows, DOS, iSeries, Android, ... все ставки отменены (но, возможно, вы можете установить слой POSIX в свою систему).#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; }
В моей системе эта программа производит:
# %'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
Вы можете использовать humanize_number (), который использует такие суффиксы, как k, m и т. д., чтобы исключить цифры низкого порядка. Это не стандартная процедура, поэтому вы должны проверить источник, с которым я связался. (2-пункт BSD лицензии, допускает любой вид использования.)
Исходный код Humanize_number из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);
Это работает путем добавления суффиксов следующим образом:
Suffix Description Multiplier k kilo 1024 M mega 1048576 G giga 1073741824 T tera 1099511627776 P peta 1125899906842624 E exa 1152921504606846976
Простым способом может быть преобразование в двойник непосредственно перед выводом и использование %e, который будет печатать их в экспоненциальной научной нотации. Попробуйте это:
double n = (double)number; printf("%10.0e", n);
Обратите внимание, что число является плавающей точкойstd::cout << std::setprecision(5) << std::scientific << 100363443.0;
EDIT: или, если вам не нравится scientific, я нашел это в сети:
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: Как указал Джерри, вам не нужен класс запятой, как указано выше, это кажется достаточным само по себе (хотя, вероятно, есть локали, которые вообще не форматируют большие числа?):
std::cout.imbue( std::locale( "" ) ); std::cout << 100363443 << std::endl;
Запомните локализацию (особенно если вы пишете библиотеку).
В Европе (за исключением Великобритании) это будет 1.000.000, а не 1.000.000
Вот пример, который я написал в straight C w / o, используя locale. Работает только на позитиве. (Большая помощь от "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 }