假设我真的很需要内存并且想要更小的范围(类似于short
vs int
)。着色器语言已经支持half
具有一半精度的浮点类型(不仅仅是来回转换以使值介于 -1 和 1 之间,即返回像这样的浮点数:)shortComingIn / maxRangeOfShort
。2字节浮点数是否已经存在实现?
我也有兴趣知道为什么没有 2 字节浮点数的任何(历史?)原因。
假设我真的很需要内存并且想要更小的范围(类似于short
vs int
)。着色器语言已经支持half
具有一半精度的浮点类型(不仅仅是来回转换以使值介于 -1 和 1 之间,即返回像这样的浮点数:)shortComingIn / maxRangeOfShort
。2字节浮点数是否已经存在实现?
我也有兴趣知道为什么没有 2 字节浮点数的任何(历史?)原因。
回复:实现:显然有人half
为 C 编写,它(当然)可以在 C++ 中工作:https ://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/cellperformance-snippets /半.c
回复:为什么是float
四个字节:可能是因为低于此,它们的精度是如此有限。在 IEEE-754 中,“半”只有 11 位有效数字精度,产生大约 3.311 位十进制精度(而单次24 位产生 6 到 9 位十进制精度,或 53 位双精度产生15 和 17 位精度的十进制数字)。
目前有 2 种常见的标准 16 位浮点格式:IEEE-754 binary16和 Google 的bfloat16。由于它们是标准化的,显然如果任何了解规范的人都可以编写实现。一些例子:
或者如果你不想使用它们,你也可以设计一个不同的16位浮点格式并实现它
通常不使用 2 字节浮点数,因为即使是浮点数的精度也不足以进行正常操作,double
除非您受到带宽或缓存大小的限制,否则应始终默认使用。double
在 C 和类 C 语言中使用不带后缀的浮点字面量也是如此。看
但是确实存在小于 32 位的浮点数。它们主要用于存储目的,例如在图形中,每像素 96 位(每通道 32 位 * 3 通道)太浪费了,并且将转换为普通的 32 位浮点数进行计算(某些特殊硬件除外) )。OpenGL 中存在各种 10、11、14位浮点类型。许多 HDR 格式对每个通道使用 16 位浮点数,Direct3D 9.0 以及一些 GPU(如 Radeon R300 和 R420)具有 24 位浮点数格式。一些 8 位微控制器(如PIC )中的编译器也支持 24 位浮点数其中 32 位浮点支持成本太高。8 位或更窄的浮点类型不太有用,但由于它们的简单性,它们经常在计算机科学课程中教授。此外,小浮点数也用于ARM 的小浮点立即数指令编码。
IEEE 754-2008 修订版正式添加了 16 位浮点格式,也称为binary16或半精度,具有 5 位指数和 11 位尾数
一些编译器支持 IEEE-754 binary16,但主要用于转换或矢量化操作,而不用于计算(因为它们不够精确)。例如,ARM 的工具链__fp16
可以在 2 个变体之间进行选择:IEEE 和替代方案,具体取决于您想要更多范围还是 NaN/inf 表示。GCC和Clang也支持__fp16
标准化名称_Float16
。请参阅如何在 gcc 上为 x86_64 启用 __fp16 类型
最近由于人工智能的兴起,另一种称为bfloat16(大脑浮点格式)的格式是IEEE-754 binary32 的前 16 位的简单截断变得普遍
减少尾数背后的动机来自谷歌的实验,该实验表明,只要仍然可以将接近零的微小值表示为训练期间微小差异总和的一部分,就可以减少尾数。较小的尾数会带来许多其他优势,例如减少乘法器功率和物理硅面积。
- 浮点数32:24 2 =576(100%)
- 浮点数 16:11 2 =121 (21%)
- bfloat16: 8 2 =64 (11%)
GCC和ICC等许多编译器现在也获得了支持 bfloat16 的能力
关于 bfloat16 的更多信息:
如果您的内存不足,您是否考虑过放弃浮动概念?浮点数使用大量位只是为了保存小数点所在的位置。如果您知道需要小数点的位置,则可以解决此问题,假设您想保存美元值,您可以将其保存为美分:
uint16_t cash = 50000;
std::cout << "Cash: $" << (cash / 100) << "." << ((cash % 100) < 10 ? "0" : "") << (cash % 100) << std::endl;
如果您可以预先确定小数点的位置,那当然只是一种选择。但如果可以的话,总是喜欢它,因为这也加快了所有计算!
16位浮点数有一个IEEE 754 标准。
这是一种新格式,在 2008 年基于 2002 年发布的 GPU 进行了标准化。
为了在切换到整数方面比 Kiralein 更进一步,我们可以定义一个范围并允许 short 的整数值表示该范围内的相等除法,如果跨越零则具有一定的对称性:
short mappedval = (short)(val/range);
这些整数版本和使用半精度浮点数之间的差异:
如果您的 CPU 支持 F16C,那么您可以通过以下方式快速启动并运行某些东西:
// needs to be compiled with -mf16c enabled
#include <immintrin.h>
#include <cstdint>
struct float16
{
private:
uint16_t _value;
public:
inline float16() : _value(0) {}
inline float16(const float16&) = default;
inline float16(float16&&) = default;
inline float16(const float f) : _value(_cvtss_sh(f, _MM_FROUND_CUR_DIRECTION)) {}
inline float16& operator = (const float16&) = default;
inline float16& operator = (float16&&) = default;
inline float16& operator = (const float f) { _value = _cvtss_sh(f, _MM_FROUND_CUR_DIRECTION); return *this; }
inline operator float () const
{ return _cvtsh_ss(_value); }
inline friend std::istream& operator >> (std::istream& input, float16& h)
{
float f = 0;
input >> f;
h._value = _cvtss_sh(f, _MM_FROUND_CUR_DIRECTION);
return input;
}
};
仍然使用 32 位浮点数执行数学运算(F16C 扩展仅提供 16/32 位浮点数之间的转换 - 不存在使用 16 位浮点数计算算术的指令)。
在不同的实现中可能有多种类型。与 stdint.h 等效的浮点数似乎是个好主意。按大小调用(别名?)类型。( float16_t
?) 4 字节的浮点数只是现在,但它可能不会变小。随着时间的推移,像 half 和 long 这样的术语大多变得毫无意义。对于 128 位或 256 位计算机,它们可能意味着任何东西。
我正在处理图像(1+1+1 字节/像素),我想表达每个像素相对于平均值的值。所以浮点或仔细定点,但请不要是原始数据的 4 倍。一个 16 位的浮点数听起来差不多。
这个 GCC 7.3 不知道“一半”,可能是在 C++ 上下文中。
2字节浮点数在clang C编译器中可用,数据类型表示为__fp16
。