namespace std {
#if defined(__STDCPP_BFLOAT16_T__)
using bfloat16_t = implementation-defined;
#endif
}
概要
16ビットのbrain floating point型。
内部表現
この型はISO/IEC/IEEE 60559 (IEEE 754) にはない16ビットの浮動小数点数型である。
Google社のTPUや、NVIDIAのGPUなどで採用されている内部表現をもつ。
型 | 符号ビット数 | 指数ビット数 | 仮数ビット数 | 最大指数 |
---|---|---|---|---|
bfloat16_t |
1 | 8 | 7 | 127 |
float16_t |
1 | 5 | 10 | 15 |
リテラル
値にサフィックスとしてbf16
もしくはBF16
を指定することで、std::bfloat16_t
のリテラルとすることができる。
std::bfloat16_t a = 1.0bf16;
std::bfloat16_t b = 2.0BF16;
事前定義マクロ
- この型は、事前定義マクロ
__STDCPP_BFLOAT16_T__
が定義されない場合、定義されない
順位
浮動小数点数の変換で使用される順位 (rank) は、以下のように定義される:
long double
>double
>float
のように、long double
が最も高い順位をもつ- 同じ値集合をもつ2つの拡張浮動小数点数型は、同じ順位をもつ
- 標準浮動小数点数型と同じ値集合をもつ拡張浮動小数点数型は、同じ順位をもつ
- 標準浮動小数点数型より多くの値集合をもつ拡張浮動小数点数型は、
double
と同じ順位をもつ
注意として、浮動小数点数型T1
の値集合が浮動小数点数型T2
の値集合の部分集合でも上位集合でもない場合、浮動小数点数型T1
とT2
の変換順位は順位通りではない。これは、一方の型が他方より大きな範囲と低い精度の両方を持つ場合に起こり得る。
順位が同じ浮動小数点数型は、サブ順位 (subrank) で順序付けられる。拡張浮動小数点数は、標準浮動小数点数型よりも大きなサブ順位をもつ。
昇格と変換
C言語の名残と後方互換性のために、オーバーロード解決でのfloat
からdouble
への変換は昇格と見なされるが、ほかの浮動小数点数型では昇格はない。
2つの浮動小数点型の少なくとも一方が拡張浮動小数点型である場合、変換先の型が変換元の型より大きいか等しい場合にのみ、2つの浮動小数点型間の変換が暗黙的に行われる。いかなる暗黙の変換も損失なく、値を正確に保持する。潜在的に損失のある変換はすべて明示的でなければならない。
小さい精度への変換は、()
と{}
による直接初期化、もしくは明示的なキャストのみ許可される。
void f(std::float16_t);
void g() {
std::float16_t a = 1.0; // エラー!小さい精度への暗黙変換はできない
std::float16_t b(2.0); // OK : 直接初期化
std::float16_t c{3.0}; // OK : 直接初期化
a = 4.0; // エラー!小さい精度への暗黙変換はできない
f(5.0); // エラー!小さい精度への暗黙変換はできない
f(static_cast<std::float16_t>(5.0)); // OK : 明示的なキャスト
}
通常の算術変換
算術演算での型変換は、以下のような規則で行われる。
- どちらかのオペランドが浮動小数点数型である場合、
- 両方のオペランドが同じ型であれば、型変換は行われない
- そうでなく、オペランドの一方が浮動小数点数型でなければ、浮動小数点数型のオペランドの型に変換される
- そうでなく、オペランドの浮動小数点数型の変換順位が等しくない場合、小さい方の順位をもつ浮動小数点数型は、もう一方の浮動小数点数型に変換される
float + double
はdouble
に、std::float16_t + float
はfloat
に変換される
- そうでなく、変換順位が等しい場合、サブ順位で比較が行われ、より大きいサブ順位をもつ浮動小数点数型に変換される
float + std::float32_t
はstd::float32_t
に変換される
- そうでなければ、式は不適格となる
std::float16_t + std::bfloat16_t
は不適格
#include <stdfloat>
#include <type_traits>
int main() {
float f32 = 1.0;
std::float16_t f16{2.0};
std::bfloat16_t b16{3.0};
std::float32_t f32b{4.0};
auto r1 = f32 + f16; // OK : f16は`float`に変換され、結果の型は`float`となる
auto r2 = f32 + b16; // OK : b16は`float`に変換され、結果の型は`float`となる
//auto r3 = f16 + b16; // エラー!どちらの型も算術変換でもう一方の型に変換できない
auto r4 = f32 + f32b; // OK : f32はより大きいサブ順位をもつ`std::float32_t`に変換される
static_assert(std::is_same_v<decltype(r4), std::float32_t>);
}
#include <stdfloat>
#include <type_traits>
int main() {
float f32 = 1.0;
std::float16_t f16{2.0};
std::bfloat16_t b16{3.0};
std::float32_t f32b{4.0};
auto r1 = f32 + f16; // OK : f16は`float`に変換され、結果の型は`float`となる
auto r2 = f32 + b16; // OK : b16は`float`に変換され、結果の型は`float`となる
//auto r3 = f16 + b16; // エラー!どちらの型も算術変換でもう一方の型に変換できない
auto r4 = f32 + f32b; // OK : f32はより大きいサブ順位をもつ`std::float32_t`に変換される
static_assert(std::is_same_v<decltype(r4), std::float32_t>);
}
オーバーロード解決
- 浮動小数点数型の変換をともなうオーバーロード解決は、値を維持する変換が優先され、同じ変換順位をもつ他の浮動小数点数型への変換が優先して行われる
- 値を維持する変換が曖昧な場合、プログラムは不適格となる
- 「ひとつ上の順位をもつ浮動小数点数型に変換する」のような規則ではないため、ひとつ以上上の順位をもつ浮動小数点数型の候補が複数あると曖昧になる
- 値を維持する変換が曖昧な場合、プログラムは不適格となる
#include <stdfloat>
void f(std::float32_t) {}
void f(std::float64_t) {}
void f(long long) {}
int main() {
float x;
std::float16_t y;
f(x); // f(std::float32_t)が呼び出される。
// floatとstd::float32_tが同じ変換順位をもつ
//f(y); // エラー!曖昧。変換順位が等しいオーバーロードが見つからない
}
例
#include <iostream>
#include <stdfloat>
#include <cmath>
int main() {
std::bfloat16_t a = 1.0bf16;
auto b = 2.0f32; // bの型はstd::float32_t
// 明示的型変換によって、
// float16_tとの間の変換ができる
auto aa = static_cast<std::float16_t>(a);
// aはより大きい精度の型float32_tに変換される
auto c = a + b; // cの型はstd::float32_t
// 精度を落とす縮小変換は明示的型変換で行う。
// 拡張浮動小数点数型は数学関数にも渡すことができ、
// 標準浮動小数点数型への暗黙変換もできる
double d = std::log(static_cast<std::bfloat16_t>(c));
// 同じ精度の浮動小数点数型との間で、精度を落とさず変換でき、
// coutでも拡張浮動小数点数のまま出力できる
std::cout << static_cast<std::float64_t>(d) << std::endl;
}
std::cout << static_cast<std::float64_t>(d) << std::endl;
#include <iostream>
#include <stdfloat>
#include <cmath>
int main() {
std::bfloat16_t a = 1.0bf16;
auto b = 2.0f32; // bの型はstd::float32_t
// 明示的型変換によって、
// float16_tとの間の変換ができる
auto aa = static_cast<std::float16_t>(a);
// aはより大きい精度の型float32_tに変換される
auto c = a + b; // cの型はstd::float32_t
// 精度を落とす縮小変換は明示的型変換で行う。
// 拡張浮動小数点数型は数学関数にも渡すことができ、
// 標準浮動小数点数型への暗黙変換もできる
出力
1.10156
バージョン
言語
- C++23
処理系
- Clang: ??
- GCC: 13.1 ✅
- Visual C++: ??
関連項目
std::float16_t
std::float32_t
std::float64_t
std::float128_t
std::basic_ostream::operator<<
std::basic_istream::operator>>