12
\$\begingroup\$

Background

IEEE 754 Double-precision floating-point format is a way to represent real numbers with 64 bits. It looks like the following:

A real number n is converted to a double in the following manner:

  1. The sign bit s is 0 if the number is positive, 1 otherwise.
  2. The absolute value of n is represented in the form 2**y * 1.xxx, i.e. a power-of-2 times a base.
  3. The exponent e is y (the power of 2) minus 1023.
  4. The fraction f is the xxx part (fractional part of the base), taking the most significant 52 bits.

Conversely, a bit pattern (defined by sign s, exponent e and fraction f, each an integer) represents the number:

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

Challenge

Given a real number n, output its 52-bit fraction part of the double representation of n as an integer.

Test Cases

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)

You can check other numbers using this C reference which uses bit fields and a union.

Note that the expected answer is the same for +n and -n for any number n.

Input and Output

Standard rules apply.

Accepted input format:

  • A floating-point number, at least having double precision internally
  • A string representation of the number in decimal (you don't need to support scientific notation, since you can use 1000...00 or 0.0000...01 as input)

For output, a rounding error at the least significant bit is tolerable.

Winning Condition

This is , so the lowest bytes in each language wins.

\$\endgroup\$
  • \$\begingroup\$ Sandbox post (deleted) \$\endgroup\$ – Bubbler Mar 31 '18 at 7:53
  • 1
    \$\begingroup\$ The test cases include only non-negative numbers. Can the input be negative? \$\endgroup\$ – Dennis Mar 31 '18 at 15:06
  • \$\begingroup\$ @Dennis Yes. I'll add some more test cases. \$\endgroup\$ – Bubbler Mar 31 '18 at 15:58
  • 3
    \$\begingroup\$ Your description of the IEEE floating point format doesn't mention denormal numbers which are interpreted in a slightly different way (no implicit leading 1). Do denormals have to be handled correctly? \$\endgroup\$ – nwellnhof Mar 31 '18 at 16:01
  • 1
    \$\begingroup\$ @nwellnhof You don't need to consider denormals, NaN and Infinity. \$\endgroup\$ – Bubbler Mar 31 '18 at 18:09

19 Answers 19

8
\$\begingroup\$

C (gcc), 42 30 bytes

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

Takes a pointer to a double as argument and returns a long.

Requires 64-bit longs and gcc (undefined behavior).

Thanks to @nwellnhof for -2 bytes!

Try it online!

\$\endgroup\$
  • \$\begingroup\$ &~0UL>>12 is two bytes shorter. The macro only works with lvalues, though. \$\endgroup\$ – nwellnhof Mar 31 '18 at 15:43
  • \$\begingroup\$ Use macro -Df(x)=*(long *)&x&~0UL>>12, save 3 bytes. TIO \$\endgroup\$ – GPS Apr 1 '18 at 18:26
6
\$\begingroup\$

Haskell, 27 31 bytes

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

decodeFloat returns the significand and the exponent, but for some reason the former is 53 bit in Haskell, so we have to cut one bit off.

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Python 3, 54 50 bytes

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

Try it online!

With Kirill's suggestion:

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

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I might be wrong, but I think Python's hex() gives normalized notation that always starts with 0x1.. If so, you could just use this for 44 bytes. \$\endgroup\$ – Kirill L. Mar 31 '18 at 17:40
  • 1
    \$\begingroup\$ Well, I forgot about negative numbers, so it looks like 50 bytes after all. \$\endgroup\$ – Kirill L. Mar 31 '18 at 18:15
  • \$\begingroup\$ @kirill-l It doesn't always start with "1." (see for example (2**-1028)) but the OP doesn't say anything about subnormals, so I guess your second suggestion is acceptable. Please feel free to edit. \$\endgroup\$ – Luca Citi Mar 31 '18 at 18:41
  • \$\begingroup\$ Actually in a recent comment the OP explicitly says we can safely ignore subnormals. \$\endgroup\$ – Luca Citi Mar 31 '18 at 18:43
5
\$\begingroup\$

x86_64 machine language for 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

Try it online!

\$\endgroup\$
  • \$\begingroup\$ try and use your own CC instead of the standard ABI. By requiring the double be in rax, you can easily drop the entire move from xmm0. Only change needed for this is to make the test framework in ASM rather than C (Unless GCC is extra smart). \$\endgroup\$ – moonheart08 Apr 29 '18 at 2:48
4
\$\begingroup\$

MATL, 10 bytes

IZ%52W\0YA

Try it online!

Explanation

        % 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
\$\endgroup\$
4
\$\begingroup\$

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

Not using Math.floor(Math.log2(n)) because it's not guaranteed to be accurate. Edit: Saved 2 bytes thanks to @DanielIndie.

\$\endgroup\$
  • \$\begingroup\$ why not --n*2**52 \$\endgroup\$ – DanielIndie Mar 31 '18 at 12:57
  • \$\begingroup\$ @DanielIndie Because I forgot that that golf works with floats... \$\endgroup\$ – Neil Mar 31 '18 at 16:21
3
\$\begingroup\$

Perl 5 -pl, 28 bytes

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

Try it online!

The 1e-256 and 1e256 test cases are off but that's because Perl 5 converts huge or tiny floating point strings inexactly.

\$\endgroup\$
2
\$\begingroup\$

C (gcc) macro, 49 bytes

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

Try it online!

Returns a double but assuming IEEE precision, it won't have a fractional part. Also handles negative numbers now.

\$\endgroup\$
2
\$\begingroup\$

T-SQL, 80 bytes

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

The input is taken from the column n of a table named 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

\$\endgroup\$
2
\$\begingroup\$

Hoon, 25 bytes

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

Create a generic function that returns the input mod 2^52.

Calling it:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
\$\endgroup\$
  • \$\begingroup\$ I never thought I would see hoon here. I tried to understand urbit a couple of years back, but couldn't really make heads or tails of it. \$\endgroup\$ – recursive Mar 31 '18 at 20:04
2
\$\begingroup\$

JavaScript (ES7), 98 76 bytes

Saved 22 (!) bytes thanks to @Neil

More verbose than Neil's answer, but I wanted to give it a try with typed arrays.

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

Try it online!

\$\endgroup\$
  • \$\begingroup\$ ES7 + UInt32Array saves 22 bytes: (n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l \$\endgroup\$ – Neil Mar 31 '18 at 19:52
  • \$\begingroup\$ Is there any interpreter which had implemented BigInt64Array already? \$\endgroup\$ – tsh Apr 3 '18 at 2:14
2
\$\begingroup\$

APL (Dyalog), 38 bytes

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

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Stax, 19 14 bytes

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

Run and debug it

Unpacked, ungolfed, and commented, the code looks like this.

|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

Run this one

\$\endgroup\$
0
\$\begingroup\$

Ruby, 39 bytes

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

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Rust, 21 bytes

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

Pretty much copied C solution. Takes an f64 argument.

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Java 8 or later, 38 bytes

x->Double.doubleToLongBits(x)&-1L>>>12

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Aarch64 machine language for Linux, 12 bytes

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

To try this out, compile and run the following C program on any Aarch64 Linux machine or (Aarch64) Android device running 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);
  }
}
\$\endgroup\$
0
\$\begingroup\$

Julia 0.4, 30 bytes

x->reinterpret(UInt,x)<<12>>12

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Forth (gforth), 42 bytes

Assumes floats are double by default and cells are 8 bytes in length (as is the case on my computer and TIO)

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

Try it online!

Explanation

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) 4-byte cell answer, 40 bytes

Some older forth installations default to 4-byte cells, instead

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

Explanation

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.