Nhân hai số mà không sử dụng bất kỳ số nào


30

Bạn được cung cấp dưới dạng hai chuỗi đầu vào biểu thị các số nguyên dương trong cơ sở 10, chẳng hạn như "12345""42". Nhiệm vụ của bạn là xuất ra một chuỗi chứa sản phẩm của họ, "518490"trong trường hợp này.

Vấn đề là bạn không được sử dụng bất kỳ loại số nào trong mã của mình. Không ints, floats, unsigned longs, v.v., không có loại số phức tích hợp hoặc số nguyên chính xác tùy ý hoặc bất cứ thứ gì dọc theo các dòng đó. Bạn không sử dụng nghĩa đen của các loại đó, cũng như bất kỳ chức năng, phương thức, toán tử, vv mà trả về chúng.

Bạn có thể sử dụng chuỗi, booleans, mảng hoặc bất kỳ thứ gì khác thường không được sử dụng để đại diện cho một số. (Nhưng lưu ý rằng không thể lập chỉ mục vào một mảng và không có độ dài của nó mà không thể gọi một kiểu số.) char, Nhưng bạn không được thực hiện bất kỳ thao tác số học hoặc bitwise nào trên chúng hoặc nếu không thì coi chúng là bất kỳ hoạt động nào khác ngoài mã thông báo đại diện cho một phần của chuỗi. ( charCho phép so sánh từ điển của s.)

Bạn có thể không làm việc xung quanh các hạn chế. Điều này bao gồm (nhưng không giới hạn) sử dụng các loại số bên trong evalhàm loại, chuyển đổi loại ngầm thành loại số, sử dụng toán tử số hoặc bit trên các loại không hỗ trợ chúng, sử dụng loại số được lưu trữ bên trong các loại bộ chứa hoặc hàm gọi hoặc các chương trình bên ngoài trả về kết quả số ở dạng chuỗi. (Tôi bảo lưu quyền thêm vào danh sách này nếu các cách giải quyết khác xuất hiện trong câu trả lời.) Bạn phải tự thực hiện phép nhân bằng cách chỉ sử dụng các loại không phải là số.

Đầu vào và đầu ra có thể bằng bất kỳ phương thức thuận tiện nào, miễn là dữ liệu nhập và thoát mã của bạn dưới dạng một chuỗi. Bạn có thể giả sử mỗi một trong hai đối số đầu vào chỉ chứa các ký tự ASCII [0-9]và sẽ không bắt đầu bằng 0. Đầu ra của bạn không nên có số 0 hàng đầu.

Một điều nữa: mã của bạn phải xử lý chính xác các đầu vào có độ dài tối thiểu 10 ký tựphải chạy dưới một phút trên một máy tính hiện đại cho tất cả các đầu vào trong phạm vi đó. Trước khi đăng, vui lòng kiểm tra xem khi đưa ra đầu vào 99999999999999999999, chương trình của bạn cung cấp đầu ra 99999999980000000001trong chưa đầy một phút. Hạn chế này tồn tại đặc biệt để ngăn chặn các câu trả lời hoạt động bằng cách phân bổ một mảng kích thước a*bvà sau đó lặp lại trên đó, vì vậy hãy nhớ rằng các câu trả lời của hình thức đó sẽ không đủ điều kiện để giành chiến thắng.

Đây là , vì vậy giải pháp hợp lệ ngắn nhất (tính bằng byte) sẽ thắng.


Chúng ta có thể chấp nhận "12345"từ STDIN hơn 12345không? Hoặc chúng ta có thể chấp nhận cả hai số là "12345", "42"?
Justin

Suy nghĩ đầu tiên của tôi là viết một hàm lấy đối số chuỗi có độ dài mnvà trả lại một đối số của chiều dài m*n. Nhưng vì các chuỗi phải chứa đại diện ASCII của các con số, tôi đoán điều đó trái với quy tắc.
Cấp sông St

