Basis Double

12

Latar Belakang

IEEE 754 Format floating-point presisi ganda adalah cara untuk mewakili bilangan real dengan 64 bit. Ini terlihat seperti berikut:

Bilangan real ndikonversi menjadi doubledengan cara berikut:

  1. Bit tanda sadalah 0 jika angkanya positif, 1 sebaliknya.
  2. Nilai absolut dari ndiwakili dalam bentuk 2**y * 1.xxx, yaitu kekuatan-2 kali basis .
  3. Eksponennya eadalah y(kekuatan 2) minus 1023.
  4. Fraksi fadalah xxxbagian (bagian pecahan dari basis), mengambil 52 bit paling signifikan.

Sebaliknya, pola bit (didefinisikan oleh tanda s, eksponen edan fraksi f, masing-masing bilangan bulat) mewakili angka:

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

Tantangan

Diberikan bilangan real n, output bagian fraksinya 52-bit sebagai doublerepresentasi nbilangan bulat.

Uji Kasus

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)

Anda dapat memeriksa nomor lain menggunakan referensi C ini yang menggunakan bidang bit dan gabungan.

Perhatikan bahwa jawaban yang diharapkan adalah sama untuk +ndan -nuntuk nomor apa pun n.

Masukan dan keluaran

Aturan standar berlaku.

Format input yang diterima:

  • Angka floating-point, setidaknya memiliki doublepresisi secara internal
  • Representasi string angka dalam desimal (Anda tidak perlu mendukung notasi ilmiah, karena Anda dapat menggunakan 1000...00atau 0.0000...01sebagai input)

Untuk output, kesalahan pembulatan pada bit paling signifikan dapat ditoleransi.

Kondisi Menang

Ini adalah , sehingga byte terendah di setiap bahasa menang.

Bubbler
sumber
Posting Sandbox (dihapus)
Bubbler
1
Kasus uji hanya mencakup angka non-negatif. Apakah inputnya negatif?
Dennis
@ Dennis Ya. Saya akan menambahkan beberapa test case lagi.
Bubbler
3
Deskripsi Anda tentang format titik apung IEEE tidak menyebutkan angka denormal yang ditafsirkan dengan cara yang sedikit berbeda (tidak ada terkemuka 1 implisit). Apakah penyangkalan harus ditangani dengan benar?
nwellnhof
1
@nwellnhof Anda tidak perlu mempertimbangkan denormals, NaN dan Infinity.
Bubbler

Jawaban:

8

C (gcc) , 42 30 byte

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

Membawa pointer ke dobel sebagai argumen dan mengembalikan panjang .

Membutuhkan 64-bit long dan gcc (perilaku tidak terdefinisi).

Berkat @nwellnhof untuk -2 byte!

Cobalah online!

Dennis
sumber
&~0UL>>12lebih pendek dua byte. Makro hanya bekerja dengan nilai, meskipun.
nwellnhof
Gunakan makro -Df(x)=*(long *)&x&~0UL>>12, simpan 3 byte. TIO
GPS
6

Haskell, 27 31 byte

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

decodeFloatmengembalikan signifikan dan eksponen, tetapi untuk beberapa alasan yang pertama adalah 53 bit di Haskell, jadi kita harus memotong satu bit.

Cobalah online!

nimi
sumber
5

Python 3 , 54 50 byte

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

Cobalah online!

Dengan saran Kirill:

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

Cobalah online!

Luca Citi
sumber
Saya mungkin salah, tapi saya pikir Python hex()memberikan notasi dinormalisasi yang selalu dimulai dengan 0x1.. Jika demikian, Anda bisa menggunakan ini untuk 44 byte.
Kirill L.
1
Yah, saya lupa tentang angka negatif, jadi sepertinya 50 byte .
Kirill L.
@ kirill-l Itu tidak selalu dimulai dengan "1." (lihat misalnya (2 ** - 1028)) tetapi OP tidak mengatakan apa-apa tentang subnormal, jadi saya kira saran kedua Anda dapat diterima. Silakan diedit.
Luca Citi
Sebenarnya dalam komentar baru-baru ini OP secara eksplisit mengatakan kita dapat dengan aman mengabaikan subnormal.
Luca Citi
5

