Умножьте два числа, не используя никаких чисел

30

Вам дается в качестве входных данных две строки, представляющие натуральные числа в базе 10, такие как "12345"и "42". Ваша задача - "518490"в этом случае вывести строку, содержащую их продукт .

Суть в том, что вы не можете использовать любые числовые типы в вашем коде. Нет ints, floats, unsigned longs и т. Д., Нет встроенных типов комплексных чисел или целых чисел произвольной точности, или что-нибудь в этом роде. Вы часто не используете литералы этих типов, ни какие-либо функции, методы, операторы и т. Д., Которые их возвращают.

Вы можете использовать строки, логические значения, массивы или что-либо еще, что обычно не используется для представления числа. (Но учтите, что ни индексация в массиве, ни получение его длины, вероятно, невозможны без вызова числового типа.) charРазрешены, но вы не можете выполнять над ними какие-либо арифметические или побитовые операции или иначе рассматривать их как что-то другое, кроме токен, представляющий часть строки. (Лексикографическое сравнение chars допускается.)

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

Ввод и вывод могут быть любым удобным способом, если данные входят и выходят из вашего кода в виде строки. Можно предположить, что каждый из двух входных аргументов содержит только символы ASCII [0-9]и не будет начинаться с 0. Ваш вывод также не должен иметь ведущих нулей.

Еще одна вещь: ваш код должен правильно обрабатывать вводы длиной не менее 10 символов и должен выполняться менее чем за минуту на современном компьютере для всех входов в этом диапазоне. Перед тем как отправить, пожалуйста , проверьте , что при предоставлении входа 9999999999и 9999999999ваша программа дает выход 99999999980000000001, менее чем за минуту. Это ограничение существует специально для предотвращения ответов, которые работают путем выделения массива размера a*bи последующей итерации по нему, поэтому имейте в виду, что ответы этой формы не будут иметь права на победу.

Это , поэтому выигрывает самое короткое действительное решение (в байтах).

Натаниель
источник
Можем ли мы принять "12345"от STDIN, а не 12345? Или мы можем принять оба числа как "12345", "42"?
Джастин
Моя первая мысль была написать функцию , принимающую строковые аргументы длины mи nи возвращает аргумент длины m*n. Но так как строки должны буквально содержать ASCII-представление чисел, я думаю, что это противоречит правилам.
Уровень Река St
1
@xnor на многих языках было бы короче выписать все дела. Но я нашел этот путь в Python:a,b="0123456789x".split('0');c=iter(b).next() if c=='x': c='0'
Натаниэль
1
или в Python 3,a,b="0123456789x".split(x);c,*d=b if c=='x': c='0'
Натаниэль
2
@ Натаниэльd='123456789';I=dict(zip('0'+d,d+'0'))
Джастин,

Ответы:

6

Хаскелл - 180 206 214

r=reverse
f=filter
z=['0'..'9']
a?f|f="1"!a
a?_=a
(a:b)!(c:d)=e:b!d?(e<a)where e=fst$last$zip(f(>=c)z++z)$f(<=a)z
a!c=a++c
a%(b:c)=foldr(!)('0':a%c)$f(<b)z>>[a]
_%b=b
a#b=r$r a%r b

Реализует умножение путем повторного сложения, а все виды магии цифр обрабатываются путем сдвига и фильтрации ['0'..'9']списка. Определяет оператор #типа String -> String -> String:

*> :set +s
*> "9990123456789"#"9999876543210"
"99900001219316321126352690"
(0.02 secs, 9862288 bytes)
МНИИП
источник
Похоже, у нас новый победитель! (Хотя, как и прежде, я не могу прочитать Haskell об этой степени сложности - может ли кто-нибудь самостоятельно проверить, соответствует ли он спецификации?)
Натаниэль
(Также ['0' .. '9'] выглядит как неявное обращение с символами как числами, которые можно повторять - есть ли короткий способ сгенерировать этот список из строки "0123456789"?)
Натаниэль
@Nathaniel Ну, прежде всего, строка "0123456789" - это список ['0'..'9']. Во-вторых, в Haskell [a..b] есть перечисление, типы, которые объявили экземпляры класса Enumтипов, могут быть перечислены таким же образом, и объявление описывает, как работает перечисление. Bool, логический тип также имеет экземпляр, и поэтому вы также можете сделать [False..True]. Есть только какие-то цифры.
Мниип
14

sed, 339 338 байт

Я знаю, что это старый, но я просматривал, и это пробудило мой интерес. Достаточно реально зарегистрироваться как пользователь! Я думаю, меня поразило « Я бы очень хотел увидеть полное решение sed - Натаниэль » ...

s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g
:o
s/\( .*\)0$/0\1/
/x$/{
x
G
s/ .*/\n/
:a
s/\(.*\)0\(x*\)\n\(.*\)0\(x*\)\n/\1\n\3\n0\2\4/
ta
s/\n//g
:c
s/^x/0x/
s/0xxxxxxxxxx/x0/
tc
x
s/x$//
}
/ 0/bo
g
s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g

Этот скрипт Sed ожидает двух десятичных чисел в качестве ввода, разделенных одним пробелом

Тесты:

time test 518490 = $(./40297.sed <<<)"12345 42" || echo fail
time test 99999999980000000001 = $(./40297.sed <<<"9999999999 9999999999") || echo fail
time test 1522605027922533360535618378132637429718068114961380688657908494580122963258952897654000350692006139 = $(./40297.sed <<<"37975227936943673922808872755445627854565536638199 40094690950920881030683735292761468389214899724061") || echo fail
time test 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413 = $(./40297.sed <<<"33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917") || echo fail

Вы можете распознать последние два как RSA-100 (50 x 50 цифр) и RSA-768 (116 x 116 цифр).

Использование GNU sed на не очень современном (Intel Core 2 2007 года) последнем из них занимает больше минуты, но быстрее на более новом процессоре:

  • Q6600:> 1 минута
  • i7-3770: 26 секунд
  • i7-6700: 22 секунды

Младшее десятизначное умножение, указанное в вопросе, занимает менее секунды на любом из них (несмотря на то, что в нем полно патологических девяток).

Я полагаю, что это стандартный sed, без расширений. POSIX гарантирует хранение только 8192 байтов, что ограничивает нас умножением 400х400 цифр, но реализации могут обеспечить больше. GNU sed ограничен только доступной памятью, поэтому может управлять чем-то намного большим, если вы готовы подождать.

И я уверен, что я выполнил правила - это почти что дано в языке, в котором нет цифр. :-)

объяснение

Я использую унарный / десятичный гибрид, преобразовывая десятичные числа в последовательность унарных:

 42 => _xxxx_xx

В одинарном десятичном виде сложение легко. Мы выполняем итерацию от наименее значимой к наиболее значимой цифре, объединяя x:

   X=965                   Y=106                                 SUM
   _xxxxxxxxx_xxxxxx_xxxxx _x__xxxxxx
   _xxxxxxxxx_xxxxxx       _x_                          _xxxxxxxxxxx
   _xxxxxxxxx              _x                    _xxxxxx_xxxxxxxxxxx
                                      _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx

