Vous recevrez en entrée un entier k
compris entre -4503599627370496
(−2 52 ) et 4503599627370496
(2 52 ). Comme cela est bien connu , les nombres entiers dans cette plage peuvent être représentés exactement comme des valeurs à virgule flottante double précision.
Vous devez sortir le poids de Hamming (nombre d'un) de l'encodage k
au format binaire64 . Cela utilise 1 bit pour le signe, 11 bits pour l'exposant (codé avec un décalage) et 52 pour la mantisse; voir le lien ci-dessus pour plus de détails.
Par exemple , le nombre 22
est représenté par
0 10000000011 0110000000000000000000000000000000000000000000000000
Puisqu'il y 5
en a, la sortie est 5
.
Notez que l'endianité n'affecte pas le résultat, vous pouvez donc utiliser en toute sécurité la représentation interne réelle de votre machine des valeurs de double précision pour calculer la sortie.
Règles supplémentaires
- Les programmes ou fonctions sont autorisés.
- N'importe quel langage de programmation peut être utilisé.
- Les failles standard sont interdites
- Le numéro saisi sera en décimal. En dehors de cela, les moyens et le format d'entrée / sortie sont flexibles comme d'habitude.
- Le code le plus court en octets gagne.
Cas de test
22 -> 5
714 -> 6
0 -> 0
1 -> 10
4503599627370496 -> 5
4503599627370495 -> 55
1024 -> 3
-1024 -> 4
-4096 -> 5
1000000000 -> 16
-12345678 -> 16
la source
binary64
format à virgule flottante si elles le souhaitent? Certaines personnes (dont moi - même, d' abord) interprétaient la question exigeant que les fonctions acceptent des entrées comme un type entier comme C delong
. En C, vous pouvez affirmer que la langue se convertira pour vous, tout comme lorsque vous appelezsqrt((int)foo)
. Mais il existe des réponses asm de code machine x86 (comme codegolf.stackexchange.com/a/136360/30206 et la mienne) qui supposaient toutes les deux que nous devions accepter des entrées entières 64 bits. Accepter unebinary64
valeur économiserait 5 octets.binary64
entier en base2. Si vous devez les gérer séparément de toute façon, cela peut valoir la peine de faire autre chose que de taper et boucler sur tous les bits.long
, donc vous ne pouvez pas simplement dire n'importe quel binaire64double
, car tous les doubles ne sont pas des entiers. Mais tous lesdouble
s à valeur entière peuvent être convertis enlong
et en arrière, jusqu'aux limites delong
. (Comme vous le faites remarquer, l'inverse n'est pas vrai. Vous obtenez le représentant le plus prochedouble
, en supposant le mode d'arrondi par défaut). Quoi qu'il en soit, c'était une façon tout à fait valable de poser la question; Je ne l'ai tout simplement pas lu attentivement. <Réponses:
MATL , 5 octets
Essayez-le en ligne!
Translittération exacte de ma réponse MATLAB. Notez que l'entrée et la sortie sont implicites. -2 octets grâce à Luis Mendo.
la source
langage machine x86_64 (Linux), 16 octets
Accepte un seul paramètre entier 64 bits dans
RDI
, le convertit en une valeur à virgule flottante dansXMM0
, stocke ces bitsRAX
, puis calcule le poids de hachage deRAX
, laissant le résultat dansRAX
afin qu'il puisse être retourné à l'appelant.Nécessite un processeur qui prend en charge l'
POPCNT
instruction, qui serait Intel Nehalem, AMD Barcelona et les microarchitectures ultérieures.Pour l' essayer en ligne! , compilez et exécutez le programme C suivant:
la source
objdump -drwC -Mintel
pour démonter dans la syntaxe Intel. Si vous aviez un pointeur dans un registre que vous pouviez utiliser pour stocker / recharger, vous pourriez enregistrer des octets avecmovaps [rsi], xmm0
/popcnt rax, [rsi]
. (movaps n'est que de 3 octets, 2 plus court que movq.) Mais cela n'aide pas ici, car[rsp-24]
prend 2 octets supplémentaires (SIB en utilisant RSP comme base, plus disp8). Et ces octets supplémentaires sont nécessaires à la fois dans le magasin et le rechargement. Eh bien, je pensais avoir vu une économie, mais non: /C (gcc) ,
8268 octets9 octets grâce à Neil.
piratage de niveau de bit à virgule flottante mal
Essayez-le en ligne!
la source
;long l=
...;l*=2;)s+=l<0;
...long
. Il fonctionne sous Linux x86-64, mais échouerait sous Windows. Je suggère de dire "gcc avec 64 bitslong
", car gcc fonctionne sur de nombreuses plates-formes, beaucoup d'entre elles avec différents ABI.Python 3 ,
7271 octets1 octet merci à Lynn.
Essayez-le en ligne!
Explication
Le format binaire64 se compose de trois composants:
1
si le nombre est négatifla source
n and(…)-(n>0)
est un octet plus court, non?C (gcc) , 47 octets
Ce n'est pas portable; il a été testé avec gcc 7.1.1 sur x86_64 sous Linux, sans drapeaux de compilation.
Essayez-le en ligne!
la source
long
versdouble
sur le site d'appel?n
durax
code non optimisé est assez ringard. Il casse si vous activez-O3
, donc ce n'est pas seulement gcc en général, c'est gcc sur x86-64 avec 64 bitslong
avec l'optimisation désactivée. Si vous mettez toutes ces exigences dans votre réponse, je voterais favorablement. Je suppose qu'il existe des plates-formes gcc prises en charge qui ont 64 bits,long
mais qui se trouvent laisser lepopcountl
résultat dans un registre autre que le registre de valeur de retour.double
devrait être très bien. Il ne dit rien d'exiger que la fonction l'accepte au format base2. Et oui, différentes versions de gcc peuvent émettre un code différent, c'est donc important aussi. (Fait amusant: sans-mpopcnt
, gcc n'utilisera pas l'popcnt
insn et émettra une séquence d'instructions pour l'émuler. Certaines architectures n'ont pas du tout d'instruction popcnt, donc__builtin_popcountl
doit toujours utiliser une séquence d'insns)__builtin_*
Ont des versions héritées pour éviter de générer des instructions illégales.-march=native
utilisepopcntq
uniquement s'il est disponible.Java (OpenJDK 8) , 92 octets
Essayez-le en ligne!
la source
C (gcc), 63 octets
Cette solution est basée sur la réponse de @ LeakyNun, mais parce qu'il ne veut pas améliorer sa propre réponse, je poste ici une version plus golfée.
Essayez-le en ligne
la source
C #,
817068 octetsÉconomisez 11 octets grâce à @Leaky Nun.
Enregistré 2 octets grâce à @Neil.
Essayez-le en ligne! Utilise à la
System.BitConverter.DoubleToInt64Bits
place duunsafe
code car je n'ai pas pu faire fonctionner TIO avec.Version complète / formatée:
la source
for(;l!=0;l*=2)
et vous n'aurez pas besoin du ternaires-=l>>31
?s+=l<0?1:0
?l
est long, donc il a besoins-=l>>63
?Python 2 , 69 octets
-12 octets, grâce à @ ASCII uniquement
Essayez-le en ligne!
la source
!
n'est pas nécessaire car l'ordre des octets n'a pas d'importance iciJavaScript (ES6),
818077 octetsEdit: 1 octet enregistré grâce à @Arnauld. Enregistré 3 octets grâce à @DocMax.
la source
g(i^i&-i,x++)
pour -1 octet?new Float64Array([n])
parFloat64Array.of(n)
code machine x86-64, 12 octets pour
int64_t
entrée6 octets pour l'
double
entréeNécessite l'
popcnt
extension ISA (CPUID.01H:ECX.POPCNT [Bit 23] = 1
).(Ou 13 octets si la modification de l'argument sur place nécessite l'écriture de tous les 64 bits, au lieu de laisser des ordures dans les 32 supérieurs. Je pense qu'il est raisonnable de dire que l'appelant ne voudra probablement que charger le 32b bas de toute façon, et x86 zéro -étend implicitement de 32 à 64 à chaque opération 32 bits. Néanmoins, cela empêche l'appelant de faire
add rbx, [rdi]
quelque chose.)Les instructions x87 sont plus courtes que la SSE2
cvtsi2sd
/ la plus évidentemovq
(utilisée dans la réponse de @ plafondcat ), et un[reg]
mode d'adressage a la même taille qu'unreg
: juste un octet mod / rm.L'astuce consistait à trouver un moyen de faire passer la valeur en mémoire, sans avoir besoin de trop d'octets pour les modes d'adressage. (Par exemple, transmettre la pile n'est pas terrible.) Heureusement, les règles autorisent les arguments de lecture / écriture ou les arguments de sortie séparés , donc je peux simplement demander à l'appelant de me passer un pointeur sur la mémoire que je suis autorisé à écrire.
Appelable depuis C avec la signature:
void popc_double(int64_t *in_out);
seul le 32b bas du résultat est valide, ce qui est peut-être bizarre pour C mais naturel pour asm. (La correction de ce problème nécessite un préfixe REX sur le magasin final (mov [rdi], rax
), donc un octet de plus.) Sous Windows, passezrdi
àrdx
, car Windows n'utilise pas le x86-64 System V ABI.Liste NASM. Le lien TIO a le code source sans le démontage.
Essayez-le en ligne! Comprend un
_start
programme de test qui lui transmet une valeur et se termine avec exit status = popcnt return value. (Ouvrez l'onglet "debug" pour le voir.)Passer des pointeurs d'entrée / sortie séparés fonctionnerait également (rdi et rsi dans l'ABI System86 x64-64), mais nous ne pouvons alors pas raisonnablement détruire l'entrée 64 bits ou justifier aussi facilement d'avoir besoin d'un tampon de sortie 64 bits tout en écrivant uniquement le faible 32b.
Si nous voulons affirmer que nous pouvons prendre un pointeur sur l'entier d'entrée et le détruire, tout en renvoyant la sortie dans
rax
, puis simplement omettre lemov [rdi], eax
frompopcnt_double_outarg
, le ramenant à 10 octets.Alternative sans astuces de convention d'appel idiotes, 14 octets
utilisez la pile comme espace de travail,
push
pour y arriver. Utilisezpush
/pop
pour copier les registres en 2 octets au lieu de 3 pourmov rdi, rsp
. ([rsp]
nécessite toujours un octet SIB, il vaut donc la peine de dépenser 2 octets à copierrsp
avant trois instructions qui l'utilisent.)Appelez de C avec cette signature:
int popcnt_double_push(int64_t);
Accepter une entrée au
double
formatLa question dit simplement que c'est un entier dans une certaine plage, pas qu'il doive être dans une représentation d'entier binaire base2. Accepter l'
double
entrée signifie qu'il n'y a plus aucun intérêt à utiliser x87. (À moins que vous n'utilisiez une convention d'appel personnalisée dans laquelle lesdouble
s sont passés dans les registres x87. Ensuite, stockez-les dans la zone rouge sous la pile et ouvrez-les à partir de là.)11 octets:
Mais nous pouvons utiliser la même astuce passe-par-référence qu'avant pour créer une version à 6 octets:
int pcd(const double&d);
6 octets .
la source
Perl 5 ,
3332 + 1 (-p) =3433 octets1 octet enregistré grâce à Hobbs
Essayez-le en ligne!
la source
d
un bareword (pack d,$_
au lieu depack"d",$_
)MATLAB, 36 octets
En utilisant le fait qui
de2bi
est non seulement plus court quedec2bin
, mais fournit également un résultat en uns et en zéros plutôt qu'en ASCII 48, 49.la source
Java (64, 61, 41 octets)
Complètement simple en utilisant la bibliothèque standard (Java SE 5+):
Contribution de Kevin Cruijssen (Java SE 5+):
Contribution de Kevin Cruijssen (Java SE 8+, fonction lambda):
la source
Long n
et utilisezn.bitCount(...)
plutôt queLong.bitCount(...)
. De plus, si vous utilisez Java 8+, vous pouvez len->n.bitCount(Double.doubleToLongBits(n))
Juste pour essayer une approche différente et plus sûre que TheLethalCoder , j'ai trouvé ceci (c'est dommage que C # ait des noms de méthode si longs):
C # (.NET Core) , 76 + 13 octets
Essayez-le en ligne!
Le nombre d'octets comprend 13 octets pour
using System;
. Je dois d'abord convertir ledouble
en unlong
qui a la même représentation binaire, puis je peux le convertir en un binairestring
, puis je compte les1
s juste en divisant la chaîne et en comptant les sous-chaînes moins 1.la source
using
dans votre nombre d'octets.namespace System.Linq;{d=>Convert.ToString(BitConverter.DoubleToInt64Bits(d),2).Count(c=>c>48)}
. Bien que je ne l'ai pas testé, cela devrait fonctionner.using
directive.namespace
est utile. Mais oui, dans ce cas, éviter Linq était légèrement moins cher. Je voulais juste commenter son approche au cas où vous auriez des idées sur la façon de la raccourcir pour vous faire économiser des octets.Sum(c=>c&1)
est plus court. OuSum()-768
Gelée , 19 octets
Essayez-le en ligne!
la source
dc, 79 octets
La sortie est laissée en haut de la pile.
J'ajouterai une explication plus tard.
Essayez-le en ligne!
Notez que les nombres négatifs sont précédés de
_
, non-
.la source
Groovy (avec analyseur Parrot) , 46 octets
la source
C, 67 octets
code de contrôle et résultats
la source
Erlang 55 octets
Une fonction anonyme qui compte tous les
1
s dans un nombre codé comme un flottant de 64 bits.les références:
la source