1
@xnor trong nhiều ngôn ngữ có thể ngắn hơn để viết ra tất cả các trường hợp. Nhưng tôi đã tìm thấy cách này trong Python:a,b="0123456789x".split('0');c=iter(b).next() if c=='x': c='0'
Nathaniel

1
hoặc trong Python 3,a,b="0123456789x".split(x);c,*d=b if c=='x': c='0'
Nathaniel

2
@Nathanield='123456789';I=dict(zip('0'+d,d+'0'))
Justin

Câu trả lời:


6

Haskell - 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

Triển khai phép nhân thông qua phép cộng lặp lại và tất cả các loại phép thuật số được xử lý bằng cách dịch chuyển và lọc ['0'..'9']danh sách. Xác định một toán tử #loại String -> String -> String:

*> :set +s
*> "9990123456789"#"9999876543210"
"99900001219316321126352690"
(0.02 secs, 9862288 bytes)

Hình như chúng ta có một người chiến thắng mới! (Mặc dù như trước đây, tôi không thể đọc Haskell về mức độ tinh vi này - ai đó có thể kiểm tra độc lập nó có đáp ứng thông số kỹ thuật không?)
Nathaniel

(Ngoài ra, ['0' .. '9'] có cảm giác hơi giống với việc coi các ký tự là số có thể lặp lại - có cách nào ngắn để tạo danh sách đó từ chuỗi "0123456789" không?)
Nathaniel

@Nathaniel Vâng, trước hết chuỗi "0123456789" danh sách ['0'..'9']. Thứ hai, trong Haskell [a..b] là một phép liệt kê, các kiểu đã khai báo các thể hiện của kiểu chữ Enumcó thể được liệt kê như thế và khai báo mô tả cách thức liệt kê hoạt động. Bool, kiểu boolean cũng có một thể hiện, và do đó bạn cũng có thể làm được [False..True]. Hầu như không có con số nào liên quan.
mniip

14

sed, 339 339 byte

Tôi biết đây là một cái cũ, nhưng tôi đã duyệt và điều này khơi gợi sự quan tâm của tôi. Đủ để thực sự đăng ký như một người dùng! Tôi đoán rằng tôi đã bị ảnh hưởng bởi " Tôi rất muốn thấy một giải pháp sed đầy đủ - Nathaniel " ...

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

Tập lệnh sed này dự kiến ​​hai số thập phân là đầu vào, cách nhau bởi một khoảng trắng

kiểm tra:

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

Bạn có thể nhận ra hai cuối cùng là RSA-100 (50 x 50 chữ số) và RSA-768 (116 x 116 chữ số).

Sử dụng GNU sed trên một Intel Core 2 không phải là rất hiện đại (thời kỳ 2007), cái cuối cùng trong số đó mất hơn một phút, nhưng nó nhanh hơn trên bộ xử lý mới hơn:

  • Q6600:> 1 phút
  • i7-3770: 26 giây
  • i7-6700: 22 giây

Phép nhân 10 chữ số được chỉ định trong câu hỏi diễn ra tốt trong một giây đối với bất kỳ trong số này (mặc dù có đầy đủ các số liệu bệnh lý).

Tôi tin rằng đó là sed tiêu chuẩn, không có phần mở rộng. POSIX đảm bảo chỉ giữ không gian 8192 byte, điều này giới hạn chúng tôi nhân số 400x400 chữ số, nhưng việc triển khai có thể cung cấp nhiều hơn. GNU sed chỉ bị giới hạn bởi bộ nhớ khả dụng, vì vậy có thể quản lý thứ gì đó lớn hơn nhiều, nếu bạn sẵn sàng chờ đợi.

Và tôi tự tin rằng tôi đã tuân thủ các quy tắc - đó gần như là một ngôn ngữ không có số. :-)

Giải trình

Tôi sử dụng phép lai unary / binary, chuyển đổi số thập phân thành một chuỗi unary:

 42 => _xxxx_xx

Trong thập phân unary, bổ sung là dễ dàng. Chúng tôi lặp lại từ chữ số có nghĩa nhỏ nhất đến chữ số có ý nghĩa nhất, nối các chữ x:

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