Затем мы удаляем пробелы и работаем с переносом, конвертируя 10 последовательных x в один из следующих блоков:

 _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx       10.6.11
 _xxxxxxxxxx_xxxxxxx_x                10.7.1
 _x__xxxxxxx_x                        1.0.7.1 

Как только у нас есть сложение, возможно умножение. Мы умножаем x * y, учитывая последнюю цифру y. Добавьте x к аккумулятору столько раз, затем перейдите к следующей цифре и сдвиньте x на один знак после запятой влево. Повторяйте, пока у не станет ноль.

Расширенный код

#!/bin/sed -f

# Convert to unary decimal.  We save two or three bytes of code by
# reusing 0 as the digit separator.
s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g

# until y==0

:one

# y ends in zero => x *= 10 and y /= 10
s/\( .*\)0$/0\1/

# while y%10, acc += x, y -= 1
/x$/{
x
G
s/ .*/\n/
# Add x
:add
s/\(.*\)0\(x*\)\n\(.*\)0\(x*\)\n/\1\n\3\n0\2\4/
tadd
s/\n//g
:carry
s/^x/0x/
s/0xxxxxxxxxx/x0/
tcarry

# repeat for each unit of y
x
s/x$//
}

# y?
/ 0/bone


# convert hold space to decimal
g
s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g
Тоби Спейт
источник
1
Очень удовлетворительный ответ, спасибо!
Натаниэль
9

sed, 379 байт

Благодарность за этот блестящий ответ идет @LuigiTiburzi на Unix & Linux.SE: https://unix.stackexchange.com/a/37213/34061 . Я просто случайно наткнулся на это несколько дней назад:

