【问题标题】:convert astronomically large numbers into human readable form in C/C++在 C/C++ 中将天文数字转换为人类可读的形式
【发布时间】:2009-09-30 16:11:28
【问题描述】:

我的程序打印出巨大的数字——比如 100363443,高达一万亿——而且有点难以阅读,所以我想以易于阅读的形式打印任何数字。

我现在用

printf ("%10ld", number);

格式

我希望使用 printf 得到一个结果数字。我的大部分代码都是 c++,但我不想引入 std::cout,因为我已经有了 printf

谢谢

【问题讨论】:

  • 您希望如何打印您的号码以使其更易于阅读?三人一组的数字?被逗号隔开?空间?
  • 我没有严格要求;我认为逗号与 3 组中的数字...
  • 此功能已内置于 std::ostream 对象中。您只需要使用正确的设置来灌输流。请参阅下面的帕特里克回答。
  • @Martin York 以粗体显示——我没有使用 std::ostream 对象...
  • 也许仅将其重新标记为 C 问题?

标签: c++ c largenumber


【解决方案1】:

在 printf 格式字符串中使用非标准的 apostrophe 标志,如果您有该选项可用并且不介意失去一点可移植性。

根据我的文档,' 标志自 1997 年以来可用于 POSIX 系统。

如果您使用的是 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

【讨论】:

  • 这是唯一一个完全符合安德烈想要的答案,完全使用他想要使用的工具。
  • 我收到警告 - 警告 #269:格式字符串转换无效:printf("\n\t %'12ld\n", total);
  • @Andrei:对此感到抱歉。显然你需要打印到一个字符串,格式化那个字符串,最后输出格式化的字符串。
  • 我的意思是新格式化的字符串类似于 Lance Rushing 的答案。
  • @Andrei - 您可能会收到警告,因为撇号修饰符是非标准的。例如,MSVC 不支持它。即使您使用的库确实支持它,您的编译器也会给您一个很好的提醒。
【解决方案2】:

您可以使用使用 k、m 等后缀的 humanize_number() 来省略低位数字。这不是一个标准的例程,所以你应该 d/l 我链接到的来源。 (2 条款 BSD 许可证,允许任何类型的使用。)

Humanize_number man page.

Humanize_number source code 来自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

【讨论】:

  • 这可能更好。我猜我的小技巧只有在你足够奇怪认为科学记数法“人类可读”时才有效。 ;)
  • 一个真正的小问题:“前缀”放在事物之前(这就是“pre-”的意思)。 “后缀”追求事物。 110K 使用 K 后缀表示 110,000。
  • 只是补充一点,这是一个仅用于整数的函数 - 不处理浮点数...
【解决方案3】:

简单的方法可能是在输出之前转换为双精度并使用 %e 以指数科学记数法打印它们。试试这个:

double n = (double)number;
printf("%10.0e", n);

【讨论】:

  • 为我+1。这将是查看它们的最简单方法。我唯一要添加的是设置一个断点。低于断点的任何内容都应该像常规数字一样格式化。
【解决方案4】:
std::cout << std::setprecision(5) << std::scientific << 100363443.0;

注意数字是浮点数

编辑:或者如果你不喜欢科学,我在网上找到了这个:

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;

编辑 2:正如 Jerry 所指出的,您不需要上述逗号类,这本身似乎就足够了(尽管可能存在根本不格式化大数字的语言环境?):

std::cout.imbue( std::locale( "" ) );
std::cout << 100363443 << std::endl;

【讨论】:

  • 是的。使用 local 是一贯的做法。
  • 好主意,但你应该更懒一点:std::cout.imbue(std::locale("")); std::cout
【解决方案5】:

记住本地化(尤其是在编写库时)。
在欧洲(英国除外),它将是 1.000.000 而不是 1,000,000

【讨论】:

    【解决方案6】:

    这是我使用语言环境用纯 C 语言编写的示例。仅适用于积极因素。 (来自“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
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-12
      • 1970-01-01
      • 2013-11-04
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多