2つの64ビット数の乗算結果を保存するため、128ビット整数が必要です。 gcc 4.4以降にはそのようなものがありますか?
128ビット整数型は64ビットターゲットでのみ使用可能であるため、最新のGCCバージョンを既に検出している場合でも可用性を確認する必要があります。理論的には、gcccouldは、1つを保持するのに4x 32ビットのレジスタを必要とするマシンでTImode整数をサポートしますが、そうするケースはないと思います。
GCC 4.6以降には、組み込み型として定義された__int128
/unsigned __int128
があります。使用#ifdef __SIZEOF_INT128__
それを検出します。
GCC 4.1以降では、__int128_t
および__uint128_t
を<stdint.h>
で定義します。最近のコンパイラでは、これはおそらく__int128
の観点から定義されています。 (#include <stdint.h>
の代わりに__int128_t
名を使用する場合は、__int128
が必要です。)
私は Godboltコンパイラエクスプローラーで をテストしました。最初のバージョンのコンパイラーは、これらの3つのこと(x86-64)のそれぞれをサポートします。 Godboltはgcc4.1、ICC13、およびclang3.0にのみ戻るため、実際の最初のサポートがさらに早い可能性があることを示すために<= 4.1を使用しました。
legacy recommended(?) | One way of detecting support
__uint128_t | [unsigned] __int128 | #ifdef __SIZEOF_INT128__
gcc <= 4.1 | 4.6 | 4.6
clang <= 3.0 | 3.1 | 3.3
ICC <= 13 | <= 13 | 16. (Godbolt doesn't have 14 or 15)
ARM、または-m32
を使用したx86のような32ビットアーキテクチャ用にコンパイルする場合、これらのコンパイラの最新バージョンでも128ビット整数型はサポートされません。したがってneedは、使用せずにコードが機能する可能性がある場合に、使用前にサポートを検出します。
それを検出するために私が知っている唯一の直接CPPマクロは__SIZEOF_INT128__
ですが、残念ながらいくつかの古いコンパイラバージョンはそれを定義せずにサポートしています。 (そして、__uint128_t
用のマクロはありません。gcc4.6スタイルのunsigned __int128
のみです)。 __ uint128_tが定義されているかどうかを知る方法
一部の人々は、RHEL(RedHat Enterprise Linux)上のgcc4.4などの古いコンパイラバージョン、または同様の無愛想な古いシステムをまだ使用しています。そのような古いgccバージョンが気になる場合は、おそらく__uint128_t
に固執したいでしょう。そしておそらく、いくつかの64ビットISAではsizeof(int_fast32_t)
に関して64ビットを検出します。これは何らかの理由で8です。ただし、x32やILP32 AArch64などのILP32 ISAではないため、__SIZEOF_INT128__
が定義されていない場合は、単にsizeof(void*)
を確認してください。
Gccが__int128
を定義していない64ビットISAもあれば、gccdoesが__int128
を定義している32ビットISAもありますが、私は何も知りません。
ここでの別の答えに対するコメントが指摘するように、GCC内部は整数TIモードです。 (テトラ整数= int
の4x幅、vs。DImode = double width vs. SImode = plain int
。)As GCCマニュアルは指摘 、__int128
は128ビット整数モード(TImode)をサポートするターゲットでサポートされます。
typedef unsigned uint128_t __attribute__ ((mode (TI)));
ランダムな事実:ICC19 -E -dM
の定義:
#define __GLIBCXX_TYPE_INT_N_0 __int128
#define __GLIBCXX_BITSIZE_INT_N_0 128
テスト機能は次のとおりです。
#include <stdint.h>
#define uint128_t __uint128_t
//#define uint128_t unsigned __int128
uint128_t mul64(uint64_t a, uint64_t b) {
return (uint128_t)a * b;
}
それをサポートするコンパイラはすべて、効率的にコンパイルし、
mov rax, rdi
mul rsi
ret # return in RDX:RAX
ああ、大きな整数はCの得意ではありません。
GCCには、バージョン4.somethingから始まるunsigned __int128
/__int128
型があります(ここではわかりません)。ただし、その前に__int128_t
defがあったことを思い出すようです。
これらは64ビットターゲットでのみ使用可能です。
(編集者注:この回答は、gccがuint128_t
およびint128_t
を定義したと主張するために使用されました。Godboltコンパイラエクスプローラーでテストしたバージョンは、__
を先頭に付けずに、gcc4.1から8.2、またはclangまたはICCを定義していません)
GNU MP Bignum Library などの、任意または大きな精度値を処理するライブラリを使用できます。