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.



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!


&~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!


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!


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!


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

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.


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.


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.


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


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

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!


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





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);
  }
}


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.