Sau đó, chúng tôi xóa khoảng trắng và xử lý thực hiện bằng cách chuyển đổi 10 x x liên tiếp sang một trong các đơn vị tiếp theo:

 _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx       10.6.11
 _xxxxxxxxxx_xxxxxxx_x                10.7.1
 _x__xxxxxxx_x                        1.0.7.1 

Một khi chúng ta có phép cộng, phép nhân là có thể. Chúng tôi nhân x * y bằng cách xem xét chữ số cuối cùng của y. Thêm x vào bộ tích lũy nhiều lần, sau đó di chuyển đến chữ số tiếp theo và dịch chuyển x một vị trí thập phân sang trái. Lặp lại cho đến khi y bằng không.

Mã mở rộng

#!/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
Câu trả lời rất thỏa mãn, cảm ơn bạn!
Nathaniel

9

sed, 379 byte

Tín dụng cho câu trả lời tuyệt vời này được gửi tới @LuigiTiburzi trên Unix & Linux.SE: https://unix.stackexchange.com/a/37213/34061 . Tôi chỉ tình cờ vấp phải điều này vài ngày trước:

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

Giải thích rộng

  • Tách từng chữ số. Do đó 12*3trở thành<1<2*<3
  • Chuyển đổi từng chữ số thành số |ký tự đó. Do đó <1<2*<3trở thành<|<||*<|||
  • Thay thế |<liên <||||||||||tục để thay đổi vị trí thập phân cao hơn xuống vị trí đơn vị. Do đó <|<||*<|||trở thành<||||||||||||*<|||
  • Loại bỏ <. Do đó <||||||||||||*<|||trở thành||||||||||||*|||
  • Xóa 1 |khỏi RHS của *. Do đó ||||||||||||*|||trở thành||||||||||||*||
  • Liên tục thay thế từng cái |trên RHS bằng tất cả |trên LHS. Điều này có ảnh hưởng của nhân số LHS và RHS của |để cung cấp cho số lượng sản phẩm của | Như vậy ||||||||||||*||trở thành||||||||||||||||||||||||||||||||||||*
  • Loại bỏ *. Do đó ||||||||||||||||||||||||||||||||||||*trở thành||||||||||||||||||||||||||||||||||||
  • chuyển đổi số |trở lại thành số thập phân bằng cách đảo ngược của một vài bước đầu tiên. Do đó ||||||||||||||||||||||||||||||||||||trở thành 36.

Đầu ra:

$ 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
$

Thật không may, nó thất bại thảm hại về yêu cầu thời gian - 200*1000mất 41 giây trên máy ảo Ubuntu của tôi và thời gian chạy dường như đi lên với bình phương của sản phẩm cuối cùng.


1
Điều này gần như tương đương về mặt thuật toán với câu trả lời JS đã bị xóa của tôi ngoại trừ việc chuyển đổi trở lại thành phần số.
Tối ưu hóa

@Optimizer Đồng ý. Sự khác biệt là việc bạn sử dụng length()sẽ trả về một số. Cái này sử dụng thay thế regex hoàn toàn không có kiểu số. Tôi nghĩ rằng câu trả lời của bạn có khả năng là một người chiến thắng mặc dù nếu bạn có thể loại bỏ length()- có lẽ bạn có thể thực hiện một số thay thế regex tương tự?
Chấn thương kỹ thuật số

1
Rất hay, nhưng hạn chế trong một phút đặc biệt có nghĩa là ngăn chặn các giải pháp hoạt động bằng cách đếm đến câu trả lời. Tôi khá muốn xem một giải pháp sed đầy đủ mặc dù.
Nathaniel

1
Tôi có một câu trả lời hoạt động với số lượng lớn (ví dụ lớn hơn không gian địa chỉ của hệ thống).
Toby Speight

@TobySpeight vâng, rất tốt. Tôi nghĩ rằng tôi chắc chắn đã nâng cấp bạn trở lại :)
Chấn thương kỹ thuật số

