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


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'versus 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

Наприкінці знак мінус (якщо такий є) та заключний рядок автоматично друкуються разом.


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, схоже, має кінцевий нуль
aditsu quit тому, що SE - EVIL

@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 для

Таким чином, вираз постійного струму обертається та усувається, 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-бітного плавання.
Цифрова травма
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.