La base del doppio


12

sfondo

IEEE 754 Il formato a virgola mobile a precisione doppia è un modo per rappresentare numeri reali con 64 bit. È simile al seguente:

Un numero reale nviene convertito in a doublenel modo seguente:

  1. Il bit di segno sè 0 se il numero è positivo, 1 altrimenti.
  2. Il valore assoluto di nè rappresentato nella forma 2**y * 1.xxx, ovvero una potenza di 2 volte una base .
  3. L'esponente eè y(la potenza di 2) meno 1023.
  4. La frazione fè la xxxparte (parte frazionaria della base), prendendo i 52 bit più significativi.

Al contrario, un modello di bit (definito da segno s, esponente ee frazione f, ciascuno un numero intero) rappresenta il numero:

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

Sfida

Dato un numero reale n, emette la sua frazione di 52 bit della doublerappresentazione di ncome numero intero.

Casi test

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)

Puoi controllare altri numeri usando questo riferimento C che usa campi di bit e un unione.

Si noti che la risposta prevista è la stessa per +ne -nper qualsiasi numero n.

Ingresso e uscita

Si applicano le regole standard.

Formato di input accettato:

  • Un numero in virgola mobile, almeno con doubleprecisione interna
  • Una rappresentazione in formato stringa del numero in decimale (non è necessario supportare la notazione scientifica, poiché è possibile utilizzare 1000...00o 0.0000...01come input)

Per l'output, è tollerabile un errore di arrotondamento nel bit meno significativo.

Condizioni vincenti

Questo è , quindi vince il byte più basso in ogni lingua.


Post sandbox (eliminato)
Bubbler

1
I casi di test includono solo numeri non negativi. L'ingresso può essere negativo?
Dennis,

@Dennis Sì. Aggiungerò altri casi di test.
Gorgogliatore

3
La tua descrizione del formato IEEE in virgola mobile non menziona i numeri denormali che sono interpretati in modo leggermente diverso (nessun 1 iniziale implicito). I denormals devono essere gestiti correttamente?
nwellnhof

1
@nwellnhof Non è necessario considerare denormali, NaN e Infinity.
Gorgogliatore

Risposte:


8

C (gcc) , 42 30 byte

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

Porta un puntatore al doppio come argomento e restituisce un lungo .

Richiede long e gcc a 64 bit (comportamento indefinito).

Grazie a @nwellnhof per -2 byte!

Provalo online!


&~0UL>>12è due byte più breve. Tuttavia, la macro funziona solo con i valori.
nwellnhof

Usa macro -Df(x)=*(long *)&x&~0UL>>12, salva 3 byte. TIO
GPS

6

Haskell, 27 31 byte

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

decodeFloatrestituisce il significato e l'esponente, ma per qualche ragione il primo è a 53 bit in Haskell, quindi dobbiamo tagliare un po '.

Provalo online!


5

Python 3 , 54 50 byte

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

Provalo online!

Con il suggerimento di Kirill:

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

Provalo online!


Potrei sbagliarmi, ma penso che Python hex()dia una notazione normalizzata che inizia sempre con 0x1.. Se è così, si potrebbe utilizzare questo per 44 byte.
Kirill L.

1
Bene, ho dimenticato i numeri negativi, quindi dopo tutto sembrano 50 byte .
Kirill L.

@ kirill-l Non sempre inizia con "1." (vedi ad esempio (2 ** - 1028)) ma l'OP non dice nulla sui subnormali, quindi immagino che il tuo secondo suggerimento sia accettabile. Non esitate a modificare.
Luca Citi,

In realtà in un recente commento l'OP afferma esplicitamente che possiamo tranquillamente ignorare i subnormali.
Luca Citi,

5

linguaggio macchina x86_64 per Linux, 14 byte

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

Provalo online!


prova ad usare il tuo CC invece dell'ABI standard. Richiedendo che il doppio sia in rax, puoi facilmente rilasciare l'intera mossa da xmm0. L'unica modifica necessaria per questo è rendere il framework di test in ASM piuttosto che in C (a meno che GCC non sia più intelligente).
moonheart08

4

MATL , 10 byte

IZ%52W\0YA

Provalo online!

Spiegazione

        % 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

4

JavaScript (ES7), 52 50 byte

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

Non utilizzare Math.floor(Math.log2(n))perché non è garantito che sia accurato. Modifica: salvato 2 byte grazie a @DanielIndie.


perché no --n * 2 ** 52
DanielIndie

@DanielIndie Perché ho dimenticato che quel golf funziona con i galleggianti ...
Neil

3

Perl 5 -pl , 28 byte

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

Provalo online!

I casi di test 1e-256 e 1e256 sono disattivati, ma ciò è dovuto al fatto che Perl 5 converte in modo inesatto stringhe in virgola mobile enormi o minuscole.


2

Macro C (gcc) , 49 byte

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

Provalo online!

Restituisce una doubleprecisione IEEE assunta, ma non avrà una parte frazionaria. Ora gestisce anche numeri negativi.


2

T-SQL , 80 byte

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

L'input è tratto dalla colonna ndi una tabella denominata 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


2

Hoon , 25 byte

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

Crea una funzione generica che restituisce la mod di input 2^52.

Chiamandolo:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028

Non avrei mai pensato di vedere hoon qui. Ho provato a capire la città un paio d'anni fa, ma non sono riuscito a capirlo.
ricorsivo

2

JavaScript (ES7), 98 76 byte

22 (!) Byte salvati grazie a @Neil

Più prolisso della risposta di Neil , ma volevo provarlo con array digitati .

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

Provalo online!


ES7 + UInt32Arraysalva 22 byte:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Neil

C'è qualche interprete BigInt64Arraygià implementato ?
TSH


1

Stax , 19 14 byte

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

Esegui ed esegui il debug

Disimballato, non modificato e commentato, il codice è simile al seguente.

|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

Esegui questo





0

Linguaggio macchina Aarch64 per Linux, 12 byte

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

Per provarlo, compila ed esegui il seguente programma C su qualsiasi macchina Aarch64 Linux o (Aarch64) dispositivo Android che esegue 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);
  }
}


0

Forth (gforth) , 42 byte

Presuppone che i float siano doppi per impostazione predefinita e le celle abbiano una lunghezza di 8 byte (come nel caso del mio computer e TIO)

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

Provalo online!

Spiegazione

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) risposta a 4 byte, 40 byte

Alcune vecchie installazioni precedenti invece impostano automaticamente le celle a 4 byte

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

Spiegazione

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.