web-dev-qa-db-ja.com

2バイトの浮動小数点数がなく、実装がすでに存在するのはなぜですか?

私が本当にメモリを求められており、より狭い範囲が必要であると仮定します(shortintに類似)。シェーダー言語はすでに、精度が半分の浮動小数点型のhalfをサポートしています(値が-1から1になるように前後に変換するだけではなく、つまり、次のような浮動小数点数を返します:shortComingIn / maxRangeOfShort)。 2バイトfloatの実装がすでに存在しますか?

また、2バイトの浮動小数点数がない理由(歴史的なもの)についても知りたいと思います。

29
Samaursa

Re:実装:誰かがC用にhalfを書いたようです。これは(もちろん)C++で動作します: https://storage.googleapis.com/google-code-archive-downloads/v2 /code.google.com/cellperformance-snippets/half.c

Re:なぜfloatが4バイトなのか:おそらくその下、 その精度は非常に制限されている が原因です。

10
T.J. Crowder

メモリが少ない場合、フロートの概念を削除することを検討しましたか?浮動小数点数は、小数点がどこにあるかを保存するためだけに多くのビットを使用します。小数点を必要とする場所でknowを使用すると、これを回避できます。たとえば、ドル値を保存したい場合は、セントでそれを保存することができます:

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

もちろん、小数点の位置を事前に決定できる場合は、これが唯一のオプションです。ただし、可能であれば、常に優先してください。これにより、すべての計算が高速化されます。

rgds、Kira :-)

13
Kirab

ありますisIEEE 754 standard for 16-bit floats

これは新しいフォーマットで、2002年にリリースされたGPUに基づいて2008年に標準化されました。

5
dan04

整数への切り替えでキラレインより少し先に進むには、範囲を定義し、shortの整数値が範囲全体で等しい除算を表すことを許可します。ゼロにまたがる場合は対称になります。

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

これらの整数バージョンと半精度浮動小数点数の違い:

  1. 整数は範囲内で等間隔に配置されますが、浮動小数点はゼロに近いほど密にパックされます
  2. 整数を使用すると、浮動小数点ではなくCPUで整数演算が使用されます。整数演算が単純なため、多くの場合より高速です。そうは言っても、値を非対称範囲にマッピングするには、最後に値を取得するために追加の追加などが必要になります。
  3. 絶対精度の損失はより予測可能です。各値の誤差がわかるので、範囲を指定して、総損失を事前に計算できます。逆に、相対誤差は浮動小数点を使用するとより予測しやすくなります。
  4. 2つのshortをintにパックすることで、値のペア、特にビット単位の演算を使用して実行できる小さな演算の選択がある場合があります。これにより、必要なサイクル数が半分になり(短い操作でintへのキャストが必要な場合はそれ以上)、32ビット幅が維持されます。これは、32ビットが並列に作用するビットスライシングの希釈バージョンであり、暗号化で使用されます。
3
Phil H

TL; DR:16ビットの浮動小数点数が存在し、ハードウェアの実装だけでなく、さまざまなソフトウェアが実装されています

現在2つの一般的な標準16ビット浮動小数点形式があります:IEEE-754 binary16とGoogleのbfloat16。それらは標準化されているので、仕様を知っている人なら誰でも実装を作成できます。いくつかの例:

または、それらを使用したくない場合は、別の16ビット浮動小数点形式を設計して実装することもできます。


floatの精度でも通常の操作には十分ではないため、2バイトのfloatは通常使用されません。帯域幅やキャッシュサイズに制限されない限り、デフォルトでdoubleを常に使用する必要があります。 CおよびCのような言語で接尾辞なしで使用する場合、浮動小数点リテラルもdoubleです。見る

ただし、 32ビット未満の浮動小数点数は存在します 。それらは主にストレージの目的で使用されます。たとえば、グラフィックスの場合、ピクセルあたり96ビット(チャネルあたり32ビット* 3チャネル)が無駄になりすぎ、通常に変換されます。計算用の32ビット浮動小数点(一部の特別なハードウェアを除く)。 OpenGLには、さまざまな 10、11、14ビットの浮動小数点型 が存在します。多くのHDR形式は各チャネルに16ビットの浮動小数点を使用し、Direct3D 9.0とRadeon R300やR420などの一部のGPUは24ビットの浮動小数点形式を持っています。 24ビット浮動小数点は、一部の8ビットマイクロコントローラーの コンパイラでもサポートされています[〜#〜] pic [〜#〜] 32ビットfloatのサポートにはコストがかかりすぎます。 8ビット以下の浮動小数点型はあまり有用ではありませんが、その単純さのため、コンピュータサイエンスのカリキュラムでよく教えられています。さらに、 ARMの命令エンコーディング で小さな浮動小数点が使用され、小さな浮動小数点の即値も使用されます。

IEEE 754-2008リビジョン は、16ビットの浮動小数点形式、AKAbinary16または 半精度 、5ビットの指数と11ビットの仮数

一部のコンパイラはIEEE-754バイナリ16をサポートしていましたが、主に変換またはベクトル化された演算をサポートし、計算はサポートしていませんでした(十分に正確ではないため)。たとえば、ARMのツールチェーンには __fp16 があり、より多くの範囲またはNaN/inf表現が必要かどうかに応じて、IEEEと代替の2つのバリアントから選択できます。 [〜#〜] gcc [〜#〜] および Clang は、標準化された名前__fp16とともに_Float16もサポートします。 x86_64 のgccで__fp16タイプを有効にする方法を参照してください

最近AIの台頭により、 bfloat16brain floating)と呼ばれる別の形式-point format )は、IEEE-754 binary32の上位16ビットの単純な切り捨てであり、一般的になりました

仮数の削減の背後にある動機は、トレーニング中に小さな差の合計の一部としてゼロに近い小さな値を表すことが可能である限り、仮数を削減しても問題ないことを示したGoogleの実験に由来します。仮数を小さくすると、乗算器の消費電力やシリコンの物理的な面積が小さくなるなど、他にも多くの利点があります。

  • float32:242 = 576(100%)
  • float16:112 = 121(21%)
  • bfloat16:82 = 64(11%)

[〜#〜] gcc [〜#〜][〜#〜] icc [〜#〜] などの多くのコンパイラもbfloat16をサポートする能力を獲得しました

Bfloat16の詳細:

2
phuclv

異なる実装には、おそらくさまざまなタイプがあります。 stdint.hに相当するfloatは良い考えのようです。サイズでタイプを(別名?)呼び出します。 (float16_t?)floatが4バイトであるのは今のところですが、おそらく小さくなりません。 halfやlongなどの用語は、時間の経過とともにほとんど意味がなくなります。 128ビットまたは256ビットのコンピューターでは、何を意味するようになる可能性があります。

画像(1 + 1 + 1バイト/ピクセル)で作業していて、平均に対する各ピクセルの値を表現したいと思います。したがって、浮動小数点または慎重に固定された点ですが、生データの4倍ではありません。 16ビットのフロートはほぼ正しい音です。

このGCC 7.3は「半分」を知らない、おそらくC++のコンテキストで。

1
Alan Corey

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ビットフロートでの計算を計算するための命令はありません)。

0
robthebloke