Двойная база

12

Фон

IEEE 754 Формат с плавающей запятой двойной точности представляет собой способ представления действительных чисел с помощью 64-разрядных. Это выглядит следующим образом:

Действительное число nпреобразуется в a doubleследующим образом:

  1. Знаковый бит sравен 0, если число положительное, и 1 в противном случае.
  2. Абсолютное значение nпредставляется в виде 2**y * 1.xxx, то есть степень -2, умноженная на основание .
  3. Показатель eявляется y(сила 2) минус 1023.
  4. Фракция f- это xxxчасть (дробная часть базы), занимающая самые значимые 52 бита.

Наоборот, битовая комбинация (определенная знаком s, показателем степени eи дробью f, каждое целое число) представляет число:

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

Вызов

Учитывая действительное число n, выведите его 52-битную дробную часть doubleпредставления nв виде целого числа.

Тестовые случаи

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)

Вы можете проверить другие числа, используя эту ссылку C, которая использует битовые поля и объединение.

Обратите внимание , что ожидаемый ответ одинаков для +nи -nдля любого числа n.

Вход и выход

Стандартные правила применяются.

Принятый формат ввода:

  • Число с плавающей запятой, по крайней мере, имеющее doubleвнутреннюю точность
  • Строковое представление числа в десятичном виде (вам не нужно поддерживать научную запись, так как вы можете использовать 1000...00или в 0.0000...01качестве ввода)

Для вывода допустима ошибка округления младшего бита.

Условие победы

Это , поэтому побеждают младшие байты на каждом языке.

фонтанчик для питья
источник
Сообщение песочницы (удалено)
Bubbler
1
Тестовые случаи включают только неотрицательные числа. Может ли вход быть отрицательным?
Деннис
@ Денис Да. Я добавлю еще несколько тестов.
Bubbler
3
В вашем описании формата IEEE с плавающей запятой не упоминаются ненормальные числа, которые интерпретируются немного по-другому (без неявного начального 1). Нужно ли правильно обращаться с ненормативной лексикой?
nwellnhof
1
@nwellnhof Вам не нужно учитывать денормали, NaN и Infinity.
Bubbler

Ответы:

8

C (gcc) , 42 30 байт

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

Принимает указатель на double в качестве аргумента и возвращает long .

Требует 64-битных длинных и gcc (неопределенное поведение).

Спасибо @nwellnhof за -2 байта!

Попробуйте онлайн!

Деннис
источник
&~0UL>>12на два байта короче. Макрос работает только с lvalues.
nwellnhof
Используйте макрос -Df(x)=*(long *)&x&~0UL>>12, сохраните 3 байта. TIO
GPS
6

Haskell, 27 31 байт

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

decodeFloatвозвращает значение и показатель степени, но по какой-то причине в Хаскелле первое составляет 53 бита , поэтому мы должны обрезать один бит.

Попробуйте онлайн!

Ними
источник
5

Python 3 , 54 50 байт

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

Попробуйте онлайн!

С предложением Кирилла:

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

Попробуйте онлайн!

Лука Чити
источник
Я могу ошибаться, но я думаю, что Python hex()дает нормализованную запись, которая всегда начинается с 0x1.. Если это так, вы можете просто использовать это для 44 байтов.
Кирилл Л.
1
Ну, я забыл об отрицательных числах, так что в конце концов он выглядит как 50 байтов .
Кирилл Л.
@ kirill-l Не всегда начинается с «1». (см., например, (2 ** - 1028)), но ОП ничего не говорит о субнормалах, поэтому я думаю, что ваше второе предложение приемлемо. Пожалуйста, не стесняйтесь редактировать.
Лука Сити
На самом деле в недавнем комментарии ОП явно говорит, что мы можем спокойно игнорировать субнормалы.
Лука Сити
5

машинный язык x86_64 для Linux, 14 байтов

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

Попробуйте онлайн!

ceilingcat
источник
попробуйте использовать свой собственный CC вместо стандартного ABI. Требуя двойного присутствия в rax, вы можете легко отбросить весь ход с xmm0. Единственное изменение, необходимое для этого, состоит в создании тестовой среды в ASM, а не в C (если только GCC не очень умный).
moonheart08
4

MATL , 10 байт

IZ%52W\0YA

Попробуйте онлайн!

объяснение

        % 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 байт

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

Не используется, Math.floor(Math.log2(n))потому что это не гарантируется, чтобы быть точным. Изменить: Сохранено 2 байта благодаря @DanielIndie.

Нил
источник
почему бы не --n * 2 ** 52
DanielIndie
@DanielIndie Потому что я забыл, что этот гольф работает с поплавками ...
Нил
3

Perl 5 -pl , 28 байт

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

Попробуйте онлайн!

Тестовые случаи 1e-256 и 1e256 отключены, но это потому, что Perl 5 преобразует огромные или крошечные строки с плавающей запятой неточно.

nwellnhof
источник
2

Макрос C (gcc) , 49 байтов

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

Попробуйте онлайн!

Возвращает, doubleно при условии точности IEEE, он не будет иметь дробной части. Также обрабатывает отрицательные числа сейчас.

nwellnhof
источник
2

T-SQL , 80 байт

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

Входные данные взяты из столбца nтаблицы с именем 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

Хун , 25 байт

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

Создайте универсальную функцию, которая возвращает мод ввода 2^52.

Называя это:

> %.  .~1e256
  |*(* (mod +< (pow 2 52)))
1.495.187.628.212.028
RenderSettings
источник
Я никогда не думал, что увижу хун здесь. Я пытался понять урбит пару лет назад, но на самом деле не мог сделать из этого ни головы, ни хвоста.
рекурсивный
2

JavaScript (ES7), 98 76 байт

Сохранено 22 (!) Байта благодаря @Neil

Более подробный, чем ответ Нейла , но я хотел попробовать его с типизированными массивами .

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

Попробуйте онлайн!

Arnauld
источник
ES7 + UInt32Arrayсохраняет 22 байта:(n,[l,h]=new Uint32Array(new Float64Array([n]).buffer))=>(h&-1>>>12)*2**32+l
Нил
Есть ли переводчик, который уже реализован BigInt64Array?
TSH
1

Stax , 19 14 байтов

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

Запустите и отладьте его

Распакованный, распакованный и прокомментированный код выглядит следующим образом.

|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

Запустите этот

рекурсивный
источник
0

Машинный язык Aarch64 для Linux, 12 байт

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

Чтобы попробовать это, скомпилируйте и запустите следующую C-программу на любом компьютере Aarch64 Linux или (Aarch64) Android-устройстве под управлением 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);
  }
}
ceilingcat
источник
0

Forth (gforth) , 42 байта

Предполагается, что число с плавающей запятой по умолчанию удваивается, а ячейки имеют длину 8 байт (как в случае с моим компьютером и TIO)

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

Попробуйте онлайн!

объяснение

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-байтовый ответ ячейки, 40 байтов

В некоторых старых установках по умолчанию вместо 4-байтовых ячеек используются

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

объяснение

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
источник