В качестве входных данных вы получите целое число k
в диапазоне от -4503599627370496
(−2 52 ) до 4503599627370496
(2 52 ). Как хорошо известно , целые числа в этом диапазоне могут быть представлены в точности как значения с плавающей запятой двойной точности.
Вы должны выход на вес Хемминга (количество единиц) в кодировании k
в формате binary64 . При этом используется 1 бит для знака, 11 бит для показателя степени (закодированный со смещением) и 52 для мантиссы; см. ссылку выше для деталей.
В качестве примера , число 22
представляется как
0 10000000011 0110000000000000000000000000000000000000000000000000
Так как есть 5
, выход 5
.
Обратите внимание, что порядковый номер не влияет на результат, поэтому вы можете безопасно использовать фактическое внутреннее представление вашей машины значений двойной точности для вычисления выходных данных.
Дополнительные правила
- Программы или функции разрешены.
- Любой язык программирования может быть использован.
- Стандартные лазейки запрещены
- Введенный номер будет в десятичном виде. Помимо этого, средства ввода и вывода и формат, как обычно, являются гибкими .
- Самый короткий код в байтах побеждает.
Контрольные примеры
22 -> 5
714 -> 6
0 -> 0
1 -> 10
4503599627370496 -> 5
4503599627370495 -> 55
1024 -> 3
-1024 -> 4
-4096 -> 5
1000000000 -> 16
-12345678 -> 16
источник
binary64
формате с плавающей запятой , если они хотят? Некоторые люди (в том числе и я изначально) интерпретировали этот вопрос как требование, чтобы функции принимали входные данные как целочисленный тип, например Сиlong
. В C вы можете утверждать, что язык будет конвертировать для вас, так же, как когда вы звонитеsqrt((int)foo)
. Но есть некоторые ответы asm для машинного кода x86 (например, codegolf.stackexchange.com/a/136360/30206 и мой), которые оба предполагали, что нам нужно принять 64-битные целочисленные входные данные. Принятиеbinary64
значения сохранит 5 байтов.binary64
целых чисел base2. В любом случае, если вам нужно обрабатывать их отдельно, возможно, стоит сделать что-то иное, нежели тип-каламбур и цикл по всем битам.long
, так что вы не могли бы просто сказать что-нибудь двоичное64double
, потому что не все двойные числа являются целыми числами. Но все целочисленныеdouble
s могут быть преобразованы вlong
и обратно, вплоть до пределовlong
. (Как вы указали, обратное неверно. Вы получаете ближайшее представлениеdouble
, предполагая режим округления по умолчанию). Во всяком случае, это был совершенно правильный способ задать вопрос; Я просто не прочитал это внимательно>. <Ответы:
MATL , 5 байтов
Попробуйте онлайн!
Точная транслитерация моего ответа в MATLAB. Обратите внимание, что ввод и вывод неявны. -2 байта благодаря Луису Мендо.
источник
машинный язык x86_64 (Linux), 16 байт
Принимает один 64-битный целочисленный параметр в
RDI
, преобразует его в значение с плавающей запятой вXMM0
, сохраняет эти биты обратноRAX
, а затем вычисляет вес ХэммингаRAX
, оставляя результат,RAX
чтобы он мог быть возвращен вызывающей стороне.Требуется процессор, поддерживающий
POPCNT
инструкцию, который будет Intel Nehalem, AMD Barcelona и более поздние микроархитектуры.Для того, чтобы попробовать его в Интернете! , скомпилируйте и запустите следующую программу на C:
источник
objdump -drwC -Mintel
чтобы разобрать в Intel синтаксис. Если у вас есть указатель в регистре, который вы можете использовать для хранения / перезагрузки, вы можете сохранить байты с помощьюmovaps [rsi], xmm0
/popcnt rax, [rsi]
. (movaps всего 3 байта, на 2 короче, чем movq.) Но это не поможет, потому что[rsp-24]
требует 2 дополнительных байта (SIB от использования RSP в качестве основы, плюс disp8). И эти дополнительные байты необходимы как для хранения, так и для перезагрузки. Ну да ладно, я думал, что видел спасение, но нет: /C (gcc) ,
8268 байт9 байт благодаря Нейлу.
злой хакинг с плавающей точкой
Попробуйте онлайн!
источник
;long l=
...;l*=2;)s+=l<0;
...long
. Он работает на x86-64 Linux, но не работает на Windows. Я бы посоветовал сказать «gcc with 64-bitlong
», поскольку gcc работает на многих платформах, многие из которых имеют разные ABI.Python 3 ,
7271 байт1 байт благодаря Линн.
Попробуйте онлайн!
объяснение
Формат binary64 состоит из трех компонентов:
1
если число отрицательноеисточник
n and(…)-(n>0)
байт короче, нет?C (gcc) , 47 байтов
Это не портативно; он был протестирован с gcc 7.1.1 на x86_64 под управлением Linux без флагов компилятора.
Попробуйте онлайн!
источник
long
вdouble
на сайте вызова?n
вrax
с ООН-оптимизированный код довольно дрянной. Он ломается, если вы включаете-O3
, так что это не просто gcc в общем, это gcc на x86-64 с 64-битнойlong
с отключенной оптимизацией. Если вы включите все эти требования в свой ответ, я бы проголосовал. Я бы предположил, что есть платформы, поддерживаемые gcc, которые имеют 64-битную версию,long
но вpopcountl
результате результат остается в регистре, отличном от регистра возвращаемого значения.double
должно быть хорошо. В нем ничего не говорится о требовании функции принять ее в формате base2. И да, разные версии gcc могут выдавать разный код, поэтому это тоже важно. (Интересный факт: без-mpopcnt
, gcc не будет использоватьpopcnt
insn и будет выдавать последовательность инструкций для эмуляции. Некоторые архитектуры вообще не имеют команды popcnt, поэтому__builtin_popcountl
всегда должны использовать некоторую последовательность insns)__builtin_*
Функций имеют устаревшие версии, чтобы избежать создания недопустимых инструкций.-march=native
используетpopcntq
только если это доступно.Java (OpenJDK 8) , 92 байта
Попробуйте онлайн!
источник
C (gcc), 63 байта
Это решение основано на ответе @ LeakyNun, но поскольку он не хочет улучшать свой собственный ответ, я публикую здесь более подходящую версию.
Попробуйте онлайн
источник
C #,
817068 байтСохраните 11 байтов благодаря @Leaky Nun.
Сохранено 2 байта благодаря @Neil.
Попробуйте онлайн! Использует
System.BitConverter.DoubleToInt64Bits
вместоunsafe
кода, так как я не мог заставить TIO работать с ним.Полная / Отформатированная версия:
источник
for(;l!=0;l*=2)
и вам не понадобится троичныйs-=l>>31
?s+=l<0?1:0
?l
это долго, так это нужноs-=l>>63
?Python 2 , 69 байт
-12 байт, благодаря @ ASCII-only
Попробуйте онлайн!
источник
!
не нужен, так как порядок байтов здесь не имеет значенияJavaScript (ES6),
818077 байтРедактировать: 1 байт сохранен благодаря @Arnauld. Сохранено 3 байта благодаря @DocMax.
источник
g(i^i&-i,x++)
за -1 байт?new Float64Array([n])
наFloat64Array.of(n)
машинный код x86-64, 12 байт для
int64_t
ввода6 байтов для
double
вводаТребуется
popcnt
расширение ISA (CPUID.01H:ECX.POPCNT [Bit 23] = 1
).(Или 13 байтов, если изменение аргумента на месте требует записи всех 64-битных, вместо того, чтобы оставлять мусор в верхних 32-х. Я думаю, что разумно утверждать, что вызывающая сторона, вероятно, в любом случае захочет загрузить только младший 32b, а ноль x86 - расширяется с 32 до 64 неявно с каждой 32-битной операцией. Тем не менее, он останавливает вызывающую функцию
add rbx, [rdi]
или что-то в этом роде.)Инструкции x87 короче, чем более очевидный SSE2
cvtsi2sd
/movq
(использованный в ответе @ terracecat ), а[reg]
режим адресации имеет тот же размер, что иreg
: просто байт mod / rm.Хитрость заключалась в том, чтобы придумать способ передачи значения в памяти без необходимости использовать слишком много байтов для адресации режимов. (например, передача в стек не так уж хороша.) К счастью, правила разрешают чтение / запись аргументов или отдельные выходные аргументы , поэтому я могу просто заставить вызывающую сторону передать мне указатель на память, которую мне разрешено писать.
Вызывается из C с подписью:
void popc_double(int64_t *in_out);
допустим только младший 32b результата, что может быть странно для C, но естественно для asm. (Для исправления требуется префикс REX в последнем хранилище (mov [rdi], rax
), то есть еще один байт.) В Windows изменитеrdi
наrdx
, поскольку Windows не использует x86-64 System V ABI.Листинг NASM. Ссылка TIO имеет исходный код без разборки.
Попробуйте онлайн! Включает в себя
_start
тестовую программу, которая передает ему значение и завершается со значением выхода status = popcnt. (Откройте вкладку «отладка», чтобы увидеть его.)Передача отдельных указателей ввода / вывода также будет работать (rdi и rsi в x86-64 SystemV ABI), но тогда мы не сможем разумно уничтожить 64-битный ввод или так же легко оправдать необходимость 64-битного выходного буфера при записи только низкий 32б.
Если мы хотим утверждать, что мы можем взять указатель на целое число ввода и уничтожить его, возвращая при этом вывод
rax
, то просто опустить значениеmov [rdi], eax
frompopcnt_double_outarg
, уменьшив его до 10 байтов.Альтернатива без глупых хитростей, 14 байтов
используйте стек как пустое место,
push
чтобы получить его там. Используйтеpush
/pop
для копирования регистров в 2 байта вместо 3 дляmov rdi, rsp
. ([rsp]
всегда требуется SIB-байт, поэтому стоит потратить 2 байта на копирование,rsp
прежде чем использовать три инструкции.)Звоните из C с этой подписью:
int popcnt_double_push(int64_t);
Принятие ввода в
double
форматеВопрос только говорит, что это целое число в определенном диапазоне, а не то, что оно должно быть в двоичном целочисленном представлении base2. Принятие
double
ввода означает, что больше нет смысла использовать x87. (Если только вы не используете пользовательское соглашение о вызовах, в которомdouble
s передается в регистрах x87. Затем сохраните его в красной зоне под стеком и оттуда попкорн.)11 байт:
Но мы можем использовать тот же трюк с передачей по ссылке, что и раньше, чтобы сделать 6-байтовую версию:
int pcd(const double&d);
6 байт .
источник
Perl 5 ,
3332 + 1 (-p) =3433 байтаСохранено 1 байт благодаря Hobbs
Попробуйте онлайн!
источник
d
голое слово (pack d,$_
вместоpack"d",$_
)MATLAB, 36 байт
Использование факта, который
de2bi
не только корочеdec2bin
, но и дает результат в единицах и нулях, а не ASCII 48, 49.источник
Java (64, 61, 41 байт)
Совершенно просто, используя стандартную библиотеку (Java SE 5+):
Вклад Кевина Круйссена (Java SE 5+):
Вклад Кевина Круйссена (Java SE 8+, лямбда-функция):
источник
Long n
и используяn.bitCount(...)
вместоLong.bitCount(...)
. Кроме того, если вы используете Java 8+, вы можетеn->n.bitCount(Double.doubleToLongBits(n))
Просто чтобы попробовать другой, более безопасный, чем TheLethalCoder подход, я придумал это (жаль, что C # имеет такие длинные имена методов):
C # (.NET Core) , 76 + 13 байт
Попробуйте онлайн!
Количество байтов включает 13 байтов для
using System;
. Сначала мне нужно преобразовать вdouble
a,long
который имеет такое же двоичное представление, затем я могу преобразовать его в двоичный файлstring
, а затем я посчитал1
s, просто разделив строку и посчитав подстроки минус 1.источник
using
в свой счетчик байтов.namespace System.Linq;{d=>Convert.ToString(BitConverter.DoubleToInt64Bits(d),2).Count(c=>c>48)}
. Хотя я не проверял это, оно должно работать.using
директиву.namespace
пригодится. Но да, в этом случае избежать Linq было немного дешевле. Я просто хотел прокомментировать этот подход, если у вас есть идеи, как сократить его, чтобы сэкономить байты.Sum(c=>c&1)
короче. ИлиSum()-768
Желе , 19 байт
Попробуйте онлайн!
источник
постоянный ток, 79 байт
Выход остается на вершине стека.
Я добавлю объяснение позже.
Попробуйте онлайн!
Обратите внимание, что отрицательным числам предшествует
_
, а не-
.источник
Groovy (с парсером Parrot) , 46 байт
источник
C 67 байт
контрольный код и результаты
источник
Эрланг 55 байт
Анонимная функция, которая считает все
1
s в числе, закодированном как 64-разрядное число с плавающей запятой.Ссылки:
источник