9

Con trăn - 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")

Nếu (rất nhiều) số 0 đứng đầu được cho phép, 12 ký tự cuối cùng là không cần thiết.

Điều này về cơ bản thực hiện phép nhân tiêu chuẩn bằng tay. Các chữ số được biểu diễn dưới dạng các chuỗi lặp lạiI s (như các chữ số La Mã nguyên thủy). Các số được biểu diễn dưới dạng danh sách các chữ số theo thứ tự ngược lại. Việc thêm các chữ số đơn được thực hiện bằng cách ghép các chuỗi và loại bỏ mười Igiây nếu cần thiết.

Đây là một phiên bản chưa được chỉnh sửa:

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())

1
Đây là yêu thuật gì! Làm thế nào nó hoạt động! Ồ Ngoài ra, đây là một sân golf khác bạn có thể làm: def A(x,y):\n S=[];o=""-> def A(x,y,S=[],o=""):. Ngoài ra, thật không may, ["","1"][t in i]không được phép; nó đang sử dụng một bool để lập chỉ mục, coi nó như một con số. Tôi nghĩ rằng t in i and"1"or""nên làm việc, mặc dù.
Justin

@Quincunx: Xác định Slàm đối số với mặc định sẽ không hoạt động, vì nó sẽ luôn là cùng một danh sách ngay cả đối với các lệnh gọi khác nhau của hàm và do đó không được đặt lại []. Bạn đã đúng về ["","1"][t in i], tôi đã sửa nó. Tôi cũng đã thêm một lời giải thích.
Wrzlprmft

Điều này là khá tuyệt vời. Nó được đánh dấu màu xanh bây giờ. (Tôi đã chỉnh sửa câu hỏi để làm rõ rằng các số 0 đứng đầu trong đầu ra không được phép - xin lỗi!)
Nathaniel

7

Hồng ngọc: 752 698

Đây chỉ là để có được một câu trả lời ngoài kia, chỉ cần thực hiện vì tò mò. Chỉnh sửa: bây giờ chơi golf một chút.

$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)

Cách sử dụng: Tôi đã có cái này trong một tệp có tên peasant.rb:

$ time ruby peasant.rb 9999999999 9999999999
99999999980000000001

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

Giải thích: đó là phép nhân nông dân, vì vậy tôi liên tục giảm một nửa và gấp đôi. Giảm một nửa được thực hiện bằng cách giảm một nửa chữ số và đánh dấu phần còn lại như vậy: 1234 -> 0b1a1b2a; sau đó tìm và thay thế trên b's: 06a17a; sau đó dọn dẹp -> 617.

Việc thêm được thực hiện như vậy ... trước hết, tôi đệm cả hai chuỗi có cùng độ dài và tạo các cặp từ các chữ số. Sau đó, tôi thêm các chữ số bằng cách xây dựng một chuỗi có độ dài của mỗi chữ số và nối; Tôi xóa một chuỗi có độ dài đó từ đầu '0123456789abcdefghij', và sau đó giữ char đầu tiên. Vì vậy, ví dụ: "9" + "9" -> "i". NB Tôi thực sự tránh sử dụng các hàm độ dài ở đây để tránh các loại số hoàn toàn; thay vào đó, việc loại bỏ tiền tố được thực hiện bằng biểu thức chính quy.

Vì vậy, bây giờ tôi có một chuỗi chứa hỗn hợp các chữ số và chữ cái. Các chữ cái đại diện cho số với một chữ số mang; Tôi thêm 0 vào số, sau đó liên tục thay thế các mẫu chữ số bằng kết quả của việc mang cho đến khi bổ sung hoàn tất.


1
Câu trả lời rất thông minh, chính xác là thứ mà tôi đã hy vọng nhìn thấy!
Nathaniel

1
Tôi thực sự hy vọng ai đó sẽ đăng một bài với các chữ số của Giáo hội!
bazzargh

