June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View file

@ -0,0 +1,88 @@
identification division.
program-id. long-mul.
data division.
replace ==ij-lim== by ==7== ==ir-lim== by ==14==.
working-storage section.
1 input-string pic x(26) value "18,446,744,073,709,551,616".
1 a-table.
2 a pic 999 occurs ij-lim.
1 b-table.
2 b pic 999 occurs ij-lim.
1 ir-table value all "0".
2 occurs ij-lim.
3 ir pic 999 occurs ir-lim.
1 s-table value all "0".
2 s pic 999 occurs ir-lim.
1 display.
2 temp-result pic 9(6) value 0.
2 carry pic 999 value 0.
2 remain pic 999 value 0.
1 binary.
2 i pic 9(4) value 0.
2 j pic 9(4) value 0.
2 k pic 9(4) value 0.
procedure division.
begin.
move 1 to j
perform varying i from 1 by 1 until i > ij-lim
unstring input-string delimited ","
into a (i) with pointer j
end-perform
move a-table to b-table
perform intermediate-calc
perform sum-ir
perform display-result
stop run
.
intermediate-calc.
perform varying i from ij-lim by -1 until i < 1
move 0 to carry
perform varying j from ij-lim by -1 until j < 1
compute temp-result = a (i) * b (j) + carry
divide temp-result by 1000 giving carry
remainder remain
compute k = i + j
move remain to ir (i k)
end-perform
subtract 1 from k
move carry to ir (i k)
end-perform
.
sum-ir.
move 0 to carry
perform varying k from ir-lim by -1 until k < 1
move carry to temp-result
perform varying i from ij-lim by -1 until i < 1
compute temp-result = temp-result + ir (i k)
end-perform
divide temp-result by 1000 giving carry
remainder remain
move remain to s (k)
end-perform
.
display-result.
display " " input-string
display " * " input-string
display " = " with no advancing
perform varying k from 1 by 1
until k > ir-lim or s (k) not = 0
end-perform
if s (k) < 100
move 1 to i
inspect s (k) tallying i for leading "0"
display s (k) (i:) "," with no advancing
add 1 to k
end-if
perform varying k from k by 1 until k > ir-lim
display s (k) with no advancing
if k < ir-lim
display "," with no advancing
end-if
end-perform
display space
.
end program long-mul.

View file

@ -0,0 +1,58 @@
"run() is the main function of this module."
shared void run() {
function multiply(String|Integer|Integer[] top, String|Integer|Integer[] bottom, Integer base = 10) {
function fromString(String s) =>
s
.filter(not(','.equals))
.map((char) => Integer.parse(char.string))
.narrow<Integer>()
.sequence()
.reversed;
function toString(Integer[] ints) =>
""
.join(ints.interpose(',', 3))
.reversed
.trimLeading((char) => char in "0,");
function fromInteger(Integer int) => fromString(int.string);
function convertArg(String|Integer|Integer[] arg) =>
switch(arg)
case (is String) fromString(arg)
case (is Integer) fromInteger(arg)
case (is Integer[]) arg;
value a = convertArg(top);
value b = convertArg(bottom);
value p = a.size;
value q = b.size;
value product = Array.ofSize(p + q, 0);
for (bIndex->bDigit in b.indexed) {
variable value carry = 0;
for (aIndex->aDigit in a.indexed) {
assert (exists prodDigit = product[aIndex + bIndex]);
value temp = prodDigit + carry + aDigit * bDigit;
carry = temp / base;
product[aIndex + bIndex] = temp % base;
}
assert (exists lastDigit = product[bIndex + p]);
product[bIndex + p] = lastDigit + carry;
}
return toString(product.sequence());
}
value twoToThe64th = "18,446,744,073,709,551,616";
value expectedResult = "340,282,366,920,938,463,463,374,607,431,768,211,456";
value result = multiply(twoToThe64th, twoToThe64th);
print("The expected result is ``expectedResult``");
print("The actual result is ``result``");
print("Do they match? ``expectedResult == result then "Yes!" else "No!"``");
}

View file

