43

假设我真的很需要内存并且想要更小的范围(类似于shortvs int)。着色器语言已经支持half具有一半精度的浮点类型(不仅仅是来回转换以使值介于 -1 和 1 之间,即返回像这样的浮点数:)shortComingIn / maxRangeOfShort。2字节浮点数是否已经存在实现?

我也有兴趣知道为什么没有 2 字节浮点数的任何(历史?)原因。

4

8 回答 8

18

回复:实现:显然有人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 位精度的十进制数字)。

于 2011-04-23T20:59:39.497 回答
16

TL;DR:确实存在 16 位浮点数,并且有各种软件和硬件实现

目前有 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 表示。GCCClang也支持__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%)

GCCICC等许多编译器现在也获得了支持 bfloat16 的能力

关于 bfloat16 的更多信息:

于 2019-05-07T05:40:22.027 回答
14

如果您的内存不足,您是否考虑过放弃浮动概念?浮点数使用大量位只是为了保存小数点所在的位置。如果您知道需要小数点的位置,则可以解决此问题,假设您想保存美元值,您可以将其保存为美分:

uint16_t cash = 50000;
std::cout << "Cash: $" << (cash / 100) << "." << ((cash % 100) < 10 ? "0" : "") << (cash % 100) << std::endl;

如果您可以预先确定小数点的位置,那当然只是一种选择。但如果可以的话,总是喜欢它,因为这也加快了所有计算!

于 2011-04-24T07:49:26.690 回答
6

16位浮点数有一个IEEE 754 标准

这是一种新格式,在 2008 年基于 2002 年发布的 GPU 进行了标准化。

于 2011-04-23T21:20:08.420 回答
3

为了在切换到整数方面比 Kiralein 更进一步,我们可以定义一个范围并允许 short 的整数值表示该范围内的相等除法,如果跨越零则具有一定的对称性:

short mappedval = (short)(val/range);

这些整数版本和使用半精度浮点数之间的差异:

  1. 整数在范围内等距分布,而浮点数在零附近更密集
  2. 使用整数将在 CPU 中使用整数数学而不是浮点数。这通常更快,因为整数运算更简单。话虽如此,将值映射到非对称范围将需要额外的添加等以在最后检索值。
  3. 绝对精度损失更可预测;您知道每个值的误差,因此可以在给定范围的情况下提前计算总损失。相反,相对误差使用浮点更可预测。
  4. 通过将两个short 打包到一个int 中,您可以使用成对的值来执行少量操作,尤其是按位操作。这可以将所需的周期数减半(或者更多,如果短操作涉及强制转换为 int)并保持 32 位宽度。这只是位切片的稀释版本,其中 32 位并行执行,用于加密。
于 2012-06-14T16:18:17.337 回答
2

如果您的 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 位浮点数计算算术的指令)。

于 2019-05-07T07:09:00.190 回答
1

在不同的实现中可能有多种类型。与 stdint.h 等效的浮点数似乎是个好主意。按大小调用(别名?)类型。( float16_t?) 4 字节的浮点数只是现在,但它可能不会变小。随着时间的推移,像 half 和 long 这样的术语大多变得毫无意义。对于 128 位或 256 位计算机,它们可能意味着任何东西。

我正在处理图像(1+1+1 字节/像素),我想表达每个像素相对于平均值的值。所以浮点或仔细定点,但请不要是原始数据的 4 倍。一个 16 位的浮点数听起来差不多。

这个 GCC 7.3 不知道“一半”,可能是在 C++ 上下文中。

于 2018-06-13T01:51:59.953 回答
1

2字节浮点数在clang C编译器中可用,数据类型表示为__fp16

于 2022-02-17T17:34:28.353 回答