Отформатируйте число с плавающей запятой в точности как десятичное

9

Любая двоичная с плавающей точкой может быть отформатирована точно в десятичном формате. Результирующая строка может быть несколько длинной, но это возможно. В моей статье о плавающей запятой я рассказываю о важности точности, и теперь я хочу эту функцию. Эта задача состоит в том, чтобы написать программу или функцию, которая принимает значение с плавающей запятой в качестве входных данных и форматирует точную десятичную строку в качестве выходных данных.

Чтобы убедиться, что мы работаем с правильными числами с плавающей запятой, в качестве входных данных для программы должен быть указан точный формат. Этот формат будет двумя целыми числами Significand Exponent, где фактическое значение с плавающей запятой равно Significand * 2 ^ Exponent. Обратите внимание, что любое значение может быть отрицательным.

Особенности:

  • Диапазон и точность не менее 32-разрядного числа с плавающей запятой должны поддерживаться (никакие входные данные не выходят за пределы этого)
  • Значение в десятичном формате должно быть точным представлением (достаточно близко, чтобы гарантировать, что правильное закругление назад для плавания не достаточно хорошо)
  • Мы не верим, что стандартные функции форматирования с плавающей запятой являются достаточно правильными и достаточно быстрыми (например, printf), и поэтому они могут не использоваться. Вы должны сделать форматирование. Встроенные функции форматирования / преобразования разрешены.
  • Не может быть никаких начальных или конечных нулей, за исключением обязательного начального нуля перед компонентом, .если нет целого числа
  • Разрешена функция или целая программа.

Примеры:

1 -2 => 0.25
17 -3 => 2.125
-123 11 => -251904
17 50 => 19140298416324608
23 -13 => 0.0028076171875
3 120 => 3987683987354747618711421180841033728
3 -50 => 0.00000000000000266453525910037569701671600341796875
-3 -50 => -0.00000000000000266453525910037569701671600341796875
10 -2 => 2.5
-12345 -3 => -1543.125
0 0 => 0
161 -4 => 10.0625
512 -3 => 64

Самый короткий код выигрывает.

эд-ка морт-ора-й
источник
3
Разрешено ли использование арифметики с плавающей точкой неограниченной точности?
Деннис
2
Если показатель неотрицателен, можем ли мы закончить .0?
Sp3000
@ Денис: Да, допускается арифметика с неограниченной или высокой фиксированной точностью.
edA-qa mort-ora-y
1
Я думаю, что это противоречиво. Если 0.abcне ведущий ноль, то abc.0не конечный.
orlp
1
Также принято всегда заканчиваться .0целыми числами при работе с числами с плавающей запятой. Смотрите, например, Python: str(1.0) == '1.0'против str(1) == '1'. Ваша логика все еще противоречива.
orlp

Ответы:

3

CJam, 43

r_'-&\ize999rim<s1e3'0e[W%999/(i_L?\+'.*sW%

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

Объяснение:

Программа работает с показателями до ± 999, близкими к двойной точности (64 бита). Он отделяет знак минус (если имеется) от значения и умножает его на 10 999, затем выполняет сдвиг в битах с показателем степени, который теперь является точным вычислением. Затем она дополняется нулями, если результат содержит менее 1000 цифр, отделяет последние 999 цифр как дробную часть, удаляет завершающие нули путем преобразования обратного числа в целое, добавляет десятичную точку, если необходимо, и собирает все обратно.

r_         read and duplicate the significand in string form
'-&        keep only the minus sign, if present
\          swap with the other copy of the significand
iz         convert to integer and get absolute value
e999       multiply by 10^999
ri         read the exponent and convert to integer
m<         shift left by it; negative values will shift right
            the result is an exact non-negative integer
s          convert to string
1e3'0e[    pad to the left with zero characters up to length 1000
            longer strings will be left intact
            we need 1 more than 999 for the 0.xxx case
W%         reverse the string
999/       split into slices of length 999
(          take out the first slice (reversed fractional part)
i          convert to integer
            this removes the leading zeros (trailing in reverse)
_L?        if it's zero, replace with an empty string
\+         concatenate back (to the left) with the second slice
'.*        join the with the dot character
            if the fractional part was zero, we only have the second slice
            (reversed integer part) and there is nothing to join
s          convert to string; this is the reversed result without the sign
W%         reverse back

В конце знак минус (если есть) и итоговая строка автоматически печатаются вместе.

уйти, потому что SE это зло
источник
2

CJam, 50 байтов

q~A1$z#\_0>K5?\z:E#@_s'-&oz*\md_sE'0e[W%isW%'.\+Q?

Это полная программа, которая читает из STDIN. Попробуйте онлайн в интерпретаторе CJam .

Проверьте все тестовые случаи одновременно.

Деннис
источник
Исходя из вашего комментария, я предполагаю, что CJam обладает неограниченной точностью, и вы использовали это здесь? Правильно ли тогда, что этот ответ охватывает любой ввод, а не только 32-битное значение с плавающей запятой? Кроме того, мы можем получить объяснение того, как это работает?
edA-qa mort-ora-y
CJam имеет неограниченную точность для целых чисел, но только с плавающей запятой двойной точности. Я умножаю на степень 20 для положительных показателей и степень 5 для отрицательных, приведу к строке и вставлю точку. Я добавлю подробное объяснение через несколько часов.
Деннис
И да, учитывая достаточное количество памяти, это должно работать для любого ввода.
Деннис
10 -2, кажется, имеет конечный ноль
адицу ушел, потому что SE - ЗЛО
@aditsu: Ах да, один завершающий ноль на каждую степень 2 ...
Деннис
2

GNU sed + dc, 65

Оценка включает +1 для -rварианта Sed .

y/-/_/
s/.*/dc -e"C8k& 2r^*p"/e
s/\\\n//
s/0+$//
s/^(-?)\./\10./

Я испытал иск, чтобы требовать этого dc- только ответ C8k& 2r^*pна счет 10, но dcесть некоторые особенности форматирования:

  • знак -ve _вместо-
  • длинные строки разбиты обратными слешами
  • конечные нули должны быть удалены
  • |n| < 1должен быть добавлен начальный 0 для

Таким образом, выражение dc обернуто и удалено, sedчтобы позаботиться о вышеперечисленном.

Тестовый вывод:

$ echo "1 -2
17 -3
-123 11
17 50
23 -13
3 120
3 -50
-3 -50
8388608 127
1 -127" | sed -rf float.sed
0.25
2.125
-251904
19140298416324608
0.0028076171875
3987683987354747618711421180841033728
0.00000000000000266453525910037569701671600341796875
-0.00000000000000266453525910037569701671600341796875
1427247692705959881058285969449495136382746624
0.0000000000000000000000000000000000000058774717541114375398436826861112283890933277838604376075437585313920862972736358642578125
$ 
Цифровая травма
источник
Хм, я думаю, что dcэто нарушает мое правило использования стандартной функции форматирования.
edA-qa mort-ora-y
1
@ edA-qamort-ora-y Я полагал, что использование в dcпорядке, учитывая, что «допускается арифметика с неограниченной или высокой фиксированной точностью» . dc«S pкоманда не является„ плавающей точкой функции форматирования“ - это произвольная функция точность печати. Я устанавливаю точность до 128 знаков после запятой ( C8k), что, я думаю, более чем достаточно для любого 32-разрядного числа с плавающей запятой.
Цифровая травма