bahasa mesin x86_64 untuk 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

Cobalah online!

plafon
sumber
coba dan gunakan CC Anda sendiri daripada ABI standar. Dengan mewajibkan dobel dalam rax, Anda dapat dengan mudah menjatuhkan seluruh gerakan dari xmm0. Hanya perubahan yang diperlukan untuk ini adalah membuat kerangka pengujian di ASM daripada C (Kecuali GCC lebih pintar).
moonheart08
4

MATL , 10 byte

IZ%52W\0YA

Cobalah online!

Penjelasan

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

Tidak menggunakan Math.floor(Math.log2(n))karena tidak dijamin akurat. Sunting: Disimpan 2 byte berkat @DanielIndie.

Neil
sumber
kenapa tidak --n * 2 ** 52
DanielIndie
@DanielIndie Karena saya lupa golf itu berfungsi dengan pelampung ...
Neil
3

Perl 5 -pl , 28 byte

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

Cobalah online!

Kasus uji 1e-256 dan 1e256 tidak aktif, tetapi itu karena Perl 5 mengkonversi string floating point besar atau kecil secara tidak tepat.

nwellnhof
sumber
2

C (gcc) makro, 49 byte

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

Cobalah online!

Mengembalikan doubletetapi mengasumsikan presisi IEEE, itu tidak akan memiliki bagian pecahan. Juga menangani angka negatif sekarang.

nwellnhof
sumber
2

T-SQL , 80 byte

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

Input diambil dari kolom ntabel bernama 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
sumber
2

Hoon , 25 byte

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

Buat fungsi generik yang mengembalikan mod input 2^52.

Menyebutnya:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
Pengaturan rendering
sumber
Saya tidak pernah berpikir saya akan melihat hoon di sini. Saya mencoba memahami urbit beberapa tahun yang lalu, tetapi tidak bisa benar-benar membuat kepala atau ekornya.
rekursif
2

JavaScript (ES7), 98 76 byte

Disimpan 22 (!) Byte berkat @Neil

Lebih bertele-tele daripada jawaban Neil , tetapi saya ingin mencobanya dengan array yang diketik .

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

Cobalah online!

Arnauld
sumber
ES7 + UInt32Arraymenghemat 22 byte:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Neil
Apakah sudah ada penerjemah yang sudah menerapkan BigInt64Array?
tsh
2

APL (Dyalog) , 38 byte

{0=⍵:0⋄(2*52)ׯ1+×∘2⍣(1≤⊣)÷∘2⍣(1>⊣)|⍵}

Cobalah online!

Uriel
sumber
1

Stax , 19 14 byte

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

Jalankan dan debug itu

Dibongkar, tidak diserang, dan dikomentari, kode ini terlihat seperti ini.

|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

Jalankan yang ini

rekursif
sumber
0

Ruby , 39 byte

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

Cobalah online!

Kirill L.
sumber
0

Karat , 21 byte

|p|p.to_bits()&!0>>12

Cukup banyak solusi C yang disalin. Membawa f64argumen.

Cobalah online!

Konrad Borowski
sumber
0

Bahasa mesin Aarch64 untuk Linux, 12 byte

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

Untuk mencoba ini, kompilasi dan jalankan program C berikut pada mesin Aarch64 Linux atau (Aarch64) perangkat Android yang menjalankan 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);
  }
}
plafon
sumber
0

Keempat (gforth) , 42 byte

Asumsikan float dua kali lipat secara default dan panjang sel adalah 8 byte (seperti halnya pada komputer saya dan TIO)

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

Cobalah online!

Penjelasan

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

Keempat (gforth) jawaban sel 4-byte, 40 byte

Beberapa instalasi lama yang lebih tua, standarnya adalah sel 4-byte

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

Penjelasan

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
sumber