7
votes

_BitscanForward en C #?

Je traduit un programme écrit en C ++ en C # et je suis tombé sur une fonction intrinsèque que je ne peux pas contourner. En C ++, il est connu sous le nom de: xxx

Si je savais que la DLL, le cas échéant, les fonctions intrinsèques étaient dans, je pourrais utiliser p / invoquer. Depuis que je ne sais pas, j'ai cherché des alternatives dans le .NET Framework, mais je suis venu des mains vides.

Est-ce que quelqu'un sait comment utiliser p / invoquer sur _bitscanforforward ou une méthode .NET qui fait le Même chose?

Toute aide est appréciée, merci.


5 Réponses :


6
votes

Les fonctions intrinsèques ne sont dans aucune bibliothèque, elles sont implémentées à l'intérieur de la CPU, le compilateur émet le Code de la machine que la CPU reconnaît comme évoquant ce comportement particulier.

Ils sont un moyen d'accéder à des instructions qui n'ont pas d'équivalent C simple.

jusqu'à ce que l'optimiseur .NET devienne suffisamment intelligent pour les reconnaître (par exemple, le MONO JIT reconnaît certaines instructions SIMD, codées dans MSIL comme des appels vers des fonctions d'une classe particulière, de la même manière, le fichier .NET JIT remplace les appels à System.Math Modes Avec des opérations à point flottant), votre code C # est condamné pour exécuter un ordre de magnitude plus lentement que l'original C ++.


0 commentaires

3
votes

La fonction _bitscanforward C ++ est une fonction de compilateur intrinsèque. Il trouve le premier sur bit dans une séquence d'octets à la recherche du bit de commande le plus bas au plus haut et renvoyant la valeur du bit. Vous pouvez probablement mettre en œuvre quelque chose de similaire à l'aide de tactiques de manipulation de bits en C # (bien que cela ne s'approchera jamais de la même performance). Si vous êtes à l'aise avec une manipulation de bits en C ++, c'est fondamentalement la même chose en C #.


0 commentaires

2
votes

Il n'est pas possible de p / invoquer _bitscanforward car il s'agit d'un compilateur intrinsèque, et non d'une fonction de bibliothèque réelle (elle est traduite par le compilateur Visual C ++ sur une instruction BSF X86 Machine). Pour autant que je sache, il n'y a pas d'instruction MSIL pour cette opération «Trouver une première définition». La chose la plus simple à faire est de rédiger votre propre DLL natif C ++ qui exporte une fonction qui appelle _bitscanforward (), puis p / invoquer cela.

Vous pouvez également l'écrire directement dans C # à l'aide de la manipulation de bits (voir algorithmes pour trouver la première place dans Wikipedia ). Je ne sais pas si cela serait plus rapide ou plus lent que p / invoquer. Mesurer et découvrir.


1 commentaires

Les conseils sont en quelque sorte le contraire en face de la raison de cette fonction fabriquée intrinsèque ... mais Pinvoke peut-être que ça va aussi ...



3
votes

_bitscanforward recherche le premier Définir un bit dans un entier, à partir du bit le moins significatif à la recherche du bit le plus significatif. Il compile le BSF instruction sur le X86 plate-forme.

La page BIG TwidDling Hacks comprend une poignée d'algorithmes de remplacement potentiels qui exceller dans différentes situations. Il y a une fonction O (n) (que la moitié du temps avec des entrées uniformément distribuées revient avec une seule itération) et certaines options sub-linéaires, et certaines qui utilisent des étapes de multiplication. Choisir un pourrait ne pas être trivial , mais tout devrait fonctionner.


0 commentaires

2
votes

WOW, on dirait qu'il y a une question sur c # qui n'a pas encore été couverte par les améliorations récentes.

Les autres commentateurs ont correctement noté que les intrinsèques comme _bitscanferfor ne sont pas des fonctions en soi, ce sont plutôt des marqueurs pour le Compilateur pour injecter une instruction de plate-forme spécifique dans le code d'objet. Il est impossible d'imiter un intrinsèque dans une langue de haut niveau (sauf si vous êtes prêt à payer une pénalité d'abstraction). Cependant, de bonnes nouvelles sont que commencer avec .NET CORE 3.0 Le JIT prend en charge la intrinsèque pour un certain nombre de plates-formes matérielles.

pour le _bitscanforward, vous pouvez utiliser System.Runtime.Intrinsics.x86.bmi1.TrarseZount .

garde : n'oubliez pas de vérifier bmi1.issupporté Avant d'utiliser, sinon le code échouerait au moment de l'exécution.

Vous pouvez aussi Obtenez une vitesse d'exécution décente sur le bras (.NET 5.0+) en utilisant leur intrinsèque FFS: xxx

Si aucune autre plate-forme n'est présente, vous devriez avoir recours au bit-Twiddling Hacks comme des séquences de De-Bruijun: xxx

(extrait de https://fr.wikipedia.org/wiki/wiki/find_first_set )

Selon les restrictions de la tâche, je choisirais des stratégies différentes de l'algorithme SELECTI au moment de l'exécution. La ramification sur chaque appel est susceptible de tuer toute l'efficacité. La manière la plus efficace consiste à agir sur un niveau supérieur - c'est-à-dire avoir trois versions de votre code à choisir au moment de l'exécution. Un moyen facile d'automatiser le codeGen est de disposer de votre code dans un générique de paramétrage avec un type de manutention de bits: xxx

puis nous définissons quelques structures implémentant notre scanner: < / p> xxx

Maintenant, chaque fois que nous avons besoin d'une version de mystage spécifique à la plate-forme, nous le faisons via MyFunction . Etre struct, le paramètre type force JIT pour générer le code spécifique pour celui-ci au lieu d'un générique d'un appel virtuel. Ensuite, comme la T est connue à JIT Time, l'appel à Bitscanforforfie est inlincé et finit par l'injection intrinsèque appropriée dans la boucle. Selon la taille de la tâche MyFunction, cette version de myfunction peut être enregistrée dans un délégué, faire partie d'une interface ou faire partie d'une structure qui implémente une interface pour répéter le niveau d'un niveau supérieur.

Note Cette question originale ne s'est pas préoccupée par la compatibilité multiplate-forme, car le _bitscanforward est une instruction uniquement. C'est probablement acceptable dans le monde C ++ de compiler un exécutable contre une combinaison spécifique OS & HW; Code géré contemporain comme Java / .NET a une chance d'être exécuté n'importe où.


0 commentaires