A Base do Duplo

12

fundo

O formato de ponto flutuante de precisão dupla IEEE 754 é uma maneira de representar números reais com 64 bits. Parece o seguinte:

Um número real né convertido doubleem da da seguinte maneira:

  1. O bit do sinal sé 0 se o número for positivo, 1 caso contrário.
  2. O valor absoluto de né representado na forma 2**y * 1.xxx, ou seja, uma potência de 2 vezes a base .
  3. O expoente eé y(a potência de 2) menos 1023.
  4. A fração fé a xxxparte (parte fracionária da base), levando os 52 bits mais significativos.

Por outro lado, um padrão de bits (definido por sinal s, expoente ee fração f, cada um inteiro) representa o número:

(s ? -1 : 1) * 2 ** (e - 1023) * (1 + f / (2 ** 52))

Desafio

Dado um número real n, imprima sua parte da fração de 52 bits da doublerepresentação ncomo um número inteiro.

Casos de teste

0.0        =>                0
1.2        =>  900719925474099 (hex 3333333333333)
3.1        => 2476979795053773 (hex 8cccccccccccd)
3.5        => 3377699720527872 (hex c000000000000)
10.0       => 1125899906842624 (hex 4000000000000)
1234567.0  =>  798825262350336 (hex 2d68700000000)
1e-256     => 2258570371166019 (hex 8062864ac6f43)
1e+256     => 1495187628212028 (hex 54fdd7f73bf3c)

-0.0       =>                0
-1.2       =>  900719925474099 (hex 3333333333333)
-3.1       => 2476979795053773 (hex 8cccccccccccd)
-3.5       => 3377699720527872 (hex c000000000000)
-10.0      => 1125899906842624 (hex 4000000000000)
-1234567.0 =>  798825262350336 (hex 2d68700000000)
-1e-256    => 2258570371166019 (hex 8062864ac6f43)
-1e+256    => 1495187628212028 (hex 54fdd7f73bf3c)

Você pode verificar outros números usando esta referência C, que usa campos de bits e uma união.

Observe que a resposta esperada é a mesma para +ne -npara qualquer número n.

Entrada e saída

Aplicam-se regras padrão.

Formato de entrada aceito:

  • Um número de ponto flutuante, pelo menos com doubleprecisão internamente
  • Uma representação em seqüência do número em decimal (você não precisa suportar notação científica, pois pode usar 1000...00ou 0.0000...01como entrada)

Para saída, um erro de arredondamento no bit menos significativo é tolerável.

Condição vencedora

Isso é , então os bytes mais baixos em cada idioma vencem.

Bubbler
fonte
Postagem em sandbox (excluída)
Bubbler 31/03
1
Os casos de teste incluem apenas números não negativos. A entrada pode ser negativa?
Dennis
@Dennis Sim. Vou adicionar mais alguns casos de teste.
Bubbler
3
Sua descrição do formato de ponto flutuante IEEE não menciona números desnormais que são interpretados de uma maneira ligeiramente diferente (sem avanço implícito 1). Os denormais precisam ser manuseados corretamente?
Nwellnhof 31/03/19
1
@nwellnhof Você não precisa considerar denormals, NaN e Infinity.
Bubbler 31/03

Respostas:

8

C (gcc) , 42 30 bytes

long f(long*p){p=*p&~0UL>>12;}

Leva um ponteiro para o dobro como argumento e retorna um longo .

Requer longs de 64 bits e gcc (comportamento indefinido).

Obrigado a @nwellnhof por -2 bytes!

Experimente online!

Dennis
fonte
&~0UL>>12é dois bytes mais curto. A macro só funciona com lvalues.
Nwellnhof 31/03/19
Use macro -Df(x)=*(long *)&x&~0UL>>12, salve 3 bytes. TIO
GPS
6

Haskell, 27 31 bytes

(`mod`2^52).abs.fst.decodeFloat

decodeFloatretorna o significando e o expoente, mas, por alguma razão, o primeiro está com 53 bits em Haskell, então precisamos cortar um pouco.

Experimente online!

nimi
fonte
5

Python 3 , 54 50 bytes

f=lambda x:int(x.hex().split('.')[1].split('p')[0],16)

Experimente online!

Com a sugestão de Kirill:

f=lambda x:int(x.hex()[4+(x<0):].split('p')[0],16)

Experimente online!

Luca Citi
fonte
Posso estar errado, mas acho que o Python hex()fornece uma notação normalizada que sempre começa com 0x1.. Nesse caso, você pode usar isso por 44 bytes.
31518 Kirill L.Mar
1
Bem, eu esqueci números negativos, então parece 50 bytes afinal.
Kirill L.
@ kirill-l Nem sempre começa com "1". (veja por exemplo (2 ** - 1028)), mas o OP não diz nada sobre subnormais, então acho que sua segunda sugestão é aceitável. Sinta-se livre para editar.
Luca Citi
Na verdade, em um comentário recente, o OP diz explicitamente que podemos ignorar com segurança subnormais.
Luca Citi
5

Linguagem de máquina x86_64 para Linux, 14 bytes

0:       66 48 0f 7e c0          movq   %xmm0,%rax
5:       48 c1 e0 0c             shl    $0xc,%rax
9:       48 c1 e8 0c             shr    $0xc,%rax
d:       c3                      retq

Experimente online!

teto
fonte
tente usar seu próprio CC em vez da ABI padrão. Ao exigir o duplo estar em rax, você pode facilmente remover todo o movimento de xmm0. Somente a mudança necessária para isso é tornar a estrutura de teste no ASM, e não no C (a menos que o GCC seja extremamente inteligente).
usar o seguinte código
4