Điều đó thật tuyệt, mặc dù tôi không chắc liệu nó có hoạt động với yêu cầu hiệu quả hay không - Tôi nghĩ rằng việc chuyển đổi giữa các chuỗi và số của Giáo hội sẽ có hiệu quả liên quan đến việc đếm tới 99999999980000000001.
Nathaniel

7

Brainfuck (1328 byte)

Cân nhắc lúc đầu:

  • Không chắc chắn liệu brainfuck có phải là câu trả lời hợp lệ cho câu hỏi này hay không vì tôi không chắc liệu bạn có xem các giá trị ô là "loại số" hay không. Tôi không nghĩ như vậy vì bf không biết các loại, nhưng đó là ý kiến ​​của riêng tôi, xin vui lòng sửa cho tôi nếu tôi sai.
  • Một triển khai hỗ trợ (gần) không giới hạn giá trị là cần thiết.
  • Nó có thể là quá chậm, dựa trên việc thực hiện.

Tôi chỉ thử nghiệm chương trình với thông dịch viên của riêng tôi, bạn có thể tìm thấy nó ở đây .

Đầu vào phải là cả hai số cách nhau bởi một không gian ASCII.

Chơi gôn

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

Ung dung:

,
>++++++[<----->-]<--
[                                           # 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
[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Tôi đã lấy mã cho đầu ra của giá trị từ câu trả lời này , cảm ơn tác giả cho điều đó!

Chương trình có thể không hợp lệ, nhưng bằng bất cứ cách nào tôi cũng muốn chia sẻ nó với bạn ^^

Update: You can now test it (only for small multiplications) here, thanks to @Sp3000's answer to this contest and SE's new Stack Snippets!

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>


I don't know if it's valid either! I guess either everything's a number in Brainfuck, or nothing is.
Nathaniel

Tôi thích câu trả lời này. Gần đây tôi đã làm phiền với bf. nó làm sáng tỏ sự thật rằng ở cấp độ máy, mọi thứ chỉ là mã thông báo. Khó có thể nói liệu điều này có thực sự tuân theo các quy tắc hay không.
Bạch tuộc

6

Python, 394 349 340 ký tự

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

Chạy như sau:

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

Mất 50 mili giây.

Sử dụng phép nhân nông dân Nga . Khi thêm chữ số, chúng tôi chuyển đổi chúng thành unary ('5' => [R, R, R, R, R]), nối các danh sách, sau đó chuyển đổi lại. Uchuyển đổi thành unary, sử dụng Rnhư là chữ số unary. Chúng tôi tính toán b/=2như b=b*5/10.


A couple golfs: def A(a,b):\n r='';c=[] -> def A(a,b,r='',c=[]):, similarly for def M. You might be able to change for z in D:d.pop()\n c=['X'] to [d.pop()for z in D];c=['X'], in which case you could even collapse it onto the previous if. Also, can if list(b).pop()in'13579' just be if b[:].pop()in'13579'?
Justin

@Quincunx: Thanks. The last one won't work because on the first iteration b is a string, not a list.
Keith Randall

You could skip M and write a complete program; a,b=input() is allowed.
Justin

1
b*5/10 is a nice trick.
bazzargh

I just stumbled upon reduce, which allows you to nicen A(b,A(b,A(b,A(b,b)))) to reduce(A,[b,b,b,b,b]). Sadly, this does not affect the character count.
Wrzlprmft

5

JavaScript (E6) 375 395 411 449

Edit Golfed
Edit Bug fixed: missing clearing a carry flag

It can be done with just symbol manipulation in near 0 time.
In this version you could use any char instead of the digits, as long as the symbol are in ascending order.

Notes: using strings, hashmap with string key, arrays used as list. No indexing, the arrays are traversed using 'map' or rotated using push & shift.
All '+' are string concatenation.

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)

Less Golfed (maybe I'll add an explanation tomorrow)

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('')
)

Test In FireFox/FireBug console

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

Output

Result 99999999980000000001 time ms 14

Possibly there's a slight bug - the output from the 9999999999 case should be 99999999980000000001, not 99999999980000000081
Nathaniel

:( going to check
edc65

If you're using multiplication tables, how are you getting around the fact that summation isn't allowed?
COTO

1
Summation IS allowed using a hashtable (s in the code). Ex. s['34'] --> '7'. Just symbols, not numbers. Could be s['cd'] -->'g'
edc65

5

Haskell, 231 bytes

This defines an operator # which multiplies two string representations of natural numbers. It works by defining an elementary increment/decrement operation on strings, then uses it to build up addition and multiplication. A little extra magic gives some exponential speedups that make it all possible..

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

This approach is fast enough that even on a 2008 laptop in the unoptimized ghci REPL, the test case takes just a fraction of a second:

λ> :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)

Here's a check that all of the two-digit products are correct:

λ> and [ show (x * y) == (show x # show y) | x <- [0..100], y <- [0..100] ]
True

Looks like we have a new leader! (I can't read Haskell though - can someone independently confirm that it fits the spec?)
Nathaniel

1
Yes, that's perfectly cromulent haskell, it fits the spec, and works as advertised. Good job!
bazzargh

4

Bash + ImageMagick: 52

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

Expects the input to be in the shell variables a and b. It's not particularly clever or efficient, but it gets the job done. It's probably been done before.

Note that the x denotes the image's dimensions; it is not an arithmetic operator in this context.

I haven't tested this, but I'm willing to assume that for non-extreme input, it will complete in under one minute. I can test it tomorrow.

In case there's any funny business with ImageMagick versions, this is the one I'm using: ImageMagick 6.7.7-10


Nice try, but I'm certain this won't work in under a minute (or indeed at all on any existing machine) for inputs 9999999999 and 9999999999.
Nathaniel

4
This also works: dd if=/dev/zero bs=$a count=$b 2>&-|wc -c.
jimmy23013

1
A 9999999999x9999999999 image in 8bit format will take up all the hard drive space that currently exists on Earth. Of course, a png would be a lot smaller, if you can create it without first creating the raw image. (Though I strongly suspect you would have integer overflow issues with an image that size.) But still, such a method would almost certainly fall foul of the calling-things-that-return-numerical-results-as-strings loophole.
Nathaniel

1
You can save 2 bytes by using $b instead of ${b}.
nyuszika7h

1
Also, you can save 5 bytes by using grep -vc g instead of grep -v g|wc -l.
nyuszika7h

2

Python 2 (proof of concept)

This solution works using strings and lists only, and a little regex. I believe it fits the spec entirely, except that there's no way it can do 9999999999x9999999999 in a minute. Though given enough time it would work. It can multiply 4 digit numbers pretty quickly.

Since it is technically invalid I've not yet bothered to completely golf it. I will do so if the rules change.

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)))

Examples:

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

multiply('1869','1243') #returns the string 2323167

1
+1 because it does meet the spec (apart from the efficiency requirement) as far as I can tell
Nathaniel

2

Python 2 (555)

I wouldn't normally answer my own challenge so quickly (or at all), but I wanted to prove it could be done. (Luckily some other answers did that before this one, but I couldn't help wanting to finish it.) There's some more golfing that could be done, but I think this is reasonable. It handles the 9999999999x9999999999 case in under 0.03s on my machine.

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))))