s/[0-9]/<&/g
s/0//g
s/1/|/g
s/2/||/g
s/3/|||/g
s/4/||||/g
s/5/|||||/g
s/6/||||||/g
s/7/|||||||/g
s/8/||||||||/g
s/9/|||||||||/g
:t
s/|</<||||||||||/g
tt
s/<//g
s/.*\*$/0/
s/^\*.*/0/
s/*|/*/
:m
s/\(|*\)\*|/\1<\1*/
tm
s/*//g
s/<//g
:b
s/||||||||||/</g
s/<\([0-9]*\)$/<0\1/
s/|||||||||/9/
s/||||||||/8/
s/|||||||/7/
s/||||||/6/
s/|||||/5/
s/||||/4/
s/|||/3/
s/||/2/
s/|/1/
s/</|/g
tb

Широкое объяснение

  • Отделяйте каждую цифру. Таким 12*3становится<1<2*<3
  • Преобразуйте каждую цифру в это количество |символов. Таким <1<2*<3становится<|<||*<|||
  • Неоднократно заменить |<с <||||||||||тем чтобы переложить более высокие знаков после запятой все вплоть до позиции единиц. Таким <|<||*<|||становится<||||||||||||*<|||
  • Удалить <. Таким <||||||||||||*<|||становится||||||||||||*|||
  • Удалить 1 |из RHS в *. Таким ||||||||||||*|||становится||||||||||||*||
  • Повторно замените каждый |на RHS на все |на LHS. Это имеет эффект умножения левой и правой частях числа , |чтобы дать номер продукта из | Таким образом , ||||||||||||*||становится||||||||||||||||||||||||||||||||||||*
  • Удалить *. Таким ||||||||||||||||||||||||||||||||||||*становится||||||||||||||||||||||||||||||||||||
  • преобразовать число |обратно в десятичную с обратной стороны первых нескольких шагов. Таким ||||||||||||||||||||||||||||||||||||становится 36.

Выход:

$ echo "04*3
4*3
40*3
42*32
150*20
1*3
3*1
0*3
3*0" | sed -f mult.sed
12
12
120
1344
3000
3
3
0
0
$

К сожалению, это с треском проваливается из-за требований ко времени - 200*1000на моей виртуальной машине Ubuntu уходит 41 секунда, и время выполнения эмпирически возрастает с квадратом конечного продукта.

Цифровая травма
источник
1
Это почти алгоритмически эквивалентно моему удаленному ответу JS, за исключением преобразования обратно в числовую часть.
Оптимизатор
@Optimizer Согласен. Разница в том, что вы используете, length()который возвращает число. Этот использует чисто подстановку регулярных выражений без числовых типов. Я думаю, что ваш ответ потенциально победит, хотя, если вы можете удалить length()- возможно, вы могли бы вместо этого сделать какую-то аналогичную замену регулярному выражению?
Цифровая травма
1
Очень хорошо, но ограничение в одну минуту специально предназначено для предотвращения решений, которые работают путем подсчета до ответа. Я бы очень хотел увидеть полное решение SED, хотя.
Натаниэль
1
У меня есть ответ, который работает с большими числами (например, больше, чем адресное пространство системы).
Тоби Спейт
@TobySpeight да, очень хорошо. Я думаю, что я, должно быть, уже проголосовал против вас некоторое время назад
Digital Trauma
9

Питон - 312 286 273

D={}
e=t=""
N=[e]
for c in"0123456789":D[c]=t;D[t]=c;t+="I";N+=N
B=lambda s:[D[c]for c in reversed(s)]
Y=B(input())+N
for a in B(input())+N:
 for c in a:
    s=[];o=e
    for a,b in zip(N,Y):i=a+b+o;o=t<=i and"I"or e;s+=i.replace(t,e),;N=s
 Y=[e]+Y
print e.join(B(N)).lstrip("0")

Если (много) начальных нулей разрешены, последние 12 символов не нужны.

По сути, это выполняет стандартное умножение вручную. Цифры представлены в виде строк повторяющихся Is (как примитивные римские цифры). Числа представлены в виде списков цифр в обратном порядке. Добавление однозначных чисел осуществляется путем объединения строк и удаления десяти Iсекунд при необходимости.

Вот негольфированная версия:

N = [""] # zero object: list with a lot of empty strings
D = {}   # dictionary for conversion from and to digits
i = ""   # iterates over digits
for c in "0123456789":
    D[c] = i  # map digit to Roman digit
    D[i] = c  # and vice versa
    i += "I"  # increments Roman digit
    N += N    # add leading zeros to zero

ten = "IIIIIIIIII" # Roman digit ten

# Conversion function
B = lambda s: [D[c] for c in reversed(s)]

def Add(x,y):
    Sum = []
    carryover = ""
    for a,b in zip(x,y):
        increment = a+b+carryover
        carryover = "I" if ten in increment else ""
        increment = increment.replace(ten,"") # take increment modulo ten
        Sum += [increment]
    return Sum

def M(x,y):
    Sum = N[:] # Initiate Sum as zero
    X = B(x)+N # Convert and add leading zeros
    Y = B(y)+N
    for a in X:
        for c in a:
            Sum = Add(Sum,p+Y)
        Y = [""] + Y # multiply Y by 10
    return "".join(B(Sum)).lstrip("0") # Convert back and to string, remove leading zeros.

M(input(),input())
Wrzlprmft
источник
1
Что это за колдовство! Как это работает! Вау. Кроме того, вот еще один гольф, который вы могли бы сделать: def A(x,y):\n S=[];o=""-> def A(x,y,S=[],o=""):. Также, к сожалению, ["","1"][t in i]это не разрешено; он использует bool для индексации, рассматривая его как число. Я думаю, что это t in i and"1"or""должно работать, хотя.
Джастин
@Quincunx: определение Sв качестве аргумента по умолчанию не сработало бы, так как он всегда был бы одним и тем же списком даже для разных вызовов функции и, следовательно, не сбрасывался до []. Вы были правы ["","1"][t in i], я исправил это. Я также добавил объяснение.
Wrzlprmft
Это довольно удивительно. Сейчас он получает зеленую галочку. (Я отредактировал вопрос, чтобы уточнить, что начальные нули в выходных данных не допускаются - извините!)
Натаниэль
7

Рубин: 752 698

Это просто чтобы получить ответ, просто сделано из любопытства. Отредактировано: сейчас немного поиграл в гольф.

$F='0123456789'
$G="#{$F}abcdefghij"
def x(a,b);p(a=~/[13579]$/?b:"",a==""?"":x(Hash[*%w(b0 5 b1 6 b2 7 b3 8 b4 9)].to_a.inject(a.tr($F,'0011223344').chars.zip(a.tr($F,'ababababab').chars).flatten.join("")){|n,q|k,v=q;n.gsub(k,v)}.gsub(/[ab]/,'').sub(/^0*/,''),p(b,b)));end
def p(a,b);j,k=["0#{a}","0#{b}"].map{|c|c.gsub(/./,'0')};c="#{k}#{a}".chars.zip("#{j}#{b}".chars).drop_while{|z|z==%w(0 0)}.map{|m|$G.sub(/#{m.map{|n|"122333444455555666666777777788888888999999999".chars.select{|c|c==n}}.flatten.map{|c|'.'}.join("")}/,"").chars.first}.flatten.join("");d=nil;
while c!=d
 d=c;c="0#{d}".gsub(/[0-9][a-j]/) {|m| m.tr($G,"123456789a#{$F}")}.sub(/^0/,'')
end;c;end
puts x(ARGV.shift,ARGV.shift)

Использование: У меня было это в файле с именем peasant.rb:

$ time ruby peasant.rb 9999999999 9999999999
99999999980000000001

real    0m0.129s
user    0m0.096s
sys 0m0.027s

Объяснение: это крестьянское умножение, поэтому я многократно делю пополам. Деление пополам осуществляется путем деления пополам цифр и разметки остатков следующим образом: 1234 -> 0b1a1b2a; затем найдите и замените на b: 06a17a; затем уборка -> 617.

Сложение выполняется так ... во-первых, я дополняю обе строки до одинаковой длины и делаю пары из цифр. Затем я добавляю цифры, создавая строку, имеющую длину каждой цифры, и объединяю ее; Я удаляю строку такой длины с начала «0123456789abcdefghij», а затем сохраняю первый символ. Так, например, «9» + «9» -> «i». NB. Я избегаю фактически использовать здесь функции длины, чтобы полностью избежать типов чисел; удаление префикса выполняется с помощью регулярного выражения.

Так что теперь у меня есть строка, содержащая смесь цифр и букв. Буквы представляют цифры с переносной цифрой; Я добавляю 0 к числу, затем многократно заменяю цифро-буквенные шаблоны на результат переноса, пока сложение не будет завершено.

bazzargh
источник
1
Очень умный ответ, именно то, что я надеялся увидеть!
Натаниэль
1
Я действительно надеюсь, что кто-то опубликует один с церковными цифрами!
bazzargh,
Это было бы здорово, хотя я не уверен, что это будет работать с требованием эффективности - я думаю, что преобразование между строками и церковными цифрами будет эффективно включать в себя подсчет до 99999999980000000001.
Натаниэль
7

Brainfuck (1328 байт)

Сначала соображения:

  • Не уверен, является ли brainfuck верным ответом на эти вопросы, поскольку я не уверен, считаете ли вы значения ячеек «числовыми типами» или нет. Я так не думаю, так как bf не знает типов, но это мое собственное мнение, пожалуйста, поправьте меня, если я ошибаюсь.
  • Требуется реализация, поддерживающая (почти) неограниченные значения.
  • Это может быть слишком медленно, в зависимости от реализации.

Я тестировал программу только с моим собственным переводчиком, вы можете найти его здесь .

Входными данными должны быть оба числа, разделенные одним пробелом ASCII.

Golfed:

,>++++++[<----->-]<--[>,>++++++[<----->-]<--]>>>+<<<<[>>++++[<<---->>-]<<[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<,[>,]>>>+<<<<[>>+++++++[<<------->>-]<<+[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<<<<<[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Ungolfed:

,
>++++++[<----->-]<--
[                                           # read input until space
    >,
    >++++++[<----->-]<--                    # decrease cell by 32 to check if it's a space
]
>>>+<<<<                                    # set multiplier to 1

[

    >>++++[<<---->>-]<<                     # decrease by 16 to get cell value of number

    [>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]        # multiply value by multiplier
    >>>>>[<<<<<+>>>>>-]                     # copy value back
    <[>++++++++++<-]>[<<+>>-]               # multiply multiplier by 10
    <<<<<                                   # go back to number

    [->+<]>[-<+>]                           # add value to next cell and move sum to previous cell

    <<                                      # go to next number
]

>>>>[-]<                                    # delete old multiplier

,[>,]                                       # read second number until end of input
>>>+<<<<                                    # set new multiplier

[

    >>+++++++[<<------->>-]<<+              # decrease by 48 to get cell value of number

    [>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]        # multiply value by multiplier
    >>>>>[<<<<<+>>>>>-]                     # copy value back
    <[>++++++++++<-]>[<<+>>-]               # multiply multiplier by 10
    <<<<<                                   # go back to number

    [->+<]>[-<+>]                           # add value to next cell and move sum to previous cell

    <<                                      # go to next number
]

>>>>[-]<<<<<                                # delete multiplier

[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>          # multiply both values

# magical algorithm for printing cell value as number taken from Cedric Mamo's code from a previous question
[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Я взял код для вывода значения из этого ответа , спасибо автору за это!

Программа может быть недействительной, но в любом случае я хотел бы поделиться ею с вами ^^

Обновление: Теперь Вы можете проверить это (только для небольших умножений) здесь, благодаря @ Sp3000 в ответ на этот конкурс и новый стек Snippets SE,!

var NUM_CELLS = 30000;var ITERS_PER_SEC = 100000;var TIMEOUT_MILLISECS = 5000;function clear_output(){document.getElementById("output").value="";document.getElementById("stderr").innerHTML=""}function stop(){running=false;document.getElementById("run").disabled=false;document.getElementById("stop").disabled=true;document.getElementById("clear").disabled=false;document.getElementById("wrap").disabled=false;document.getElementById("timeout").disabled=false;document.getElementById("eof").disabled=false}function interrupt(){error(ERROR_INTERRUPT)}function error(e){document.getElementById("stderr").innerHTML=e;stop()}function run(){clear_output();document.getElementById("run").disabled=true;document.getElementById("stop").disabled=false;document.getElementById("clear").disabled=true;document.getElementById("wrap").disabled=true;document.getElementById("timeout").disabled=true;document.getElementById("eof").disabled=true;code=document.getElementById("code").value;input=document.getElementById("input").value;wrap=document.getElementById("wrap").value;timeout=document.getElementById("timeout").checked;eof=document.getElementById("eof").value;loop_stack=[];loop_map={};for(var e=0;e<code.length;++e){if(code[e]=="["){loop_stack.push(e)}else if(code[e]=="]"){if(loop_stack.length==0){error(ERROR_BRACKET);return}else{var t=loop_stack.pop();loop_map[t]=e;loop_map[e]=t}}}if(loop_stack.length>0){error(ERROR_BRACKET);return}running=true;start_time=Date.now();code_ptr=0;input_ptr=0;cell_ptr=Math.floor(NUM_CELLS/2);cells={};iterations=0;bf_iter(1)}function bf_iter(e){if(code_ptr>=code.length||!running){stop();return}var t=Date.now();for(var n=0;n<e;++n){if(cells[cell_ptr]==undefined){cells[cell_ptr]=0}switch(code[code_ptr]){case"+":if(wrap=="8"&&cells[cell_ptr]==255||wrap=="16"&&cells[cell_ptr]==65535||wrap=="32"&&cells[cell_ptr]==2147483647){cells[cell_ptr]=0}else{cells[cell_ptr]++}break;case"-":if(cells[cell_ptr]==0){if(wrap=="8"){cells[cell_ptr]=255}if(wrap=="16"){cells[cell_ptr]=65535}if(wrap=="32"){cells[cell_ptr]=2147483647}}else{cells[cell_ptr]--}break;case"<":cell_ptr--;break;case">":cell_ptr++;break;case".":document.getElementById("output").value+=String.fromCharCode(cells[cell_ptr]);break;case",":if(input_ptr>=input.length){if(eof!="nochange"){cells[cell_ptr]=parseInt(eof)}}else{cells[cell_ptr]=input.charCodeAt(input_ptr);input_ptr++}break;case"[":if(cells[cell_ptr]==0){code_ptr=loop_map[code_ptr]}break;case"]":if(cells[cell_ptr]!=0){code_ptr=loop_map[code_ptr]}break}code_ptr++;iterations++;if(timeout&&Date.now()-start_time>TIMEOUT_MILLISECS){error(ERROR_TIMEOUT);return}}setTimeout(function(){bf_iter(ITERS_PER_SEC*(Date.now()-t)/1e3)},0)}var ERROR_BRACKET="Mismatched brackets";var ERROR_TIMEOUT="Timeout";var ERROR_INTERRUPT="Interrupted by user";var code,input,wrap,timeout,eof,loop_stack,loop_map;var running,start_time,code_ptr,input_ptr,cell_ptr,cells,iterations
<div style="font-size:12px;font-family:Verdana, Geneva, sans-serif;"> <div style="float:left; width:50%;"> Code: <br> <textarea id="code" rows="4" style="overflow:scroll;overflow-x:hidden;width:90%;">,>++++++[<----->-]<--[>,>++++++[<----->-]<--]>>>+<<<<[>>++++[<<---->>-]<<[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<,[>,]>>>+<<<<[>>+++++++[<<------->>-]<<+[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<<<<<[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]</textarea> <br>Input: <br> <textarea id="input" rows="2" style="overflow:scroll;overflow-x:hidden;width:90%;">7 6</textarea> <p> Wrap: <select id="wrap"> <option value="8">8-bit</option> <option value="16">16-bit</option> <option value="32" selected="selected">32-bit</option> </select> &nbsp; Timeout: <input id="timeout" type="checkbox"></input>&nbsp; EOF: <select id="eof"> <option value="nochange">Same</option> <option value="0" selected="selected">0</option> <option value="-1">-1</option> </select> </p> </div> <div style="float:left; width:50%;"> Output: <br> <textarea id="output" rows="6" style="overflow:scroll;width:90%;"></textarea> <p> <input id="run" type="button" value="Run" onclick="run()"></input> <input id="stop" type="button" value="Stop" onclick="interrupt()" disabled="true"></input> <input id="clear" type="button" value="Clear" onclick="clear_output()"></input> &nbsp; <span id="stderr" style="color:red"></span></p></div></div>

шифровать
источник
Я не знаю, действительно ли это тоже! Я думаю, что в Brainfuck либо все число, либо ничего.
Натаниэль
Мне нравится этот ответ. Я в последнее время возился с БФ. это как бы проливает свет на тот факт, что на уровне машины все равно все просто токены. Трудно сказать, действительно ли это следует правилам или нет.
Осьминог
6

Питон, 394 349 340 символов

D='0123456789'
R=reversed
U=lambda x:[R for y in D if y<x]
T=U(':')
def A(a,b,r='',c=[]):
 for x,y in map(None,R(a),R(b)):
    d=U(x)+U(y)+c;t=T;c=[R]
    if d<T:t=c=[]
    r=min(k for k in D if U(k)+t>=d)+r
 if c:r='1'+r
 return r
a,b=input()
m=''
while b:
 if list(b).pop()in'13579':m=A(m,a)
 b=list(A(b,A(b,A(b,A(b,b)))));b.pop();a=A(a,a)
print m

Беги как:

echo '"9999999999","9999999999"' | ./mulstr.py

Занимает 50 миллисекунд.

Использует русское крестьянское умножение . При добавлении цифр мы конвертируем их в унарные ('5' => [R, R, R, R, R]), объединяем списки и затем конвертируем обратно. Uконвертируется в одинарный, используя Rв качестве одинарной цифры. Мы вычисляем b/=2как b=b*5/10.

Кит Рэндалл
источник
Пара гольфов: def A(a,b):\n r='';c=[]-> def A(a,b,r='',c=[]):, аналогично для def M. Вы могли бы быть в состоянии изменить for z in D:d.pop()\n c=['X']к [d.pop()for z in D];c=['X'], в этом случае вы могли бы даже свернуть его на предыдущий if. Кроме того, может if list(b).pop()in'13579'быть просто if b[:].pop()in'13579'?
Джастин
@Quincunx: Спасибо. Последняя не будет работать, потому что на первой итерации bэто строка, а не список.
Кит Рэндалл
Вы можете пропустить Mи написать полную программу; a,b=input() разрешено.
Джастин
1
b * 5/10 хороший трюк.
Bazzargh
Я просто наткнулся на reduce, который позволяет nicen A(b,A(b,A(b,A(b,b))))к reduce(A,[b,b,b,b,b]). К сожалению, это не влияет на количество персонажей.
Wrzlprmft
5

JavaScript (E6) 375 395 411 449

Редактировать Golfed
Редактировать Исправлена ​​ошибка: отсутствует очистка флага переноса

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

Примечания: использование строк, hashmap со строковым ключом, массивы, используемые в качестве списка. Нет индексации, массивы просматриваются с помощью «карты» или вращаются с помощью push & shift.
Все «+» являются конкатенацией строк.

M=(x,y,S=a=>a.shift()||z,R=a=>[...a].reverse(),e=R('9876543210'),d=[...e])=>
  R(y)[T='map'](b=>
     R(x)[T](a=>(
       u=R[e[a+=b]+v],
       v=R[S[a]+(u<v?'1':z)],
       p[P](t=R[S(o)+u]),
       t<u?v=R[v+'1']:v
     ),o=p,p=[])
    +(v>z&&p[P](v),x+=v=z),
    d[T](a=>d[T](b=>e[P='push'](R[a+b]=S(e)))+e[P](S(e))),  
    d[T](a=>d[T](b=>e[d[T](c=>v=c<a?(u=R[u+b])<b?R[v+'1']:v:v,v=u=z='0'),S[a+b]=v,a+b]=u)),
    p=[v=z]
  )&&R(p).join(o)

Меньше гольфа (возможно, я добавлю объяснение завтра)

M=(x,y)=>(
  R=a=>[...a].reverse(),
  // Addition table s 
  s={},
  e=[...'9012345678'],
  [for(a of(d='0123456789'))for(b of(e.push(e.shift()),d))e.push(s[a+b]=c=e.shift())],
  // Multiplication table m,n
  m={},n={},
  [for(a of d)for(b of d)(
     [for(c of(z=u=v='0',d))
     c<a&&(t=s[u+b],t<u?v=s[v+'1']:v,u=t)
     ],m[a+b]=u,n[a+b]=v
  )],
  x=R(x),v=z,o=[],p=[],
  [for(b of R(y))(
     [for(a of x)(
       u=s[m[a+b]+v],v=s[n[a+b]+(u<v?'1':z)],
       p.push(t=s[(o.shift()||z)+u]),
       t<u?v=s[v+'1']:v
     )],
     v>z?p.push(v):o,o=p,p=[],x.unshift(v=z)
  )],
  R(o).join('')
)

Тест в консоли FireFox / FireBug

t0=-new Date
r=M('9999999999','9999999999')
t1=-new Date
console.log("Result",r, "time ms", t0-t1)

Выход

Result 99999999980000000001 time ms 14
edc65
источник
Возможно, есть небольшая ошибка - выход из 9999999999дела должен быть 99999999980000000001, а не99999999980000000081
Натаниэль
:( собираюсь проверить
edc65
Если вы используете таблицы умножения, как вы обходите тот факт, что суммирование не допускается?
COTO
1
Суммирование разрешено с использованием хеш-таблицы (s в коде). Ex. s ['34 '] ->' 7 '. Просто символы, а не цифры. Может быть s ['cd'] -> 'g'
edc65
5

Haskell, 231 байт

Это определяет оператор #, который умножает два строковых представления натуральных чисел. Он работает путем определения элементарной операции увеличения / уменьшения строк, а затем использует ее для построения сложения и умножения. Небольшое дополнительное волшебство дает некоторые экспоненциальные ускорения, которые делают все это возможным.

r=reverse
n="9876543210"
t=True
c&(x:y)|c==x=head y|t=c&y
m%[]="1";m%(c:s)|c==last m=head m:m%s|t=c&m:s
[]!y=y;x![]=x;(x:a)!('0':b)=x:a!b;x!y=(r n%x)!(n%y)
"0"?_="0";x?('0':y)|all(=='0')y="0"|t=('0':x)?y;x?y=x?(n%y)!x
x#y=r$r x?r y

Этот подход достаточно быстр, и даже на ноутбуке 2008 года в неоптимизированном ghci REPL тестовый кейс занимает доли секунды:

λ> :set +s
λ> let test = replicate 10 '9'
(0.00 secs, 0 bytes)
λ> test
"9999999999"
(0.00 secs, 1069784 bytes)
λ> test # test
"99999999980000000001"
(0.06 secs, 13451288 bytes)

Вот проверка того, что все двузначные продукты верны:

λ> and [ show (x * y) == (show x # show y) | x <- [0..100], y <- [0..100] ]
True
Мэтт Нунан
источник
Похоже, у нас новый лидер! (Хотя я не могу читать Haskell - может ли кто-нибудь самостоятельно подтвердить, что он соответствует спецификации?)
Натаниэль
1
Да, это совершенно нелепый хаскелл, он соответствует спецификациям и работает так, как рекламируется. Отличная работа!
Bazzargh
4

Bash + ImageMagick: 52

convert -size ${a}x${b} xc:red txt:-|grep -v g|wc -l

Ожидается, что входные данные будут в переменных оболочки aи b. Это не особенно умно или эффективно, но это делает работу. Вероятно, это было сделано раньше.

Обратите внимание, что xобозначает размеры изображения; в этом контексте это не арифметический оператор.

Я не проверял это, но я готов предположить, что для неэкстремального ввода это завершится менее чем за одну минуту. Я могу проверить это завтра.

На случай, если с версиями ImageMagick возникнут забавные ситуации, я использую именно эту: ImageMagick 6.7.7-10

millinon
источник
Хорошая попытка, но я уверен, что это не сработает в течение минуты (или даже вообще на любой существующей машине) для входов 9999999999и 9999999999.
Натаниэль
4
Это также работает: dd if=/dev/zero bs=$a count=$b 2>&-|wc -c.
jimmy23013
1
9999999999x9999999999Изображение в формате 8bit будет занимать все пространство на жестком диске , который существует в настоящее время на Земле. Конечно, png будет намного меньше, если вы сможете создать его без предварительного создания необработанного изображения. (Хотя я сильно подозреваю, что у вас будут проблемы с целочисленным переполнением изображения такого размера.) Но, тем не менее, такой метод почти наверняка не справится с лазейкой "вызывающие вещи, которые возвращают числовые результаты в виде строк".
Натаниэль
1
Вы можете сохранить 2 байта, используя $bвместо ${b}.
nyuszika7h
1
Кроме того, вы можете сохранить 5 байтов, используя grep -vc gвместо grep -v g|wc -l.
nyuszika7h
2

Python 2 (подтверждение концепции)

Это решение работает с использованием только строк и списков и небольшого регулярного выражения. Я считаю, что это полностью соответствует спецификации, за исключением того, что это невозможно сделать 9999999999x9999999999за минуту. Хотя, учитывая достаточно времени, это сработает. Он может очень быстро умножить 4-значное число.

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

import re
D='123456789'
D=dict(zip('0'+D,D+'0'))

def toRlist(s):
    if s:t,h=re.match(r'(\d*)(\d)',s).groups();return[h,toRlist(t)]
    return''

def increment(r):
    if not r:return['1','']
    h,t=r
    return[D[h],increment(t)if h=='9'else t]

def toString(r):
    if not r:return''
    h,t=r
    return h+toString(t)

def listify(r,L):
    if not r:return
    h,t=r
    if h=='1':L.append('')
    if h=='2':L.extend(['',''])
    if h=='3':L.extend(['','',''])
    if h=='4':L.extend(['','','',''])
    if h=='5':L.extend(['','','','',''])
    if h=='6':L.extend(['','','','','',''])
    if h=='7':L.extend(['','','','','','',''])
    if h=='8':L.extend(['','','','','','','',''])
    if h=='9':L.extend(['','','','','','','','',''])
    listify(t,L);listify(t,L);listify(t,L);listify(t,L);listify(t,L)
    listify(t,L);listify(t,L);listify(t,L);listify(t,L);listify(t,L)

def add(r1,r2):
    L=[];listify(r2,L)
    for _ in L:r1=increment(r1)
    return r1

def multiply(a,b):
    total=''
    r=toRlist(a)
    L=[];listify(toRlist(b),L)
    for _ in L:total=r if total=='' else add(total,r)
    return''.join(reversed(toString(total)))

Примеры:

multiply('12','5') #returns the string 60

multiply('1869','1243') #returns the string 2323167
Кальвин Хобби
источник
1
+1, потому что он соответствует спецификации (кроме требований к эффективности), насколько я могу судить
Натаниэль
2

Python 2 (555)

Обычно я не отвечал на свой вызов так быстро (или вообще), но я хотел доказать, что это возможно. (К счастью, некоторые другие ответы делали это до этого, но я не мог не захотеть закончить это.) Есть еще кое-что, что можно сделать, но я думаю, что это разумно. Он обрабатывает 9999999999x9999999999случай менее 0,03 с на моей машине.

d="123456789";I=dict(zip('0'+d,d+'0'))
def r(x):return reversed(x)
def s(x):return''.join(x)
def i(x):
    try:
        h=I[x.next()]
        if h!='0':h+=s(x)
        else:h+=i(x)
        return h
    except:return'1'
def b(x,y):
    for c in'0'+d:
        if c==y:break
        x=iter(i(x))
    return x
def a(x,y):
    z=''
    for c in y:
        x=b(x,c)
        try:z+=x.next()
        except:z+='0'
    return z+s(x)
def n(x,y):
    z='0'
    for c in'0'+d:
        if c==y:break
        z=a(iter(z),x)
    return z
def o(x,y):
    x=s(x)
    l='';z=''
    for c in y:
        z=a(iter(z),l+s(n(x,c)))
        l+='0'
    return z
def m(x,y):
    return s(r(o(r(x),r(y))))

Пример использования: m("12345","42")

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

Вот объяснение функции за функцией:

  • rи sбухгалтерские функции. ( rэто просто псевдоним для reversed, который создает обратный итератор и sпреобразует итераторы в строки.)

  • iувеличивает число в строке на 1, включая такие случаи, как 39+1=40и 99+1=100.

  • bдобавляет xи y, но yдолжен быть только одна цифра. Это работает, увеличивая x yвремя.

  • aдобавляет два числа вместе, которые могут иметь несколько цифр, вызывая bкаждую цифру в y.

  • nумножается xи y, но yдолжен быть только одна цифра. Это работает, добавляя xк себе yвремя.

  • oумножается xи y, где оба аргумента могут иметь несколько цифр. Он использует классическое длинное умножение

  • mпросто преобразует свои строковые входные данные в обратные итераторы и передает их o, затем инвертирует результат и преобразует его в строку.

Натаниель
источник
Пара гольфов: def a(x,y):-> def a(x,y,z=''):и удалить следующую строку; подобные приемы для других функций, в def o(x,y):, изменить , x=s(x)чтобы x=s(x);l='';z='', в том , что цикл, аналогично удалить новую строку + шаги; вместо этого используйте ;. Кроме того, я думаю, что это if h!='0':h+=s(x)\nelse:h+=i(x)может быть просто h+=h!='0'and i(x)or s(x); возможно даже h+=(h!='0'and i or s)(x); в противном случае просто измените на if'0'!=h. Также такие вещи, как def r(x):return reversed(x)->r=reversed
Джастин
Кроме того, я забыл упомянуть для s, m: s=lambda x:''.join(x), m=lambda x,y:s(r(o(r(x),r(y))))вместо всего объявления функции. Благодаря тому, что я знаю, что это работает, ваш счетчик байтов уменьшается до 521.
Джастин
Да, и еще один: для ваших forциклов: for c in'0'+d:\nif c==y:break\nz=a(iter(z),x)-> for c in'0'+d:\nif c!=y:z=a(iter(z),x), хотя это может значительно изменить скорость вашей программы.
Джастин
@Quincunx спасибо! Я вижу еще несколько улучшений этим утром. (В основном, вкладывая циклы вместо определения функций.) Я внесу эти изменения, если появятся более конкурентные ответы, что кажется вероятным - в настоящее время они поставят меня в лидеры, что кажется немного несправедливым, так как это был мой вопрос, и я ' Нам пришлось больше думать об этом.
Натаниэль
2

JavaScript: 3710 3604 байта

  • Использование таблиц поиска строк с умножением на 1 цифру и добавление с переносом.
  • Умножение производится цифрой х цифра вместо цифры х строки.

Гольф:

var M={
'00':'0','01':'0','02':'0','03':'0','04':'0','05':'0','06':'0','07':'0','08':'0','09':'0',
'10':'0','11':'1','12':'2','13':'3','14':'4','15':'5','16':'6','17':'7','18':'8','19':'9',
'20':'0','21':'2','22':'4','23':'6','24':'8','25':'10','26':'12','27':'14','28':'16','29':'18',
'30':'0','31':'3','32':'6','33':'9','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
'40':'0','41':'4','42':'8','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
'50':'0','51':'5','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
'60':'0','61':'6','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
'70':'0','71':'7','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
'80':'0','81':'8','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
'90':'0','91':'9','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81'
};
var A={
'000':'0','001':'1','002':'2','003':'3','004':'4','005':'5','006':'6','007':'7','008':'8','009':'9',
'010':'1','011':'2','012':'3','013':'4','014':'5','015':'6','016':'7','017':'8','018':'9','019':'10',
'020':'2','021':'3','022':'4','023':'5','024':'6','025':'7','026':'8','027':'9','028':'10','029':'11',
'030':'3','031':'4','032':'5','033':'6','034':'7','035':'8','036':'9','037':'10','038':'11','039':'12',
'040':'4','041':'5','042':'6','043':'7','044':'8','045':'9','046':'10','047':'11','048':'12','049':'13',
'050':'5','051':'6','052':'7','053':'8','054':'9','055':'10','056':'11','057':'12','058':'13','059':'14',
'060':'6','061':'7','062':'8','063':'9','064':'10','065':'11','066':'12','067':'13','068':'14','069':'15',
'070':'7','071':'8','072':'9','073':'10','074':'11','075':'12','076':'13','077':'14','078':'15','079':'16',
'080':'8','081':'9','082':'10','083':'11','084':'12','085':'13','086':'14','087':'15','088':'16','089':'17',
'090':'9','091':'10','092':'11','093':'12','094':'13','095':'14','096':'15','097':'16','098':'17','099':'18',
'100':'1','101':'2','102':'3','103':'4','104':'5','105':'6','106':'7','107':'8','108':'9','109':'10',
'110':'2','111':'3','112':'4','113':'5','114':'6','115':'7','116':'8','117':'9','118':'10','119':'11',
'120':'3','121':'4','122':'5','123':'6','124':'7','125':'8','126':'9','127':'10','128':'11','129':'12',
'130':'4','131':'5','132':'6','133':'7','134':'8','135':'9','136':'10','137':'11','138':'12','139':'13',
'140':'5','141':'6','142':'7','143':'8','144':'9','145':'10','146':'11','147':'12','148':'13','149':'14',
'150':'6','151':'7','152':'8','153':'9','154':'10','155':'11','156':'12','157':'13','158':'14','159':'15',
'160':'7','161':'8','162':'9','163':'10','164':'11','165':'12','166':'13','167':'14','168':'15','169':'16',
'170':'8','171':'9','172':'10','173':'11','174':'12','175':'13','176':'14','177':'15','178':'16','179':'17',
'180':'9','181':'10','182':'11','183':'12','184':'13','185':'14','186':'15','187':'16','188':'17','189':'18',
'190':'10','191':'11','192':'12','193':'13','194':'14','195':'15','196':'16','197':'17','198':'18','199':'19'
} 
Array.prototype.e=function(){return(''+this)==='';}
String.prototype.s=function(){return this.split('').reverse();}
function B(a,b,c) {
var r='',s='';
a=a.s();
b=b.s();
while (!a.e()||!b.e()||c!=='0') {
x=a.e()?'0':a.shift();
y=b.e()?'0':b.shift();
s=A[c+x+y];
s=s.s();
r=s.shift()+r;
c=s.e()?'0':'1';
}
return r;
}
function m(a,b) {
var s='0',m='';
b.split('').reverse().forEach(function(e){
var z=m;
a.split('').reverse().forEach(function(f){s=B(s,M[e+f]+z,'0');z+='0';});
m+='0';
});
return s;
}

Разгулялся с тестами:

var mul = {
'00':'0','01':'0','02':'0','03':'0','04':'0','05':'0','06':'0','07':'0','08':'0','09':'0',
'10':'0','11':'1','12':'2','13':'3','14':'4','15':'5','16':'6','17':'7','18':'8','19':'9',
'20':'0','21':'2','22':'4','23':'6','24':'8','25':'10','26':'12','27':'14','28':'16','29':'18',
'30':'0','31':'3','32':'6','33':'9','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
'40':'0','41':'4','42':'8','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
'50':'0','51':'5','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
'60':'0','61':'6','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
'70':'0','71':'7','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
'80':'0','81':'8','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
'90':'0','91':'9','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81'
};

var adc = {
'000':'0','001':'1','002':'2','003':'3','004':'4','005':'5','006':'6','007':'7','008':'8','009':'9',
'010':'1','011':'2','012':'3','013':'4','014':'5','015':'6','016':'7','017':'8','018':'9','019':'10',
'020':'2','021':'3','022':'4','023':'5','024':'6','025':'7','026':'8','027':'9','028':'10','029':'11',
'030':'3','031':'4','032':'5','033':'6','034':'7','035':'8','036':'9','037':'10','038':'11','039':'12',
'040':'4','041':'5','042':'6','043':'7','044':'8','045':'9','046':'10','047':'11','048':'12','049':'13',
'050':'5','051':'6','052':'7','053':'8','054':'9','055':'10','056':'11','057':'12','058':'13','059':'14',
'060':'6','061':'7','062':'8','063':'9','064':'10','065':'11','066':'12','067':'13','068':'14','069':'15',
'070':'7','071':'8','072':'9','073':'10','074':'11','075':'12','076':'13','077':'14','078':'15','079':'16',
'080':'8','081':'9','082':'10','083':'11','084':'12','085':'13','086':'14','087':'15','088':'16','089':'17',
'090':'9','091':'10','092':'11','093':'12','094':'13','095':'14','096':'15','097':'16','098':'17','099':'18',
'100':'1','101':'2','102':'3','103':'4','104':'5','105':'6','106':'7','107':'8','108':'9','109':'10',
'110':'2','111':'3','112':'4','113':'5','114':'6','115':'7','116':'8','117':'9','118':'10','119':'11',
'120':'3','121':'4','122':'5','123':'6','124':'7','125':'8','126':'9','127':'10','128':'11','129':'12',
'130':'4','131':'5','132':'6','133':'7','134':'8','135':'9','136':'10','137':'11','138':'12','139':'13',
'140':'5','141':'6','142':'7','143':'8','144':'9','145':'10','146':'11','147':'12','148':'13','149':'14',
'150':'6','151':'7','152':'8','153':'9','154':'10','155':'11','156':'12','157':'13','158':'14','159':'15',
'160':'7','161':'8','162':'9','163':'10','164':'11','165':'12','166':'13','167':'14','168':'15','169':'16',
'170':'8','171':'9','172':'10','173':'11','174':'12','175':'13','176':'14','177':'15','178':'16','179':'17',
'180':'9','181':'10','182':'11','183':'12','184':'13','185':'14','186':'15','187':'16','188':'17','189':'18',
'190':'10','191':'11','192':'12','193':'13','194':'14','195':'15','196':'16','197':'17','198':'18','199':'19'
} 

Array.prototype.isEmpty = function() {
  return (''+this) === '';
}

function add(a, b, c) {
  var r = '', s = '';
  a = a.split("").reverse();
  b = b.split("").reverse();
  while (!a.isEmpty() || !b.isEmpty() || c !== '0') {
    x = a.isEmpty() ? '0' : a.shift();
    y = b.isEmpty() ? '0' : b.shift();
    s = adc[c + x + y];
    s = s.split("").reverse();
    r = (s.shift()) + r;
    c = (s.isEmpty()) ? '0' : '1';
  }
  return r;
}

function mult(a, b) {
  var s = '0';
  var m = '';
  b.split('').reverse().forEach(function(e) {
    var z = m;
    a.split('').reverse().forEach(function(f) {
      s = add(s, mul[e + f] + z, '0');
      z = z + '0';
    });
    m = m + '0';
  } );
  return s;
}

function test(a, b) {
  var t0 = (new Date()).getTime();
  var r = mult(a,b);
  var t1 = (new Date()).getTime();
  var e = t1 - t0;
  console.log('mult ' + a + ' * ' + b + ' = ' + r + " (" + e + " ms)");
}

test('12345', '42');
test('9999999999', '9999999999');

Это выводит:

mult 12345 * 42 = 518490 (3 ms) 
mult 9999999999 * 9999999999 = 99999999980000000001 (47 ms) 
Стивен Куан
источник
2

Haskell 507 496

Это работает для сколь угодно больших целых чисел. Я определяю пользовательские представления для натуральных чисел от 0 до 18 (самое большое натуральное число, равное сумме двух цифр), и определяю умножение с прямым порядком байтов в терминах умножения цифр * чисел, которое я определяю в терминах сложения числа + числа , который я определяю с точки зрения сложения цифра + цифра. У меня есть функция сокращения, которая расширяет 10-18 значений в их цифровое разложение. Затем он просто читает и переворачивает две строки, переводит в пользовательские привязки, умножает и переводит обратно, обращаясь, чтобы получить правильный результат.

Редактировать 2

Я сохранил несколько персонажей, создавая короткие локальные псевдонимы для команд несколько символов , которые я использую более чем один раз, а также удаление пробелов и скобок, а замена (- )пары с , $когда это возможно.

data S=Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R deriving(Enum, Ord, Eq)
p Z=id
p x=succ.p(pred x)
s Z=id
s x=pred.s(pred x)
z=s J
r[]=[]
r(x:y)|x<J=x:r y
r(x:[])=z x:[A]
r(x:y)=z x:(r$p A a:b)where(a:b)=r y
a x y=r$w(r x)(r y)
m Z _=[]
m _[]=[]
m x y=r$a y(m(pred x)y)
t[]_=[Z]
t _[]=[Z]
t(x:z)y=r$a(m x y)(Z:r(t z y))
i '0'=Z
i x=succ.i.pred$x
b Z='0'
b x=succ.b.pred$x
w[]y=y
w x[]=x
w(x:c)(y:d)=p x y:(w c d)
o=map
v=reverse
f=(o i).v
g=v.o b
main=getLine>>=putStrLn.(\[x,y]->g$t(f x)(f y)).words

Для справки: S - это пользовательский целочисленный тип данных, pэто «плюс» (сложение цифра + цифра), sвычитание (для уменьшения), rуменьшение (расширение в цифровую декомпозицию), aсложение (сложение числа + числа), mэто умножить (цифра * умножение числа), tэто времена (умножение числа * числа), iэто «интерпретировать» (преобразовать строку в список S), b«назад» (список из S в строку), а f и g - просто сокращения для игры в гольф цели. Я не использовал числа, даже неявно; самое близкое, что я получил, - это использование преемников и предшественников, которые являются математическими понятиями гораздо более высокого уровня, чем сложение и умножение натуральных чисел.

редактировать

Забыл включить профиль времени.

> time echo "9999999999 9999999999" | runhaskell multnonum.hs
99999999980000000001

real    0m0.246s
user    0m0.228s
sys     0m0.012s

Просто для хорошей меры:

> time echo "99999999980000000001 99999999980000000001" | runhaskell multnonum.hs
9999999996000000000599999999960000000001

real    0m0.244s
user    0m0.224s
sys     0m0.016s

Пойдем с ума!

> time echo "9999999996000000000599999999960000000001 9999999996000000000599999999960000000001" | runhaskell multnonum.hs
99999999920000000027999999994400000000699999999944000000002799999999920000000001

real    0m0.433s
user    0m0.424s
sys     0m0.004s

подтверждение

archaephyrryx
источник
1

Питон 2 - 1165, 712, 668, 664

I,T,V,N,X,J=raw_input,dict,reversed,None,zip,''.join
D='0123456789'
z,o='01'
A,B=I(),I()
r=i=""
K=map(J,X('666622222222911111551111555884444447773333333','678945672389954132987698765898967457989837654'))
P=T(X(K,map(J,X('344501110011800000440000332673322124652202211','628480244668154132507698505422648609367491852'))))
S=T(X(K,'cdef678945abi65243ed87a9cbaghcdab89egfcb6a987'))
for d in D:P[z+d]=z;S[z+d]=d
def Z(A,B,R=r):
 for a,b in V(map(N,V(z+A),V(z+B))):c=(a or z)+(b or z);s=S[min(c)+max(c)];R=Z(R,o)+T(X('abcdefghi',D))[s]if s>"?"else R+s
 return R
for a in V(A):
 j=""
 for b in V(B):r=Z(r,P[min(a+b)+max(a+b)]+i+j).lstrip(z);j+=z
 i+=z
print r if r else z

Обратите внимание, что я не использую подобное логическое индексирование Z = [X, Y][N == "0"], потому что это может быть интерпретировано как логическое приведение к числовому индексу.

Ungolfed:

A = raw_input()
B = raw_input()

P = {'00':'00','01':'00','02':'00','03':'00','04':'00','05':'00','06':'00','07':'00','08':'00','09':'00',
     '10':'00','11':'01','12':'02','13':'03','14':'04','15':'05','16':'06','17':'07','18':'08','19':'09',
     '20':'00','21':'02','22':'04','23':'06','24':'08','25':'10','26':'12','27':'14','28':'16','29':'18',
     '30':'00','31':'03','32':'06','33':'09','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
     '40':'00','41':'04','42':'08','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
     '50':'00','51':'05','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
     '60':'00','61':'06','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
     '70':'00','71':'07','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
     '80':'00','81':'08','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
     '90':'00','91':'09','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81',
     }
S = {'00':'0','01':'1','02':'2','03':'3','04':'4','05':'5','06':'6','07':'7','08':'8','09':'9',
     '10':'1','11':'2','12':'3','13':'4','14':'5','15':'6','16':'7','17':'8','18':'9','19':'a',
     '20':'2','21':'3','22':'4','23':'5','24':'6','25':'7','26':'8','27':'9','28':'a','29':'b',
     '30':'3','31':'4','32':'5','33':'6','34':'7','35':'8','36':'9','37':'a','38':'b','39':'c',
     '40':'4','41':'5','42':'6','43':'7','44':'8','45':'9','46':'a','47':'b','48':'c','49':'d',
     '50':'5','51':'6','52':'7','53':'8','54':'9','55':'a','56':'b','57':'c','58':'d','59':'e',
     '60':'6','61':'7','62':'8','63':'9','64':'a','65':'b','66':'c','67':'d','68':'e','69':'f',
     '70':'7','71':'8','72':'9','73':'a','74':'b','75':'c','76':'d','77':'e','78':'f','79':'g',
     '80':'8','81':'9','82':'a','83':'b','84':'c','85':'d','86':'e','87':'f','88':'g','89':'h',
     '90':'9','91':'a','92':'b','93':'c','94':'d','95':'e','96':'f','97':'g','98':'h','99':'i',
     }
L = {'a':'0','b':'1','c':'2','d':'3','e':'4','f':'5','g':'6','h':'7','i':'8'}

def strSum(A, B):
    R = ""
    for a, b in reversed(map(None, reversed("0" + A), reversed("0" + B))):
        if a == None: a = '0'
        if b == None: b = '0'
        s = S[a + b]
        if s.isdigit():
            R += s
        else:
            R = strSum(R, "1") + L[s]
    return R

i = ""
r = "0"
for a in reversed(A):
    j = ""
    for b in reversed(B):
        p = P[a + b] + i + j
        r = strSum(r, p)
        j += "0"
    i += "0"

r = r.lstrip("0")
if r == "":
    r = "0"

print r
Фалько
источник
Я бы сказал, что нельзя использовать функции min () и max (), потому что они сравнивают реальные целочисленные значения, не так ли?
WorldSEnder
@WorldSEnder: я бы сказал, что они сравнивают персонажей, что разрешено в этом испытании. («Лексикографическое сравнение символов допускается.»)
Фалько
1

Скала, 470 символов

( это стандартное scala, но его можно эквивалентно заменить на =>подсчет байтов)

def p(a: String,b: String)={type D=List[Char]
val d="0123456789".toList
def v(s: String)=s.toList.map{c⇒d.takeWhile(c.!=)}
def u(l:D, a:D):(Char,D)=l match {
case _::_::_::_::_::_::_::_::_::_::m⇒u(m,'a'::a)
case _⇒(('a'::l).zip(d).last._2,a)}
val o=(("", List[Char]())/:v(a).tails.toList.init.map{l⇒(v(b) map {_.flatMap(_⇒l.head)})++l.tail.map(_⇒Nil) reverse}.reduce(_.zipAll(_, Nil, Nil).map{t⇒t._1++t._2}))({(t,e)⇒val s=u(t._2++e,Nil);(s._1+t._1,s._2)})
u(o._2, Nil)._1+o._1}

Здесь мы эмулируем цифры, используя длину списков, стараясь не использовать никаких числовых операций - только сгибы, карты, почтовые индексы и тому подобное. Число - это список этих цифр (стратегически обратный порядок в середине вычисления); мы умножаем отдельные цифры на flatMapи наши строки вверх reduce. uобрабатывает вычисление переноса (путем непосредственного сопоставления со списком из> 10 элементов и повторения) и преобразования цифр обратно в символы, и мы используем a, /:чтобы пройти через этот стек. Требуемый пример завершается менее чем за секунду.

LMM
источник