Baza podwójna

12

tło

Format zmiennoprzecinkowy podwójnej precyzji IEEE 754 to sposób reprezentowania liczb rzeczywistych za pomocą 64 bitów. Wygląda to następująco:

Liczba rzeczywista njest konwertowana doublena następujący w następujący sposób:

  1. Bit znaku sma wartość 0, jeśli liczba jest dodatnia, w przeciwnym razie 1.
  2. Wartość bezwzględna njest reprezentowana w postaci 2**y * 1.xxx, tj. Potęga 2 razy podstawa .
  3. Wykładnik ewynosi y(potęga 2) minus 1023.
  4. Ułamek fto xxxczęść (ułamkowa część podstawy), zajmująca najbardziej znaczące 52 bity.

I odwrotnie, wzór bitowy (zdefiniowany przez znak s, wykładnik ei ułamek f, każda liczba całkowita) reprezentuje liczbę:

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

Wyzwanie

Biorąc pod uwagę liczbę rzeczywistą n, wyślij jej 52-bitową część ułamkową doublereprezentacji njako liczba całkowita.

Przypadki testowe

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)

Możesz sprawdzić inne liczby za pomocą tego odwołania C, które wykorzystuje pola bitowe i połączenie.

Pamiętaj, że oczekiwana odpowiedź jest taka sama dla dowolnej liczby +ni -ndla niej n.

Wejście i wyjście

Obowiązują standardowe zasady.

Akceptowany format wejściowy:

  • Liczba zmiennoprzecinkowa, przynajmniej o doubleprecyzji wewnętrznej
  • Ciąg znaków reprezentujący liczbę dziesiętną (nie trzeba obsługiwać notacji naukowej, ponieważ można użyć 1000...00lub 0.0000...01jako danych wejściowych)

W przypadku danych wyjściowych dopuszczalny jest błąd zaokrąglania co najmniej znaczącego bitu.

Warunki wygranej

To jest , więc wygrywa najmniej bajtów w każdym języku.

Bubbler
źródło
Wpis w piaskownicy (usunięty)
Bubbler,
1
Przypadki testowe obejmują tylko liczby nieujemne. Czy dane wejściowe mogą być ujemne?
Dennis
@Dennis Tak. Dodam więcej przypadków testowych.
Bubbler
3
Twój opis formatu zmiennoprzecinkowego IEEE nie wspomina liczb normalnych, które są interpretowane w nieco inny sposób (bez domyślnego wiodącego 1). Czy denormale muszą być obsługiwane poprawnie?
nwellnhof
1
@nwellnhof Nie musisz brać pod uwagę denormali, NaN i Infinity.
Bubbler

Odpowiedzi:

8

C (gcc) , 42 30 bajtów

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

Podnosi wskaźnik jako podwójny jako argument i zwraca długi .

Wymaga 64-bitowych długości i gcc (niezdefiniowane zachowanie).

Dzięki @nwellnhof za -2 bajty!

Wypróbuj online!

Dennis
źródło
&~0UL>>12jest dwa bajty krótszy. Makro działa jednak tylko z wartościami lvalues.
nwellnhof
Użyj makra -Df(x)=*(long *)&x&~0UL>>12, zapisz 3 bajty. TIO
GPS
6

Haskell, 27 31 bajtów

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

decodeFloatzwraca znaczenie i wykładnik, ale z jakiegoś powodu ten pierwszy ma 53 bity w Haskell, więc musimy odciąć jeden bit.

Wypróbuj online!

nimi
źródło
5

Python 3 , 54 50 bajtów

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

Wypróbuj online!

Z sugestią Kirilla:

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

Wypróbuj online!

Luca Citi
źródło
Mogę się mylić, ale myślę, że Python hex()podaje znormalizowaną notację, która zawsze zaczyna się od 0x1.. Jeśli tak, możesz użyć tego dla 44 bajtów.
Kirill L.
1
Cóż, zapomniałem o liczbach ujemnych, więc w końcu wygląda na 50 bajtów .
Kirill L.
@ kirill-l Nie zawsze zaczyna się od „1.” (patrz na przykład (2 ** - 1028)), ale OP nie mówi nic o subnormalach, więc myślę, że twoja druga sugestia jest do przyjęcia. Możesz edytować.
Luca Citi
Właściwie w ostatnim komentarzu OP wyraźnie mówi, że możemy bezpiecznie ignorować podnormale.
Luca Citi
5

język maszynowy x86_64 dla systemu Linux, 14 bajtów

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

Wypróbuj online!

sufitowy
źródło
spróbuj użyć własnego CC zamiast standardowego ABI. Wymagając, aby double był w trybie rax, możesz łatwo upuścić cały ruch z xmm0. Jedyną potrzebną zmianą jest stworzenie środowiska testowego w ASM zamiast w C (chyba że GCC jest wyjątkowo inteligentny).
moonheart08
4

MATL , 10 bajtów

IZ%52W\0YA

Wypróbuj online!

Wyjaśnienie

        % 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
źródło
4

JavaScript (ES7), 52 50 bajtów

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

Nie używa, Math.floor(Math.log2(n))ponieważ nie gwarantuje się, że będzie dokładna. Edycja: Zapisano 2 bajty dzięki @DanielIndie.

Neil
źródło
dlaczego nie
n
@DanielIndie Ponieważ zapomniałem, że golf działa z pływakami ...
Neil
3

Perl 5 -pl , 28 bajtów

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

Wypróbuj online!

Przypadki testowe 1e-256 i 1e256 są wyłączone, ale dlatego, że Perl 5 konwertuje duże lub małe ciągi zmiennoprzecinkowe niedokładnie.

nwellnhof
źródło
2

Makro C (gcc) , 49 bajtów

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

Wypróbuj online!

Zwraca, doubleale przy założeniu precyzji IEEE, nie będzie miała części ułamkowej. Teraz obsługuje także liczby ujemne.

nwellnhof
źródło
2

T-SQL , 80 bajtów

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

Dane wejściowe pochodzą z kolumny ntabeli o nazwie 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
źródło
2

Hoon , 25 bajtów

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

Utwórz ogólną funkcję, która zwraca mod wejściowy 2^52.

Nazywając to:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
RenderSettings
źródło
Nigdy nie myślałem, że zobaczę hoon tutaj. Próbowałem zrozumieć urbita kilka lat temu, ale tak naprawdę nie mogłem tego zrobić.
rekurencyjny
2

JavaScript (ES7), 98 76 bajtów

Zaoszczędź 22 (!) Bajtów dzięki @Neil

Bardziej szczegółowe niż odpowiedź Neila , ale chciałem spróbować z tablicami maszynowymi .

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

Wypróbuj online!

Arnauld
źródło
ES7 + UInt32Arrayoszczędza 22 bajty:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Neil
Czy jest już jakiś tłumacz, który już zaimplementował BigInt64Array?
tsh
1

Stax , 19 14 bajtów

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

Uruchom i debuguj

Kod po rozpakowaniu, niepolowaniu i komentowaniu wygląda tak.

|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

Uruchom ten

rekurencyjny
źródło
0

Język maszynowy Aarch64 dla systemu Linux, 12 bajtów

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

Aby to wypróbować, skompiluj i uruchom następujący program C na dowolnym komputerze z systemem Linux Aarch64 lub urządzeniu z Androidem (Aarch64) z systemem 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);
  }
}
sufitowy
źródło
0

Dalej (gforth) , 42 bajty

Zakłada, że ​​liczby zmiennoprzecinkowe są domyślnie podwójne, a komórki mają długość 8 bajtów (jak ma to miejsce w moim komputerze i TIO)

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

Wypróbuj online!

Wyjaśnienie

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

Czwarta (gforth) 4-bajtowa odpowiedź komórki, 40 bajtów

Zamiast tego niektóre starsze czwarte instalacje używają komórek 4-bajtowych

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

Wyjaśnienie

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
źródło