C++ 如何在 g++ 中打印 __int128?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25114597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to print __int128 in g++?
提问by perror
I am using the GCC built-in type __int128
for a few things in my C++ program, nothing really significant, at least not enough to justify to use BigInt library only for that and, yet, enough to prevent to remove it totally.
我__int128
在我的 C++ 程序中将 GCC 内置类型用于一些事情,没有什么真正重要的,至少不足以证明只为此使用 BigInt 库是合理的,但足以防止完全删除它。
My problem comes when I run into the printing parts my classes, here is a minimal example:
当我遇到我的课程的打印部分时,我的问题就出现了,这是一个最小的例子:
#include <iostream>
int main()
{
__int128 t = 1234567890;
std::cout << t << std::endl;
return t;
}
Commenting out the std::cout
line will make this code to compile nicely with g++
, but having it will cause the following error message:
注释掉该std::cout
行将使此代码与 很好地编译g++
,但将导致以下错误消息:
int128.c: In function ‘int main()':
int128.c:7:13: error: ambiguous overload for ‘operator<<' (operand types are ‘std::ostream {aka std::basic_ostream<char>}' and ‘__int128')
std::cout << t << std::endl;
^
int128.c:7:13: note: candidates are:
In file included from /usr/include/c++/4.9/iostream:39:0,
from int128.c:1:
/usr/include/c++/4.9/ostream:108:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/include/c++/4.9/ostream:108:7: note: no known conversion for argument 1 from ‘__int128' to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}'
/usr/include/c++/4.9/ostream:117:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>] <near match>
operator<<(__ios_type& (*__pf)(__ios_type&))
^
/usr/include/c++/4.9/ostream:117:7: note: no known conversion for argument 1 from ‘__int128' to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}'
/usr/include/c++/4.9/ostream:127:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
operator<<(ios_base& (*__pf) (ios_base&))
^
/usr/include/c++/4.9/ostream:127:7: note: no known conversion for argument 1 from ‘__int128' to ‘std::ios_base& (*)(std::ios_base&)'
/usr/include/c++/4.9/ostream:166:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long __n)
^
/usr/include/c++/4.9/ostream:170:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned long __n)
^
/usr/include/c++/4.9/ostream:174:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(bool __n)
^
In file included from /usr/include/c++/4.9/ostream:609:0,
from /usr/include/c++/4.9/iostream:39,
from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:91:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
basic_ostream<_CharT, _Traits>::
^
In file included from /usr/include/c++/4.9/iostream:39:0,
from int128.c:1:
/usr/include/c++/4.9/ostream:181:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned short __n)
^
In file included from /usr/include/c++/4.9/ostream:609:0,
from /usr/include/c++/4.9/iostream:39,
from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:105:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
basic_ostream<_CharT, _Traits>::
^
In file included from /usr/include/c++/4.9/iostream:39:0,
from int128.c:1:
/usr/include/c++/4.9/ostream:192:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned int __n)
^
/usr/include/c++/4.9/ostream:201:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long long __n)
^
/usr/include/c++/4.9/ostream:205:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(unsigned long long __n)
^
/usr/include/c++/4.9/ostream:220:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(double __f)
^
/usr/include/c++/4.9/ostream:224:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(float __f)
^
/usr/include/c++/4.9/ostream:232:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
operator<<(long double __f)
^
/usr/include/c++/4.9/ostream:245:7: note: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>] <near match>
operator<<(const void* __p)
^
/usr/include/c++/4.9/ostream:245:7: note: no known conversion for argument 1 from ‘__int128' to ‘const void*'
In file included from /usr/include/c++/4.9/ostream:609:0,
from /usr/include/c++/4.9/iostream:39,
from int128.c:1:
/usr/include/c++/4.9/bits/ostream.tcc:119:5: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>] <near match>
basic_ostream<_CharT, _Traits>::
^
/usr/include/c++/4.9/bits/ostream.tcc:119:5: note: no known conversion for argument 1 from ‘__int128' to ‘std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}'
In file included from /usr/include/c++/4.9/iostream:39:0,
from int128.c:1:
/usr/include/c++/4.9/ostream:493:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char) [with _Traits = std::char_traits<char>]
operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
^
/usr/include/c++/4.9/ostream:488:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char) [with _Traits = std::char_traits<char>]
operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
^
/usr/include/c++/4.9/ostream:482:5: note: std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char) [with _Traits = std::char_traits<char>]
operator<<(basic_ostream<char, _Traits>& __out, char __c)
^
/usr/include/c++/4.9/ostream:476:5: note: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) [with _CharT = char; _Traits = std::char_traits<char>]
operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
^
Yes, I know, a lot of lines to explain that __int128
is just not properly handled...
是的,我知道,很多行来解释__int128
只是没有正确处理......
Is there a simpleway to get __int128
to be printed by the iostream
as any other numeric types ?
有没有一种简单的方法__int128
可以iostream
像任何其他数字类型一样被打印?
EDIT: For those who are still confusing C and C++, yes, I read the question: how to print __uint128_t number using gcc?But, this was for C and not for C++ as I am asking now.
编辑:对于那些仍然对 C 和 C++ 感到困惑的人,是的,我读到了一个问题:如何使用 gcc 打印 __uint128_t 数字?但是,这是针对 C 而不是针对我现在问的 C++。
采纳答案by James Kanze
If you don't need any of the fancy formatting options, writing
your own <<
operator is trivial. Formally, I suspect that
writing one for __int128_t
would be considered undefined
behavior, but practically, I think it would work, up until the
library starts providing actual support for it (at which point,
you'd retire your conversion operator).
如果您不需要任何花哨的格式选项,编写您自己的<<
运算符是微不足道的。正式地说,我怀疑编写一个 for__int128_t
将被视为未定义的行为,但实际上,我认为它会起作用,直到库开始为其提供实际支持(此时,您将退休您的转换运算符)。
Anyway, something like the following should work:
无论如何,类似以下的内容应该有效:
std::ostream&
operator<<( std::ostream& dest, __int128_t value )
{
std::ostream::sentry s( dest );
if ( s ) {
__uint128_t tmp = value < 0 ? -value : value;
char buffer[ 128 ];
char* d = std::end( buffer );
do
{
-- d;
*d = "0123456789"[ tmp % 10 ];
tmp /= 10;
} while ( tmp != 0 );
if ( value < 0 ) {
-- d;
*d = '-';
}
int len = std::end( buffer ) - d;
if ( dest.rdbuf()->sputn( d, len ) != len ) {
dest.setstate( std::ios_base::badbit );
}
}
return dest;
}
Note that this is just a quicky, temporary fix, until the time
the g++ library supports the type. It counts on 2's complement,
wrap around on overflow, for __int128_t
, but I'd be very
surprised if that wasn't the case (formally, it's undefined
behavior). If not, you'll need to fix up the initialization of
tmp
. And of course, it doesn't handle anyof the formatting
options; you can add as desired. (Handling padding and the
adjustfield
correctly can be non-trivial.)
请注意,这只是一个快速的临时修复,直到 g++ 库支持该类型为止。它依赖于 2 的补码,环绕溢出, for __int128_t
,但如果情况并非如此,我会感到非常惊讶(正式而言,这是未定义的行为)。如果没有,您需要修复
tmp
. 当然,它不处理任何格式选项;您可以根据需要添加。(处理填充和adjustfield
正确处理
可能非常重要。)
回答by TemplateRex
I would recommend against overloading operator<<
for __int128_t
. The reason is that whenever you see cout << x
for some integer type, you'd expect that all kinds of manipulators like std::hex
or std::setw
should also work. The most important guideline when overloading operators is: "do as the ints do".
我建议不要operator<<
为__int128_t
. 原因是当你看到cout << x
某种整数类型时,你会期望所有类型的操纵器都喜欢std::hex
或std::setw
应该也能工作。重载运算符时最重要的准则是:“像整数一样做”。
As an alternative, I would recommend using a decimal_string(__int128_t)
function that you can use as cout << decimal_string(x);
in your code. For the string conversion, you can use the algorithm from any of the C-related Q&As. This makes it clear that you have special code for your 128-bit ints. Whenever the Standard Library upgrades to 128-bit support, you can drop it (and it's easy to grep
for these functions).
作为替代方案,我建议使用decimal_string(__int128_t)
可以cout << decimal_string(x);
在代码中使用的函数。对于字符串转换,您可以使用任何与 C 相关的问答中的算法。这清楚地表明您的 128 位整数有特殊代码。每当标准库升级到 128 位支持时,您都可以放弃它(grep
对于这些功能很容易)。
回答by Non-maskable Interrupt
The stock cout
does not handle __int128
, but you may extends it with your own function.
股票cout
不处理__int128
,但你可以用你自己的函数扩展它。
For starter, code something like this:
首先,编写如下代码:
std::ostream& operator<<(std::ostream& os, __int128 t) {
// TODO: Convert t to string
return os << str;
}
There are many solution on SO to convert 128 bit number to string, I'll not repeat here.
SO上有很多将128位数字转换为字符串的解决方案,这里不再赘述。
About library compatibility in comment:
关于评论中的库兼容性:
You only need to roll your own function if the standard library does not provide such handler. Once the library support the type, you should then see a conflict when building, something like [ note: built-in candidate operator<< ], go try that with int64_t.
如果标准库没有提供这样的处理程序,你只需要滚动你自己的函数。一旦库支持该类型,您应该会在构建时看到冲突,例如[注意:内置候选运算符<<],请尝试使用 int64_t。
回答by HolKann
The most efficient version I could come up with
我能想到的最有效的版本
std::ostream& operator<<(std::ostream& os, __int128 x){
if(x<0){ os << "-"; x = -x; }
uint64_t tenPow18 = 1000000000000000000;
uint64_t x1 = x%tenPow18;
x/=tenPow18;
if(x>0){
uint64_t x2 = x%tenPow18;
x/=tenPow18;
if(x>0) os << (short) x;
os << x2;
}
return os << x1;
}
just prints two 64 bit and one 16 bit integer. This boils down to an unrolled and simplified version of @Gumby The Green and @HackerBoss's answer.
只打印两个 64 位和一个 16 位整数。这归结为@Gumby The Green 和@HackerBoss 答案的展开和简化版本。
The above code is wrong, as it does not take leading zeros into account for intermediate prints. E.g. "1000000000000000001" will be printed as "11". @Gumby The Green and @HackerBoss's answer probably suffer from this as well.
上面的代码是错误的,因为它没有考虑中间打印的前导零。例如,“1000000000000000001”将被打印为“11”。@Gumby The Green 和@HackerBoss 的回答也可能受到此影响。
In the end, I went with the answer in my other comment.
最后,我在另一条评论中给出了答案。
回答by Gumby The Green
If it's not performance-critical, here's a simple, readable way to convert a non-negativeint128 to a base-10 string (which can then be printed of course):
如果它不是性能关键,这里有一种简单易读的方法将非负int128 转换为 base-10 字符串(当然可以打印):
std::string toString(__int128 num) {
std::string str;
do {
int digit = num % 10;
str = std::to_string(digit) + str;
num = (num - digit) / 10;
} while (num != 0);
return str;
}
We can make this several times faster by getting the digits in larger chunks instead of one at a time. But it requires us to check each chunk for any leading zeroes that have been lost and add them back in:
通过以更大的块而不是一次获取一个数字,我们可以使速度提高几倍。但它要求我们检查每个块中是否有丢失的前导零并将它们添加回:
std::string toString(__int128 num) {
auto tenPow18 = 1000000000000000000;
std::string str;
do {
long long digits = num % tenPow18;
auto digitsStr = std::to_string(digits);
auto leading0s = (digits != num) ? std::string(18 - digitsStr.length(), '0') : "";
str = leading0s + digitsStr + str;
num = (num - digits) / tenPow18;
} while (num != 0);
return str;
}
Note: I've also posted a version of this answer for unsignedint128s here.
注意:我还在此处为unsignedint128s发布了此答案的一个版本。
回答by HackerBoss
The answers so far are good, but I just wanted to add to the answer from James Kanze. Firstly note that because of the unsigned conversion, it will not work for the number -0x80000000000000000000000000000000
. Secondly, you can advantage the fact that printing with 64-bit integers works, to optimize the function implementation as follows:
到目前为止的答案都很好,但我只是想补充一下 James Kanze 的答案。首先请注意,由于无符号转换,它不适用于 number -0x80000000000000000000000000000000
。其次,您可以利用使用 64 位整数打印的事实来优化函数实现,如下所示:
std::ostream& operator<<(std::ostream& os, __int128_t value) {
if (value < 0) {
os << '-';
value = -value;
}
// save flags to restore them
std::ios_base::fmtflags flags(os.flags());
// set zero fill
os << std::setfill('0') << std::setw(13);
// 128-bit number has at most 39 digits,
// so the below loop will run at most 3 times
const int64_t modulus = 10000000000000; // 10**13
do {
int64_t val = value % modulus;
value /= modulus;
if (value == 0) {
os.flags(flags);
return os << val;
}
os << val;
} while (1);
}
回答by HolKann
A deceptively simple approach
看似简单的方法
std::ostream& operator<<(std::ostream& os, __int128 x){
if(x<0) return os << "-" << -x;
if(x<10) return os << (char)(x+'0');
return os << x/10 << (char)(x%10+'0');
}
See my other comment for a failed attempt at a more performant implementation.
有关更高性能实现的失败尝试,请参阅我的其他评论。