Example use: m("12345","42")

It works by doing long multiplication using string manipulations. Sometimes the variables are strings and sometimes they're iterators over strings, which makes it possible to get the first element without using an integer literal. Everything's stored with the digits reversed, so that the first element is the least significant digit.

Here's a function-by-function explanation:

  • r and s are bookkeeping functions. (r is just an alias for reversed, which makes a reverse iterator, and s converts iterators into strings.)

  • i increments the number in a string by 1, including cases like 39+1=40 and 99+1=100.

  • b adds x and y, but y must be only one digit. It works by incrementing x y times.

  • a adds two numbers together that can both have multiple digits, by calling b for each digit in y.

  • n multiplies x and y, but y must be only one digit. It works by adding x to itself y times.

  • o multiplies x and y, where both arguments can have multiple digits. It uses classic long-multiplication

  • m just converts its string inputs into reverse iterators and hands them to o, then reverses the result and converts it into a string.


Couple golfs: def a(x,y): -> def a(x,y,z=''): and remove next line; similar tricks for other functions, in def o(x,y):, change the x=s(x) to x=s(x);l='';z='', in that for loop, similarly remove newline + paces; instead use ;. Also, I think the if h!='0':h+=s(x)\nelse:h+=i(x) can simply be h+=h!='0'and i(x)or s(x); maybe even h+=(h!='0'and i or s)(x); otherwise, simply change to if'0'!=h. Also things like def r(x):return reversed(x) -> r=reversed
Justin

