web-dev-qa-db-fra.com

Pourquoi n'y a-t-il pas de flotteur de 2 octets et une implémentation existe-t-elle déjà?

En supposant que je suis vraiment pressé pour la mémoire et que vous voulez une gamme plus petite (semblable à short vs int). Shader Langues Support déjà half pour un type à point flottant avec la moitié de la précision (non seulement convertir la valeur pour être compris entre -1 et 1, renvoie un flottant comme celui-ci: shortComingIn / maxRangeOfShort). Existe-t-il une implémentation qui existe déjà pour un flotteur de 2 octets?

Je suis également intéressé à connaître des raisons (historiques?) Quant pourquoi il n'y a pas de flotteur de 2 octets.

29
Samaursa

si vous avez une mémoire faible, avez-vous envisagé de laisser tomber le concept de flotteur? Les flotteurs utilisent beaucoup de bits juste pour économiser d'où le point décimal est .. Vous pouvez contourner cela si vous SAVOIR où vous avez besoin du point décimal, disons que vous voulez économiser une valeur dollar, vous. pourrait simplement l'enregistrer dans des cents:

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

Cela n'existe bien sûr qu'une option s'il est possible pour vous de prédéterminer la position du point décimal. Mais si vous le pouvez, préférez-le toujours, car cela accélère également tous les calculs!

rgds, kira :-)

13
Kirab

est AN IEEE 754 Standard pour les flotteurs 16 bits .

C'est un nouveau format, ayant été normalisé en 2008 sur la base d'un GPU publié en 2002.

5
dan04

Pour aller un peu plus loin que kiralein sur la commutation en entiers, nous pourrions définir une plage et permettre aux valeurs d'entier d'un court-circuit de représenter une division égale sur la gamme, avec une certaine symétrie si elle est à la chevauche zéro:

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

Différences entre ces versions entière et utilisant des flotteurs de demi précision:

  1. Les entiers sont également espacés sur la gamme, tandis que les flotteurs sont plus densément emballés près de zéro
  2. L'utilisation d'entiers utilisera des mathématiques entier dans la CPU plutôt que sur le point flottant. C'est souvent plus rapide car les opérations entière sont plus simples. Cela dit, la cartographie des valeurs sur une plage asymétrique nécessiterait des ajouts supplémentaires, etc. pour récupérer la valeur à la fin.
  3. La perte de précision absolue est plus prévisible; Vous connaissez l'erreur dans chaque valeur afin que la perte totale puisse être calculée à l'avance, compte tenu de la plage. Inversement, l'erreur relative est plus prévisible en utilisant un point flottant.
  4. Il peut y avoir une petite sélection d'opérations que vous pouvez effectuer à l'aide de paires de valeurs, notamment des opérations dans les bits, en emballant deux shorts dans un Int. Cela peut réduire de moitié le nombre de cycles nécessaires (ou plus, si des opérations courtes impliquent une fonte à int) et maintiennent une largeur de 32 bits. Il s'agit simplement d'une version diluée de tranchage bit où 32 bits sont agités en parallèle, qui est utilisé dans Crypto.
3
Phil H

Il existe probablement une variété de types dans différentes implémentations. Un équivalent flotteur de stdint.h semble être une bonne idée. Appelez (alias?) Les types par leurs tailles. (float16_t?) Un flotteur d'étant 4 octets n'est que pour le moment, mais cela ne sera probablement pas plus petit. Les termes comme la moitié de la moitié deviennent principalement sans signification avec le temps. Avec des ordinateurs de 128 ou 256 bits, ils pourraient dire quoi que ce soit.

Je travaille avec des images (1 + 1 + 1 octet/pixel) et je souhaite exprimer la valeur de chaque pixel par rapport à la moyenne. Donc, un point flottant ou un point soigneusement fixe, mais pas 4 fois plus gros que les données brutes s'il vous plaît. Un flotteur de 16 bits sonne à peu près bien.

Ce GCC 7.3 ne connaît pas "la moitié", peut-être dans un contexte C++.

1
Alan Corey

Si votre CPU prend en charge F16C, vous pouvez obtenir quelque chose de haut et de fonctionner assez rapidement avec quelque chose comme:

// 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;
  }
};

Les mathématiques sont toujours effectuées en utilisant des flotteurs 32 bits (les extensions F16C ne fournissent que des conversions entre 16/32 bits flottants - aucune instruction n'existe pour calculer arithmétique avec des flotteurs 16 bits).

0
robthebloke