MATL , 10 bytes

IZ%52W\0YA

Experimente online!

Explicação

        % Implicit input
IZ%     % Cast to uint64 without changing underlying byte representation
52W     % Push 2^52
\       % Modulus
0YA     % Convert to decimal. Gives a string. This is needed to avoid
        % the number being displayed in scientific notation
        % Implicit display
Luis Mendo
fonte
4

JavaScript (ES7), 52 50 bytes

f=n=>n?n<0?f(-n):n<1?f(n*2):n<2?--n*2**52:f(n/2):0
<input oninput=o.textContent=f(this.value)><pre id=o>0

Não usar Math.floor(Math.log2(n))porque não é garantido que seja preciso. Editar: salvou 2 bytes graças a @DanielIndie.

Neil
fonte
por que não -N * 2 ** 52
DanielIndie
@DanielIndie Porque eu esqueci que que o golfe funciona com flutuadores ...
Neil
3

Perl 5 -pl , 28 bytes

$_=-1>>12&unpack Q,pack d,$_

Experimente online!

Os casos de teste 1e-256 e 1e256 estão desativados, mas isso ocorre porque o Perl 5 converte inexatamente cadeias enormes ou minúsculas de ponto flutuante.

Nwellnhof
fonte
2

Macro C (gcc) , 49 bytes

-DF(x)=x?ldexp(frexp(fabs(x),(int[1]){})-.5,53):0

Experimente online!

Retorna uma, doublemas assumindo precisão IEEE, ela não terá uma parte fracionária. Também lida com números negativos agora.

Nwellnhof
fonte
2

T-SQL , 80 bytes

SELECT CAST(CAST(n AS BINARY(8))AS BIGINT)&CAST(4503599627370495AS BIGINT)FROM t

A entrada é obtida da coluna nde uma tabela denominada t:

CREATE TABLE t (n FLOAT)
INSERT INTO t VALUES (0.0),(1.2),(3.1),(3.5),(10.0),(1234567.0),(1e-256),(1e+256)

SQLFiddle

Razvan Socol
fonte
2

Hoon , 25 bytes

|*(* (mod +< (pow 2 52)))

Crie uma função genérica que retorne o mod de entrada 2^52.

Chamando:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
RenderSettings
fonte
Eu nunca pensei que veria hoon aqui. Tentei entender o urbit há alguns anos, mas não conseguia entender direito.
recursivo
2

JavaScript (ES7), 98 76 bytes

Economizou 22 (!) Bytes graças a @Neil

Mais detalhado que a resposta de Neil , mas eu queria tentar com matrizes digitadas .

(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l

Experimente online!

Arnauld
fonte
O ES7 + UInt32Arraysalva 22 bytes:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Neil
Existe algum intérprete que BigInt64Arrayjá tenha implementado ?
Tsh
1

Stax , 19 14 bytes

üâïc-Hò~÷]ó┬ó♪

Execute e depure

Descompactado, não jogado e comentado, o código fica assim.

|a      absolute value
{HcDw   double until there's no fractional part
@       convert to integer type
:B      convert to binary digits
D52(    drop the first digit, then pad to 52
:b      convert back number

Execute este

recursivo
fonte
0

Ruby , 39 bytes

->n{[n].pack(?D).unpack(?Q)[0]&~-2**52}

Experimente online!

Kirill L.
fonte
0

Linguagem de máquina Aarch64 para Linux, 12 bytes

0:   9e660000        fmov x0, d0
4:   9240cc00        and  x0, x0, #0xfffffffffffff
8:   d65f03c0        ret

Para tentar isso, compile e execute o seguinte programa C em qualquer máquina Aarch64 Linux ou dispositivo (Aarch64) Android executando o Termux

#include<stdio.h>
const char f[]="\0\0f\x9e\0\xcc@\x92\xc0\3_\xd6";
int main(){
  double io[] = { 0.0,
                  1.2,
                  3.1,
                  3.5,
                 10.0,
            1234567.0,
               1e-256,
               1e+256,
                 -0.0,
                 -1.2,
                 -3.1,
                 -3.5,
                -10.0,
           -1234567.0,
              -1e-256,
              -1e+256 };

  for (int i = 0; i < sizeof io / sizeof*io; i++) {
    double input = io[i];
    long output = ((long(*)(double))f)(io[i]);

    printf("%-8.7g => %16lu (hex %1$013lx)\n", input, output);
  }
}
teto
fonte
0

Quarto (gforth) , 42 bytes

Supõe que os flutuadores tenham o dobro por padrão e as células tenham 8 bytes de comprimento (como é o caso no meu computador e no TIO)

: f f, here float - @ $fffffffffffff and ;

Experimente online!

Explicação

f,             \ take the top of the floating point stack and store it in memory
here float -   \ subtract the size of a float from the top of the dictionary
@              \ grab the value at the address calculated above and stick it on the stack
$fffffffffffff \ place the bitmask (equivalent to 52 1's in binary) on the stack
and            \ apply the bitmask to discard the first 12 bits

Quarta (gforth) resposta de célula de 4 bytes, 40 bytes

Algumas instalações mais antigas são padronizadas para células de 4 bytes,

: f f, here float - 2@ swap $FFFFF and ;

Explicação

f,             \ take the top of the floating point stack and store it in memory
here float -   \ subtract the size of a float from the top of the dictionary
2@             \ grab the value at the address above and put it in the top two stack cells
swap           \ swap the top two cells put the number in double-cell order
$fffff         \ place the bitmask (equivalent to 20 1's in binary) on the stack
and            \ apply the bitmask to discard the first 12 bits of the higher-order cell
reffu
fonte