Also, I forgot to mention for s, m: s=lambda x:''.join(x), m=lambda x,y:s(r(o(r(x),r(y)))) instead of the entire function declaration. With just the things that I know work, this brings your byte-count down to 521.
Justin

Oh, and one more: for your for loops: 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), although this could significantly change the speed of your program.
Justin

@Quincunx thanks! I can see another few improvements as well this morning. (Mostly nesting the loops instead of defining functions.) I'll make these changes if some more competitive answers appear, which seems likely - currently they would put me in the lead, which seems a bit unfair since it was my question and I've had longer to think about it.
Nathaniel

2

JavaScript: 3710 3604 bytes

  • Using string lookup tables with 1 digit multiplication and add with carry.
  • The multiplication is done by digit x digit instead of digit x line.

Golf:

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;
}

Ungolfed with tests:

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');

This outputs:

mult 12345 * 42 = 518490 (3 ms) 
mult 9999999999 * 9999999999 = 99999999980000000001 (47 ms) 

2

Haskell 507 496

This works for arbitrarily large integers. I define custom representations for the natural numbers from 0 to 18 (the largest natural number equal to the sum of two digits), and define little-endian multiplication in terms of digit*number multiplication, which I define in terms of number+number addition, which I define in terms of digit+digit addition. I have a reduction function that expands 10--18 values into their digital decomposition. This then just reads and reverses the two strings, translates to the custom bindings, multiplies, and translates back, reversing to get the right result.

Edit 2

I saved a few characters by creating short local aliases for multi-character commands I use more than once, as well as removing spaces and parentheses, and by replacing (-) pairs with $ when possible.

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

For reference, S is the custom integer-like data type, p is 'plus' (digit+digit addition), s is subtract (for reduction), r is reduce (expand into digital decomposition), a is addition (number+number addition), m is multiply (digit*number multiplication), t is times (number*number multiplication), i is 'interpret' (convert string to list of S), b is 'back' (list of S to string), and f and g are just shortenings for golfing purposes. I didn't use numbers, even implicitly; the closest I got was using successors and predecessors, which are much higher level mathematical concepts than addition and multiplication of natural numbers.

Edit

Forgot to include the time profile.

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

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

Just for good measure:

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

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

Let's go insane!

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

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

confirmation


1

Python 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

Note that I'm not using logical indexing like Z = [X, Y][N == "0"], because this could be interpreted as a boolean casted to a numeric index.

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

I would say that using min() and max() functions shouldn't be allowed because those are comparing actual integer values, aren't they?
WorldSEnder

@WorldSEnder: I'd say they compare characters, which is allowed in this challenge. ("Lexicographical comparison of chars is allowed.")
Falko

1

Scala, 470 characters

(the are standard scala but can equivalently be replaced with => if we're counting bytes)

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}

Here we're emulating digits using the length of lists, being careful not to use any numeric operations - only folds, maps, zips and the like. A number is a list of these digits (order strategically reversed halfway through the computation); we multiply individual digits with flatMap and our rows up with reduce. u handles figuring out the carry (by directly matching against a list of >10 elements, and recursing) and converting digits back to characters, and we use a /: to work our way through the stack with that. The required example completes in less than a second.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.