Найти - Пользователи
Полная версия: система счисления с основанием n
Начало » Python для новичков » система счисления с основанием n
1 2 3
shiroi
py.user.next
out = re.sub(r'\(\d+\)', lambda mo: trans(mo.group()), number), re.sub это как я понимаю функция замены?а можно ее заменить например s.replace?
py.user.next
shiroi
а можно ее заменить например s.replace?
Нет. str.replace() ходит всегда по всей строке и для каждой цифры надо будет вызывать str.replace() снова. А re.sub() идёт один раз по строке и для каждой встреченной цифры делает сразу её замену. Замена у re.sub() умная (это распространённый шаблон для многих языков) и делает не просто замену строки на строку, а делает замену строки на результат функции, в которую передаётся найденная подстрока. Таким образом мы можем использовать отображение одних строк на другие (в виде словаря с парами), чтобы замена происходила по этому отображению. А в str.replace() можно только одну строку на одну строку заменять, поэтому она здесь не подходит. То есть re.sub() может искать, на что заменить совпавшую подстроку, а str.replace() может только тупо заменить определённую строку на определённую строку.

Вот пример гибкости re.sub()
  
>>> import re
>>> 
>>> re.sub(r'.', lambda mo: str(int(mo.group()) ** 2), '1234') # находим квадрат каждой цифры и пишем в результат
'14916'
>>>
>>> re.sub(r'.', lambda mo: mo.group() * 3, '1234') # утраиваем каждую цифру и пишем в результат
'111222333444'
>>>
>>> re.sub(r'(..)(..)', lambda mo: str(sum(map(int, mo.groups()))), '1234') # находим пары цифр, складываем двузначные числа и пишем в результат
'46'
>>>
>>> re.sub(r'.', lambda mo: print('see', mo.group()) or mo.group() * 2, '1234') # выводим найденные цифры, удваиваем их и пишем в результат
see 1
see 2
see 3
see 4
'11223344'
>>>
shiroi
py.user.next
эх, плюсов то много, правда у меня условие что не могу использовать сторонние библиотеки, поэтому re.sub не могу использовать
py.user.next
Вот ещё монолитный вариант.
shiroi
py.user.next
почти все правильно работает, кроме правой части, если после точки вводить что-нибудь, отличное от левой части, то он начинает неправильно считать, например: 12345.12345 в 36 он выводит правильно, 9ix.15wx, а вот если 12345.54321, то он выводит 9ix.15wx вместо 9ix.1920007162620232434
py.user.next
shiroi
почти все правильно работает, кроме правой части
Да я просто неправильно посчитал дробную часть, Забыл, как это делается (давно делали, где-то в 2002-м, если не в 2000-м ). Там другой алгоритм. Надо умножать дробь с нулевой целой частью на основание системы счисления и получающуюся целую часть брать в качестве очередной цифры. Надо всё переделать.

Add
Посмотрел тут, многие дроби получаются периодическими (бесконечными). Так что надо определиться с количеством знаков после запятой.

Пример перевода непериодической дроби из 10-чной в периодическую 2-ичную:
1.1d = 1.0(0011)b

Так что нужно брать сколько-то знаков после запятой.


shiroi
а вот если 12345.54321, то он выводит 9ix.15wx вместо 9ix.1920007162620232434
https://numsys.ru/
12345.54321 = 9IX.JK007GQL696Y2QPBJYPJUK92SRYXUG3S10HTZIKXYLEJSHLOX1

Фишка в том, что 19 и 20 надо тоже переводить в буквы. То есть там, в калькуляторе, где ты считал, это не учли.

А я вот считаю в Emacs'е
http://www.imageup.ru/img122/2900764/emacs-calc1.png.html
http://www.imageup.ru/img122/2900765/emacs-calc2.png.html
Это автоматический результат и вручную ещё посчитал обе цифры через умножение.

Повысил точность до 40 десятичных знаков
http://www.imageup.ru/img122/2900771/emacs-calc3.png.html
shiroi
py.user.next
ограничение 8 знаков после точки на выводе
py.user.next
shiroi
ограничение 8 знаков после точки на выводе
Видишь, надо точно знать, чтобы сначала юнит-тесты написать. Без юнит-тестов не будешь точно знать, работает ли функция без ошибок. Она же большая, всё в голове держать заманаешься, поэтому делаются юнит-тесты, которые её запускают и проверяют результат сразу. Если результаты всех тестов правильные, то он просто пишет точки. Если результат неправильный где-то, то он сразу пишет сообщение об ошибке (сбой теста).

Чтобы запускать юнит-тесты, у тебя должен быть установлен модуль pytest.
Потом просто в директории запускаешь
python3 -m pytest
и оно их находит и запускает все тесты.

Попозже посмотрю скрипт, сейчас надо проверить кое-что. Спешка в этих делах - дело неблагородное. При спешке часто потом приходится заново всё переписывать.
py.user.next
Да, видимо, в питоне такой алгоритм не прокатит из-за слишком малой точности у вещественных чисел
[guest@localhost numbase_mono]$ python3 -m pytest
================================== test session starts ===================================
platform linux -- Python 3.6.1, pytest-3.1.1, py-1.4.34, pluggy-0.4.0
rootdir: /home/guest/prog/tests/py/numbase_mono, inifile:
plugins: mock-1.6.2, cov-2.4.0
collected 14 items

test_numbase.py .F............

======================================== FAILURES ========================================
__________________________________ test_fraction_values __________________________________

def test_fraction_values():
lst = (
(1.1, 2, '1.000110011'),
(10.5, 2, '1010.1'),
(255.255, 16, 'ff.4147ae147a'),
(12345.12345, 36, '9ix.4fzolfdnfyd'),
(12345.54321, 36, '9ix.jk007gql696'),
)
for i1, i2, o in lst:
> assert f(i1, i2) == o
E AssertionError: assert '9ix.4fzolfdl0g' == '9ix.4fzolfdnfyd'
E - 9ix.4fzolfdl0g
E ? ^^^
E + 9ix.4fzolfdnfyd
E ? ^^^^

test_numbase.py:26: AssertionError
========================== 1 failed, 13 passed in 0.05 seconds ===========================
[guest@localhost numbase_mono]$
Как только начинаешь выходить за пределы точности при умножении дробной части, она начинает давать неправильный результат.

Так что тут, походу, другой алгоритм надо применять: сначала убрать плавающую точку из числа, потом проводить вычисления, а потом возвращать её обратно с учётом новой системы счисления.
py.user.next
В общем, небольшие вещественные числа она правильно вычисляет, но когда число становится больше по точности (когда исходная дробь растёт), начинаются глюки.

Поковырял это математически, можно там замутить рекурсивную функцию, если в питоне точности не хватает.

Например:
0.12d == 0.(1EB85)h

Приводим к дробному виду
12 / 100 = x / 256

Находим x
x = (12 * 256) / 100 = 30.72

Получаем равное соотношение (слева в десятичной системе, справа - в 16-ричной)
12 / 100 = 30.72 / 256

Дальше 30.72 переводим по частям в 16-ричную систему
30 = 1E
0.72 = 0.(B851E) (это так же переводится - приводится к дроби и так далее 72 / 100 = x / 256 … )

Потом склеиваем 1E и 0.(B851E) и получаем x в 16-ричной системе
0.1EB851E
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB