Conversion de la point flottante en point fixe

en C++, quelle est la façon générique de convertir n'importe quelle valeur flottante (float) en point fixe (int, 16: 16 ou 24: 8)?

EDIT: pour clarifier, les valeurs à point fixe ont deux parties: une partie entière et une partie fractionnaire. La partie entière peut être représentée par un type de données entier signé ou non signé. La partie fractionnaire est représentée par un type de données entier non signé.

faisons une analogie avec l'argent par souci de clarté. La partie fractionnaire peut représenter cents -- une partie fractionnaire d'un dollar. La fourchette du type de données "cents" serait de 0 à 99. Si un entier non signé de 8 bits devait être utilisé pour les mathématiques à point fixe, alors la partie fractionnaire serait divisée en 256 parties également divisibles.

j'espère que efface les choses.

21
demandé sur Kevin 2008-10-09 19:10:07

6 réponses

Ici, vous allez:

// A signed fixed-point 16:16 class
class FixedPoint_16_16
{
    short          intPart;
    unsigned short fracPart;

public:
    FixedPoint_16_16(double d)
    {
        *this = d; // calls operator=
    }

    FixedPoint_16_16& operator=(double d)
    {
        intPart = static_cast<short>(d);
        fracPart = static_cast<unsigned short>
                    (numeric_limits<unsigned short> + 1.0)*d);
        return *this;
    }

    // Other operators can be defined here
};

EDIT: Voici une classe plus générale basée sur une autre manière commune de traiter les nombres à points fixes (et que KPexEA a fait remarquer):

template <class BaseType, size_t FracDigits>
class fixed_point
{
    const static BaseType factor = 1 << FracDigits;

    BaseType data;

public:
    fixed_point(double d)
    {
        *this = d; // calls operator=
    }

    fixed_point& operator=(double d)
    {
        data = static_cast<BaseType>(d*factor);
        return *this;
    }

    BaseType raw_data() const
    {
        return data;
    }

    // Other operators can be defined here
};


fixed_point<int, 8> fp1;           // Will be signed 24:8 (if int is 32-bits)
fixed_point<unsigned int, 16> fp1; // Will be unsigned 16:16 (if int is 32-bits)
26
répondu Kevin 2016-03-23 16:34:17

un moulage de flotteur à entier va jeter la partie fractionnaire donc si vous voulez garder cette fraction autour comme point fixe, alors vous venez de multiplier le flotteur avant de le couler. Le code ci-dessous ne vérifiera pas de débordement d'Esprit vous.

Si vous voulez 16:16

double f = 1.2345;
int n;

n=(int)(f*65536);

si vous voulez 24:8

double f = 1.2345;
int n;

n=(int)(f*256);
19
répondu KPexEA 2008-10-09 15:29:14

**** * Edit**: mon premier commentaire s'applique avant l'édition de Kevin, mais je vais le laisser ici pour la postérité. Réponses changer si vite parfois!

le problème avec L'approche de Kevin est qu'avec un point fixe vous êtes normalement empaqueter dans une taille de mot garantie (typiquement 32bits). Déclarer les deux parties séparément vous laisse au caprice de l'empaquetage de la structure de votre compilateur. Oui, vous pouvez le forcer, mais il ne fonctionne pas pour rien d'autre que 16:16 représentation.

KPexEA est plus proche de la marque en emballant tout dans int - bien que j'utiliserais "signé long" pour essayer d'être explicite sur 32bits. Ensuite, vous pouvez utiliser son approche pour générer la valeur de point fixe, et BIT slicing extraire les composants à nouveau. Sa suggestion couvre également l'affaire 24:8.

(et tous ceux qui ont suggéré juste static_cast.....que pensiez-vous? ;))

7
répondu Greg Whitfield 2008-10-09 16:17:05

j'ai donné la réponse au gars qui a écrit la meilleure réponse, mais j'ai vraiment utilisé une des questions connexes code points ici.

il utilisait des gabarits et était facile de se débarrasser des dépendances sur la lib boost.

1
répondu CVertex 2018-08-22 12:23:27

c'est très bien pour passer de la virgule flottante à l'entier, mais L'O. P. voulait aussi point fixe.

maintenant comment vous feriez cela en C++, Je ne sais pas (C++ n'étant pas quelque chose que je peux penser facilement). Peut-être essayer une approche d'échelle-entier, c.-à-d. utiliser un 32 ou 64 bits entier et programmatically attribuer le dernier, disons, 6 chiffres à ce qui est sur le côté droit de la virgule décimale.

0
répondu bugmagnet 2008-10-09 15:28:02

Il n'y a pas de support intégré en C++ pour les points fixes. Votre meilleur pari serait d'écrire une classe d'emballage "FixedInt" qui prend des doubles et les convertit.

Comme pour une méthode générique pour convertir... la partie int est assez facile, il suffit de saisir la partie entière de la valeur et de la stocker dans les bits supérieurs... partie décimale serait quelque chose le long des lignes de:

for (int i = 1; i <= precision; i++)
{
   if (decimal_part > 1.f/(float)(i + 1)
   {
      decimal_part -= 1.f/(float)(i + 1);
      fixint_value |= (1 << precision - i);
   }
}

bien que cela soit susceptible de contenir encore des bogues

-4
répondu workmad3 2008-10-09 15:32:18