# 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) plus 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
16.0       =>                0
0.0625     =>                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
-16.0      =>                0
-0.0625    =>                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.

• Sandbox post (deleted) Commented Mar 31, 2018 at 7:53
• The test cases include only non-negative numbers. Can the input be negative? Commented Mar 31, 2018 at 15:06
• @Dennis Yes. I'll add some more test cases. Commented Mar 31, 2018 at 15:58
• 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? Commented Mar 31, 2018 at 16:01
• @nwellnhof You don't need to consider denormals, NaN and Infinity. Commented Mar 31, 2018 at 18:09

# 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!

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

(mod2^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!

# 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


# 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!

• 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. Commented Mar 31, 2018 at 17:40
• Well, I forgot about negative numbers, so it looks like 50 bytes after all. Commented Mar 31, 2018 at 18:15
• @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. Commented Mar 31, 2018 at 18:41
• Actually in a recent comment the OP explicitly says we can safely ignore subnormals. Commented Mar 31, 2018 at 18:43

# 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!

EDIT: Thanks to @Bubbler

• 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). Commented Apr 29, 2018 at 2:48
• Fixed TIO Commented Sep 22, 2022 at 0:19

## 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.

• why not --n*2**52 Commented Mar 31, 2018 at 12:57
• @DanielIndie Because I forgot that that golf works with floats...
– Neil
Commented Mar 31, 2018 at 16:21

# 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.

# 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.

# 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

## 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

• 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. Commented Mar 31, 2018 at 20:04

# 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!

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

# APL (Dyalog), 38 bytes

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


Try it online!

# 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

# Rust, 21 bytes

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


Pretty much copied C solution. Takes an f64 argument.

Try it online!

# 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


# 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


# Go, 68 bytes

import."math"
func d(n float64)uint64{return Float64bits(n)<<12>>12}


Can't do the &-1 trick because Go disallows overflows.

Attempt This Online!

# Ruby, 39 bytes

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


Try it online!

# Java 8 or later, 38 bytes

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


Try it online!

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


# Julia 0.4, 30 bytes

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


Try it online!

# 05AB1E, 18 bytes

Ä[ÐïQ#·}b0₃×«À52£C


Alternatively:

_+Ä[DbD53∍©›#·}®¦C


Alternatively (by porting @LucaCiti's Python answer in the legacy version of 05AB1E):

Ä".hex()"«.E„.p¡Hà


Explanation:

Ä             # Get the absolute value of the (implicit) input-float
[            # Start an infinite loop:
Ð           #  Triplicate the current value
ï          #  Cast the top to an integer
Q         #  Check if the top two values are the same†
#        #  If they are: stop the infinite loop
·           #  Double the current float
}b           # After the loop: convert the integer to a binary string
0₃×«       # Append 95 trailing 0s
# (95 is the smallest single-byte constant >= 52)
À      # Rotate it once towards the left, so the leading 1 becomes trailing
52£   # Only keep the first 52 bits
C  # Convert it from a binary string to a base-10 integer
# (which is output implicitly as result)

_             # Check if the (implicit) input-float is 0
+            # Add it to the (implicit) input-float so it becomes 1
Ä           # Convert it to its absolute value
[             # Start an infinite loop:
D            #  Duplicate the current value
b           #  Convert its integer part to a binary string
D          #  Duplicate this string
53∍       #  Extend/shorten it to size 53
©      #  Store this result in variable ®
›     #  Check if it's larger than the binary string
#    #  If it is: stop the infinite loop
·            #  Double the current float
}®            # After the loop: push binary string ® which we've saved
¦           # Remove its leading 1
C          # Convert it from a binary string to a base-10 integer
# (which is output implicitly as result)

Ä             # Get the absolute value of the (implicit) input-float††
".hex()"«    # Append string ".hex()"
.E  # Evaluate and execute it as Python code
„.p¡          # Split it on both the "." and "p"
H         # Convert each inner part from a hexadecimal string to an integer
à        # Push the maximum of this list
# (which is output implicitly as result)


† If 05AB1E didn't had this bug and the input format is also guaranteed to not contain any additional trailing 0 besides #.0 (e.g. 12.0 is a valid input, but 12 or 12.10 aren't), the DïQ could have been ¤_ - which checks if the float contains a trailing zero.

†† Unlike the Python answer, .hex() doesn't work on negative values in the legacy version of 05AB1E, unless I add parenthesis around it (e.g. -1.0.hex() doesn't work, but 1.0.hex() and (-1.0).hex() both do: try it online), which is why the Ä was necessary in the third program.