Você receberá como entrada um número inteiro k
no intervalo de -4503599627370496
(−2 52 ) a 4503599627370496
(2 52 ). Como é sabido , números inteiros nesse intervalo podem ser representados exatamente como valores de ponto flutuante de precisão dupla.
Você deve saída o peso de Hamming (número de ones) da codificação de k
no formato binary64 . Isso usa 1 bit para o sinal, 11 bits para o expoente (codificado com um deslocamento) e 52 para a mantissa; veja o link acima para detalhes.
Como exemplo , o número 22
é representado como
0 10000000011 0110000000000000000000000000000000000000000000000000
Como existem 5
, a saída é 5
.
Observe que o endianness não afeta o resultado; portanto, você pode usar com segurança a representação interna real de valores de dupla precisão da sua máquina para calcular a saída.
Regras adicionais
- Programas ou funções são permitidos.
- Qualquer linguagem de programação pode ser usada.
- As brechas padrão são proibidas
- O número de entrada será decimal. Fora isso, os meios e o formato de entrada / saída são flexíveis, como de costume.
- O menor código em bytes vence.
Casos de teste
22 -> 5
714 -> 6
0 -> 0
1 -> 10
4503599627370496 -> 5
4503599627370495 -> 55
1024 -> 3
-1024 -> 4
-4096 -> 5
1000000000 -> 16
-12345678 -> 16
code-golf
integer
floating-point
Luis Mendo
fonte
fonte
binary64
formato de ponto flutuante , se quiserem? Algumas pessoas (inclusive eu, inicialmente) estavam interpretando a pergunta como exigindo que as funções aceitassem entradas como um tipo inteiro como Cslong
. Em C, você pode argumentar que o idioma será convertido para você, assim como quando você ligasqrt((int)foo)
. Mas existem algumas respostas asm de código de máquina x86 (como codegolf.stackexchange.com/a/136360/30206 e mine) que ambas estavam assumindo que precisávamos aceitar entradas inteiras de 64 bits. Aceitar umbinary64
valor economizaria 5 bytes.binary64
como números inteiros base2. Se você precisar manipulá-los separadamente de qualquer maneira, pode valer a pena fazer algo diferente de digitar pun e repetir todos os bits.long
, então você não pode simplesmente dizer qualquer binary64double
, porque nem todas as duplas são inteiras. Mas todos osdouble
s com valor inteiro podem ser convertidoslong
e retornados, até os limites delong
. (Como você aponta, o inverso não é verdadeiro. Você obtém o representante mais próximodouble
, assumindo o modo de arredondamento padrão). Enfim, essa era uma maneira totalmente válida de fazer a pergunta; Eu só não lê-lo com cuidado> <.Respostas:
MATL , 5 bytes
Experimente online!
Transliteração exata da minha resposta do MATLAB. Observe que entrada e saída estão implícitas. -2 bytes graças a Luis Mendo.
fonte
linguagem de máquina x86_64 (Linux), 16 bytes
Aceita um único parâmetro inteiro de 64 bits
RDI
, converte-o para um valor de ponto flutuanteXMM0
, armazena esses bits novamenteRAX
e calcula o peso de hamming deRAX
, deixando o resultadoRAX
para que ele possa ser retornado ao chamador.Requer um processador que suporte a
POPCNT
instrução, que seria Intel Nehalem, AMD Barcelona e microarquiteturas posteriores.Para experimentá-lo online! , compile e execute o seguinte programa C:
fonte
objdump -drwC -Mintel
para desmontar na sintaxe da Intel. Se você tivesse um ponteiro em um registro que pudesse usar para armazenar / recarregar, poderia salvar bytes commovaps [rsi], xmm0
/popcnt rax, [rsi]
. (movaps é de apenas 3 bytes, 2 menores que o movq.) Mas isso não ajuda aqui, porque[rsp-24]
leva 2 bytes extras (o SIB usa o RSP como base, mais disp8). E esses bytes extras são necessários na loja e na recarga. Oh bem, eu pensei ter visto uma economia, mas não: /C (gcc) ,
8268 bytes9 bytes graças a Neil.
hacking de nível de bit de ponto flutuante mal
Experimente online!
fonte
;long l=
...;l*=2;)s+=l<0;
...long
. Funciona no Linux x86-64, mas falharia no Windows. Eu sugiro dizer "gcc com 64 bitslong
", já que o gcc é executado em muitas plataformas, muitas delas com ABIs diferentes.Python 3 ,
7271 bytes1 byte graças a Lynn.
Experimente online!
Explicação
O formato binary64 consiste em três componentes:
1
se o número for negativofonte
n and(…)-(n>0)
é um byte mais curto, não?C (gcc) , 47 bytes
Isso não é portátil; foi testado com o gcc 7.1.1 no x86_64 executando o Linux, sem sinalizadores do compilador.
Experimente online!
fonte
long
paradouble
no site da chamada?n
emrax
com código-un otimizado é bastante bregas. Ele quebra se você ativar-O3
, portanto, não é apenas o gcc em geral, é o gcc no x86-64 com 64 bitslong
com a otimização desativada. Se você colocar todos esses requisitos em sua resposta, eu votaria. Eu diria que existem plataformas suportadas pelo gcc com 64 bits,long
mas que deixam opopcountl
resultado em um registro diferente do registro de valor retornado.double
deveria estar bem. Não diz nada sobre exigir que a função aceite-a no formato base2. E sim, versões diferentes do gcc podem emitir códigos diferentes, então isso é importante também. (Curiosidade: sem-mpopcnt
, o gcc não usará opopcnt
insn e emitirá uma sequência de instruções para emulá-lo. Algumas arquiteturas não têm nenhuma instrução popcnt, portanto,__builtin_popcountl
sempre é necessário usar alguma sequência de insns)__builtin_*
funções (a maioria?) Possuem versões herdadas para evitar a geração de instruções ilegais.-march=native
usapopcntq
somente se estiver disponível.Java (OpenJDK 8) , 92 bytes
Experimente online!
fonte
C (gcc), 63 bytes
Esta solução é baseada na resposta de @ LeakyNun, mas como ele não quer melhorar sua própria resposta, estou postando aqui uma versão mais elaborada.
Experimente online
fonte
C #,
817068 bytesEconomize 11 bytes graças ao @Leaky Nun.
Economizou 2 bytes graças a @Neil.
Experimente online! Utiliza em
System.BitConverter.DoubleToInt64Bits
vez dounsafe
código, pois não consegui que o TIO trabalhasse com ele.Versão completa / formatada:
fonte
for(;l!=0;l*=2)
e você não vai precisar do ternários-=l>>31
?s+=l<0?1:0
?l
é um longo, então ele precisas-=l>>63
?Python 2 , 69 bytes
-12 bytes, graças a @ ASCII-only
Experimente online!
fonte
!
não é necessário, pois a ordem dos bytes não importa aquiJavaScript (ES6),
818077 bytesEditar: salvou 1 byte graças a @Arnauld. Economizou 3 bytes graças a @DocMax.
fonte
g(i^i&-i,x++)
por -1 byte?new Float64Array([n])
porFloat64Array.of(n)
código de máquina x86-64, 12 bytes para
int64_t
entrada6 bytes para
double
entradaRequer a
popcnt
extensão ISA (CPUID.01H:ECX.POPCNT [Bit 23] = 1
).(Ou 13 bytes, se a modificação do argumento no local exigir a gravação de todos os 64 bits, em vez de deixar o lixo nos 32 superiores. Acho razoável argumentar que o chamador provavelmente só desejaria carregar os 32b baixos de qualquer maneira e x86 zero - estende de 32 a 64 implicitamente em todas as operações de 32 bits. Ainda assim, impede o chamador de fazer
add rbx, [rdi]
algo assim.)As instruções x87 são mais curtas que o SSE2
cvtsi2sd
/ mais óbviomovq
(usado na resposta do @ ceilingcat ) e um[reg]
modo de endereçamento é do mesmo tamanho que umreg
: apenas um byte mod / rm.O truque era encontrar uma maneira de passar o valor na memória, sem precisar de muitos bytes para os modos de endereçamento. (por exemplo, passar a pilha não é tão bom.) Felizmente, as regras permitem args de leitura / gravação ou args de saída separados , para que eu possa fazer com que o chamador me passe um ponteiro para a memória que tenho permissão para escrever.
É possível chamar a partir de C com a assinatura:
void popc_double(int64_t *in_out);
apenas os 32b baixos do resultado são válidos, o que talvez seja estranho para C, mas natural para asm. (A correção disso requer um prefixo REX no armazenamento final (mov [rdi], rax
), portanto, mais um byte.) No Windows, altererdi
parardx
, pois o Windows não usa a ABI do System V x86-64.Listagem NASM. O link TIO possui o código fonte sem a desmontagem.
Experimente online! Inclui um
_start
programa de teste que transmite um valor e sai com exit status = popcnt return value. (Abra a guia "debug" para vê-lo.)Passar ponteiros de entrada / saída separados também funcionaria (rdi e rsi na ABI do x86-64 SystemV), mas não podemos destruir razoavelmente a entrada de 64 bits ou justificar facilmente a necessidade de um buffer de saída de 64 bits enquanto apenas grava o baixo 32b.
Se quisermos argumentar que podemos pegar um ponteiro para o inteiro de entrada e destruí-lo, enquanto retornamos a saída
rax
, simplesmente omita omov [rdi], eax
frompopcnt_double_outarg
, diminuindo-o para 10 bytes.Alternativa sem truques bobos de convenções de chamada, 14 bytes
use a pilha como espaço de trabalho,
push
para chegar lá. Usepush
/pop
para copiar registros em 2 bytes em vez de 3 paramov rdi, rsp
. ([rsp]
sempre precisa de um byte SIB, vale a pena gastar 2 bytes para copiarrsp
antes de três instruções que o utilizam.)Ligue de C com esta assinatura:
int popcnt_double_push(int64_t);
Aceitando entrada em
double
formatoA questão apenas diz que é um número inteiro em um determinado intervalo, não que ele precise estar em uma representação de número inteiro binário base2. Aceitar
double
entrada significa que não há mais sentido usar x87. (A menos que você use uma convenção de chamada personalizada ondedouble
s são passados nos registros x87. Em seguida, armazene na zona vermelha abaixo da pilha e popcnt a partir daí.)11 bytes:
Mas podemos usar o mesmo truque de passagem por referência de antes para criar uma versão de 6 bytes:
int pcd(const double&d);
6 bytes .
fonte
Perl 5 ,
3332 + 1 (-p) =3433 bytesGuardado 1 byte graças a hobbs
Experimente online!
fonte
d
uma palavra de barra (pack d,$_
em vez depack"d",$_
)MATLAB, 36 bytes
Usar o fato de que
de2bi
não é apenas mais curto quedec2bin
, mas também fornece um resultado em uns e zeros, em vez de ASCII 48, 49.fonte
Java (64, 61, 41 bytes)
Completamente simples usando a biblioteca padrão (Java SE 5+):
Contribuição de Kevin Cruijssen (Java SE 5+):
Contribuição de Kevin Cruijssen (Java SE 8+, função lambda):
fonte
Long n
e use emn.bitCount(...)
vez deLong.bitCount(...)
. Além disso, se você usar Java 8+, você pode golfe paran->n.bitCount(Double.doubleToLongBits(n))
( 41 bytes )Apenas para tentar uma abordagem diferente e mais segura do que TheLethalCoder , eu vim com isso (é uma pena que o C # tenha nomes de métodos tão longos):
C # (.NET Core) , 76 + 13 bytes
Experimente online!
A contagem de bytes inclui 13 bytes para
using System;
. Primeiro, preciso converter odouble
para umlong
que tenha a mesma representação binária, depois posso convertê-lo em um bináriostring
e depois contar os1
s apenas dividindo a string e contando as substrings menos 1.fonte
using
na sua contagem de bytes.namespace System.Linq;{d=>Convert.ToString(BitConverter.DoubleToInt64Bits(d),2).Count(c=>c>48)}
. Embora eu não o tenha testado, ele deve funcionar.using
diretiva.namespace
é útil. Mas sim, neste caso, evitar o Linq era um pouco mais barato. Só queria comentar com sua abordagem, caso você tenha alguma idéia de como encurtá-la para economizar bytes.Sum(c=>c&1)
é mais curto. OuSum()-768
Geléia , 19 bytes
Experimente online!
fonte
dc, 79 bytes
A saída é deixada no topo da pilha.
Vou adicionar uma explicação mais tarde.
Experimente online!
Observe que números negativos são precedidos por
_
, não-
.fonte
Groovy (com analisador Parrot) , 46 bytes
fonte
C, 67 bytes
código de controle e resultados
fonte
Erlang 55 bytes
Uma função anônima que conta todos os
1
s em um número codificado como um flutuador de 64 bits.referências:
fonte