@ -20,7 +20,7 @@
significant digit first. The digits returned by
long-add do have the most significant bit first."
(if (every 'endp digitses)
(nconc (digits carry) sum)
(nconc (number->digits carry) sum)
(let ((column-sum (reduce '+ (mapcar #'first-digit digitses)
:initial-value carry)))
(multiple-value-bind (carry column-digit)
@ -30,8 +30,8 @@
;; get the digits of a and b (least significant bit first), and
;; compute the zero padded rows. Then, add these rows (using
;; long-add) and convert the digits back to a number.
(do ((a (nreverse (digits a)))
(b (nreverse (digits b)))
(do ((a (nreverse (number->digits a)))
(b (nreverse (number->digits b)))
(prefix '() (list* 0 prefix))
(rows '()))
((endp b) (digits->number (long-add rows)))

View file

@ -11,7 +11,7 @@ function mult(strNum1,strNum2){
if ( aResult[idxIter] > 9 ) { // Carrying
aResult[idxIter + 1] = Math.floor( aResult[idxIter] / 10 ) + ( idxIter + 1 >= aResult.length ? 0 : aResult[idxIter + 1] );
aResult[idxIter] -= Math.floor( aResult[idxIter] / 10 ) * 10;
aResult[idxIter] %= 10;
}
}
}

View file

@ -0,0 +1,45 @@
module LongMultiplication
using Compat
function addwithcarry!(r, addend, addendpos)
while true
pad = max(0, addendpos - lastindex(r))
append!(r, fill(0, pad))
addendrst = addend + r[addendpos]
addend, r[addendpos] = divrem(addendrst, 10)
iszero(addend) && break
addendpos += 1
end
return r
end
function longmult(mult1::AbstractVector{T}, mult2::AbstractVector{T}) where T <: Integer
r = T[]
for (offset1, digit1) in enumerate(mult1), (offset2, digit2) in zip(eachindex(mult2) + offset1 - 1, mult2)
single_multrst = digits(digit1 * digit2)
for (addoffset, rstdigit) in zip(eachindex(single_multrst) + offset2 - 1, single_multrst)
addwithcarry!(r, rstdigit, addoffset)
end
end
return r
end
function longmult(a::T, b::T)::T where T <: Integer
mult1 = digits(a)
mult2 = digits(b)
r = longmult(mult1, mult2)
return sum(d * T(10) ^ (e - 1) for (e, d) in enumerate(r))
end
function longmult(a::AbstractString, b::AbstractString)
if !ismatch(r"^\d+", a) || !ismatch(r"^\d+", b)
throw(ArgumentError("string must contain only digits"))
end
mult1 = reverse(collect(Char, a) .- '0')
mult2 = reverse(collect(Char, b) .- '0')
r = longmult(mult1, mult2)
return reverse(join(r))
end
end # module LongMultiplication

View file

@ -0,0 +1,2 @@
@show LongMultiplication.longmult(big(2) ^ 64, big(2) ^ 64)
@show LongMultiplication.longmult("18446744073709551616", "18446744073709551616")

View file

@ -1,9 +1,11 @@
> longmult := proc( a, b )
local la, lb, digit;
la := length(a);
lb := length(b);
digit := (n,i)->iquo(n,10^(i-1)) mod 10;
add( add( digit(a,la-i+1) * digit(b,lb-j+1) *10^(la-i+lb-j), i=1..la), j=1..lb );
longmult := proc(a::integer,b::integer)
local A,B,m,n,i,j;
# Note, return a*b; works in Maple for any sized integer
A := convert(a,base,10);
B := convert(b,base,10);
m := numelems(A);
n := numelems(B);
add( add( A[i]*B[j]*10^(j-1), j=1..n )*10^(i-1), i=1..m );
end;
> longmult( 2^64, 2^64 );

View file

@ -16,4 +16,8 @@ sub long_multiply ( Str $x, Str $y ) {
return groups_to_num @group_sums;
}
long_multiply( '18446744073709551616', '18446744073709551616' ).say;
my $str = '18446744073709551616';
long_multiply( $str, $str ).say;
# cross-check with native implementation
say +$str * +$str;

View file

@ -1,11 +1,10 @@
def longmult(x,y)
digits = reverse_split_number(x)
result = [0]
j = 0
reverse_split_number(y).each do |m|
y.digits.each do |m|
c = 0
i = j
digits.each do |d|
x.digits.each do |d|
v = result[i]
result << 0 if v.zero?
c, v = (v + c + d*m).divmod(10)
@ -19,15 +18,6 @@ def longmult(x,y)
result.reverse.inject(0) {|sum, n| 10*sum + n}
end
def reverse_split_number(m)
digits = []
while m > 0
m, v = m.divmod 10
digits << v
end
digits
end
n=2**64
printf " %d * %d = %d\n", n, n, n*n
printf "longmult(%d, %d) = %d\n", n, n, longmult(n,n)

View file

@ -1,37 +1,37 @@
func add_with_carry(result, addend, addendpos) {
loop {
while (result.len < addendpos+1) {
result.append(0);
};
var addend_digits = (addend.to_i + result[addendpos].to_i -> to_chars);
result[addendpos] = addend_digits.pop;
addend_digits.len > 0 || break;
addend = addend_digits.pop;
addendpos++;
result.append(0)
}
var addend_digits = (addend.to_i + result[addendpos] -> to_s.chars)
result[addendpos] = addend_digits.pop
addend_digits.len > 0 || break
addend = addend_digits.pop
addendpos++
}
}
 
func longhand_multiplication(multiplicand, multiplier) {
var result = [];
var multiplicand_offset = 0;
 
var result = []
var multiplicand_offset = 0
 
multiplicand.reverse.each { |multiplicand_digit|
var multiplier_offset = multiplicand_offset;
var multiplier_offset = multiplicand_offset
multiplier.reverse.each { |multiplier_digit|
var multiplication_result = (multiplicand_digit.to_i * multiplier_digit.to_i -> to_s);
var addend_offset = multiplier_offset;
var multiplication_result = (multiplicand_digit.to_i * multiplier_digit.to_i -> to_s)
 
var addend_offset = multiplier_offset
multiplication_result.reverse.each { |result_digit_addend|
add_with_carry(result, result_digit_addend, addend_offset);
addend_offset++;
};
multiplier_offset++;
};
multiplicand_offset++;
};
return result.join.reverse;
add_with_carry(result, result_digit_addend, addend_offset)
addend_offset++
}
multiplier_offset++
}
multiplicand_offset++
}
 
return result.join.reverse
}
say longhand_multiplication('18446744073709551616', '18446744073709551616');
 
say longhand_multiplication('18446744073709551616', '18446744073709551616')