2010-07-18 22 views
3

J'essaie de multiplier A*B par un point fixe de 16 bits, tout en conservant la plus grande précision possible. A est 16 bits dans la plage d'entiers non signés, B est divisé par 1000 et toujours entre 0.001 et 9.999. Cela fait un moment que je traite de problèmes comme ça, donc:Multiplication à virgule fixe dans une plage connue

  • Je sais que je peux faire A*B/1000 après le déplacement des variables 32 bits, bande retour à 16 bits
  • Je voudrais rendre plus rapide que celle
  • Je voudrais faire toutes les opérations sans passer à 32 bits (depuis que j'ai multiplication 16 bits uniquement)

est-il un moyen facile de le faire?

Éditer: A sera entre 0 et 4000, de sorte que tous les résultats possibles sont également dans la plage de 16 bits.

Modifier: B vient de l'utilisateur, définir chiffre par chiffre dans le masque X.XXX, c'est pourquoi l'opération est /1000.

+0

Avez-vous une division entière non signée de 16 bits? Ou division d'un entier non signé de 32 bits par un entier non signé de 16 bits? –

+0

Ne pouvez-vous pas simplement convertir A en un de vos types à virgule fixe, puis multiplier? Ou est-A hors de portée? – George

+0

@George: à première vue, A est dans la gamme 0..65535, bien en dehors de la plage de B. –

Répondre

3

Non, vous devez aller à 32 bits. En général, le produit de deux nombres de 16 bits vous donnera toujours un résultat de 32 bits.

Vous devez vérifier le jeu d'instructions CPU de la CPU sur laquelle vous travaillez car la plupart des instructions de multiplication sur les machines 16 bits ont une option pour renvoyer le résultat sous la forme d'un entier 32 bits directement.

Cela vous aidera beaucoup parce que:

short testfunction (short a, short b) 
{ 
    int A32 = a; 
    int B32 = b; 

    return A32*B32/1000 
} 

forcerait le compilateur à faire un 32bit * 32bit se multiplient. Sur votre machine, cela peut être très lent ou même effectué en plusieurs étapes en utilisant uniquement des multiplicateurs 16 bits.

Un peu d'assemblage en ligne ou même mieux un intrinsèque du compilateur pourrait accélérer beaucoup les choses.

Voici un exemple pour le Texas Instruments C64x + DSP qui a des valeurs intrinsèques:

short test (short a, short b) 
{ 
    int product = _mpy (a,b); // calculates product, returns 32 bit integer 
    return product/1000; 
} 

Une autre pensée: Vous divisant par 1000. Était-ce votre choix constant? Il serait beaucoup plus rapide d'utiliser une puissance de deux comme base pour vos nombres à virgule fixe. 1024 est proche. Pourquoi pas vous:

return (a*b)/1024 

à la place? Le compilateur pourrait optimiser ceci en utilisant un décalage à droite de 10 bits. Cela devrait être beaucoup plus rapide que de faire des tours de multiplication réciproques.

+0

Votre exemple listé ne force * pas * le compilateur à faire une multiplication 32 bits. Puisque le compilateur peut prouver de façon triviale que 'A32' et' B32' sont tous les deux dans la plage d'un 'short', il peut très bien produire une multiplication 16x16 -> 32 à partir de ce code. – caf

+0

Caf, vous avez raison, mais connaissez-vous un compilateur qui fait cela? –

+0

gcc génère toujours les multiplicateurs les plus petits corrects. Un idiome standard pour obtenir les 32 bits supérieurs d'une multiplication 32 x 32 'x * y' est' (int64_t) x * y >> 32'. –