La base del doble

12

Antecedentes

IEEE 754 El formato de coma flotante de doble precisión es una forma de representar números reales con 64 bits. Se parece a lo siguiente:

Un número real nse convierte doubleen a de la siguiente manera:

  1. El bit de signo ses 0 si el número es positivo, 1 de lo contrario.
  2. El valor absoluto de nse representa en la forma 2**y * 1.xxx, es decir, una potencia de 2 veces una base .
  3. El exponente ees y(la potencia de 2) menos 1023.
  4. La fracción fes la xxxparte (parte fraccional de la base), que toma los 52 bits más significativos.

Por el contrario, un patrón de bits (definido por signo s, exponente ey fracción f, cada uno un número entero) representa el número:

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

Desafío

Dado un número real n, genera su fracción de 52 bits como parte de la doublerepresentación de nun entero.

Casos de prueba

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)

Puede verificar otros números usando esta referencia C que usa campos de bits y una unión.

Tenga en cuenta que la respuesta esperada es la misma para +ny -npara cualquier número n.

Entrada y salida

Aplican reglas estándar.

Formato de entrada aceptado:

  • Un número de coma flotante, al menos con doubleprecisión interna
  • Una representación de cadena del número en decimal (no necesita admitir notación científica, ya que puede usar 1000...00o 0.0000...01como entrada)

Para la salida, es tolerable un error de redondeo en el bit menos significativo.

Condición ganadora

Este es el , por lo que gana los bytes más bajos en cada idioma.

Bubbler
fuente
Publicación de Sandbox (eliminada)
Bubbler
1
Los casos de prueba incluyen solo números no negativos. ¿Puede la entrada ser negativa?
Dennis
@ Dennis Sí. Agregaré algunos casos de prueba más.
Bubbler
3
Su descripción del formato de punto flotante IEEE no menciona los números denormales que se interpretan de una manera ligeramente diferente (sin un 1 implícito). ¿Los denormales deben manejarse correctamente?
nwellnhof
1
@nwellnhof No es necesario tener en cuenta los valores normales, NaN e Infinity.
Bubbler

Respuestas:

8

C (gcc) , 42 30 bytes

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

Toma un puntero a un doble como argumento y devuelve un largo .

Requiere largos de 64 bits y gcc (comportamiento indefinido).

¡Gracias a @nwellnhof por -2 bytes!

Pruébalo en línea!

Dennis
fuente
&~0UL>>12es dos bytes más corto. Sin embargo, la macro solo funciona con valores.
nwellnhof
Use macro -Df(x)=*(long *)&x&~0UL>>12, ahorre 3 bytes. TIO
GPS
6

Haskell, 27 31 bytes

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

decodeFloatdevuelve el significado y el exponente, pero por alguna razón el primero es de 53 bits en Haskell, por lo que tenemos que cortar un bit.

Pruébalo en línea!

nimi
fuente
5

Python 3 , 54 50 bytes

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

Pruébalo en línea!

Con la sugerencia de Kirill:

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

Pruébalo en línea!

Luca Citi
fuente
Podría estar equivocado, pero creo que Python hex()da una notación normalizada que siempre comienza con 0x1.. Si es así, podría usar esto para 44 bytes.
Kirill L.
1
Bueno, olvidé los números negativos, por lo que parece que son 50 bytes después de todo.
Kirill L.
@ kirill-l No siempre comienza con "1". (ver por ejemplo (2 ** - 1028)) pero el OP no dice nada sobre subnormales, así que supongo que su segunda sugerencia es aceptable. Por favor, siéntase libre de editar.
Luca Citi
En realidad, en un comentario reciente, el OP dice explícitamente que podemos ignorar con seguridad lo subnormal.
Luca Citi
5

lenguaje 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

Pruébalo en línea!

techo
fuente
intente y use su propio CC en lugar del ABI estándar. Al requerir que el doble esté en rax, puede soltar fácilmente todo el movimiento desde xmm0. El único cambio necesario para esto es hacer el marco de prueba en ASM en lugar de C (a menos que GCC sea más inteligente).
moonheart08
4

MATL , 10 bytes

IZ%52W\0YA

Pruébalo en línea!

Explicación

        % 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
fuente
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

No se usa Math.floor(Math.log2(n))porque no se garantiza que sea precisa. Editar: Guardado 2 bytes gracias a @DanielIndie.

Neil
fuente
por qué no --n * 2 ** 52
DanielIndie
@DanielIndie Porque olvidé que el golf funciona con flotadores ...
Neil
3

Perl 5 -pl , 28 bytes

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

Pruébalo en línea!

Los casos de prueba 1e-256 y 1e256 están desactivados, pero eso se debe a que Perl 5 convierte las cadenas de coma flotante grandes o pequeñas de manera inexacta.

nwellnhof
fuente
2

Macro C (gcc) , 49 bytes

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

Pruébalo en línea!

Devuelve un doublepero suponiendo precisión IEEE, no tendrá una parte fraccional. También maneja números negativos ahora.

nwellnhof
fuente
2

T-SQL , 80 bytes

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

La entrada se toma de la columna nde una tabla llamada 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
fuente
2

Hoon , 25 bytes

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

Cree una función genérica que devuelva el mod de entrada 2^52.

Llamándolo:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
RenderSettings
fuente
Nunca pensé que vería a Hoon aquí. Traté de entender Urbit hace un par de años, pero realmente no pude entenderlo.
recursivo
2

JavaScript (ES7), 98 76 bytes

Ahorró 22 (!) Bytes gracias a @Neil

Más detallado que la respuesta de Neil , pero quería probarlo con matrices escritas .

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

Pruébalo en línea!

Arnauld
fuente
ES7 + UInt32Arrayahorra 22 bytes:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Neil
¿Hay algún intérprete que ya haya implementado BigInt64Array?
tsh
1

Stax , 19 14 bytes

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

Ejecutar y depurarlo

Desempaquetado, sin golf y comentado, el código se ve así.

|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

Ejecute este

recursivo
fuente
0

Lenguaje de máquina Aarch64 para Linux, 12 bytes

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

Para probar esto, compile y ejecute el siguiente programa C en cualquier máquina Linux Aarch64 o dispositivo Android (Aarch64) que ejecute 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);
  }
}
techo
fuente
0

Adelante (gforth) , 42 bytes

Asume que los flotantes son dobles por defecto y las celdas tienen 8 bytes de longitud (como es el caso en mi computadora y TIO)

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

Pruébalo en línea!

Explicación

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

Forth (gforth) respuesta de celda de 4 bytes, 40 bytes

Algunas instalaciones más antiguas por defecto tienen celdas de 4 bytes, en su lugar

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

Explicación

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
fuente