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

@ -1,16 +1,25 @@
[[wp:Balanced ternary|Balanced ternary]] is a way of representing numbers. Unlike the prevailing binary representation, a balanced ternary integer is in base 3, and each digit can have the values 1, 0, or 1. For example, decimal 11 = 3<sup>2</sup> + 3<sup>1</sup> 3<sup>0</sup>, thus can be written as "++", while 6 = 3<sup>2</sup> 3<sup>1</sup> + 0 × 3<sup>0</sup>, i.e., "+0".
[[wp:Balanced ternary|Balanced ternary]] is a way of representing numbers. Unlike the prevailing binary representation, a balanced ternary integer is in base 3, and each digit can have the values 1, 0, or 1.
For this task, implement balanced ternary representation of integers with the following
'''Requirements'''
;Examples:
Decimal 11 = 3<sup>2</sup> + 3<sup>1</sup> 3<sup>0</sup>, thus it can be written as "++"
Decimal 6 = 3<sup>2</sup> 3<sup>1</sup> + 0 × 3<sup>0</sup>, thus it can be written as "+0"
;Task:
Implement balanced ternary representation of integers with the following:
# Support arbitrarily large integers, both positive and negative;
# Provide ways to convert to and from text strings, using digits '+', '-' and '0' (unless you are already using strings to represent balanced ternary; but see requirement 5).
# Provide ways to convert to and from native integer type (unless, improbably, your platform's native integer type ''is'' balanced ternary). If your native integers can't support arbitrary length, overflows during conversion must be indicated.
# Provide ways to perform addition, negation and multiplication directly on balanced ternary integers; do ''not'' convert to native integers first.
# Make your implementation efficient, with a reasonable definition of "efficient" (and with a reasonable definition of "reasonable").
'''Test case''' With balanced ternaries ''a'' from string "+-0++0+", ''b'' from native integer -436, ''c'' "+-++-":
* write out ''a'', ''b'' and ''c'' in decimal notation;
* calculate ''a'' × (''b'' ''c''), write out the result in both ternary and decimal notations.
'''Note:''' The pages [[generalised floating point addition]] and [[generalised floating point multiplication]] have code implementing [[wp:arbitrary precision|arbitrary precision]] [[wp:floating point|floating point]] balanced ternary.
<br><br>

View file

@ -0,0 +1,85 @@
struct BalancedTernary <: Signed
digits::Vector{Int8}
end
BalancedTernary() = zero(BalancedTernary)
BalancedTernary(n) = convert(BalancedTernary, n)
const sgn2chr = Dict{Int8,Char}(-1 => '-', 0 => '0', +1 => '+')
Base.show(io::IO, bt::BalancedTernary) = print(io, join(sgn2chr[x] for x in reverse(bt.digits)))
Base.copy(bt::BalancedTernary) = BalancedTernary(copy(bt.digits))
Base.zero(::Type{BalancedTernary}) = BalancedTernary(Int8[0])
Base.iszero(bt::BalancedTernary) = bt.digits == Int8[0]
Base.convert(::Type{T}, bt::BalancedTernary) where T<:Number = sum(3 ^ T(ex - 1) * s for (ex, s) in enumerate(bt.digits))
function Base.convert(::Type{BalancedTernary}, n::Signed)
r = BalancedTernary(Int8[])
if iszero(n) push!(r.digits, 0) end
while n != 0
if mod(n, 3) == 0
push!(r.digits, 0)
n = fld(n, 3)
elseif mod(n, 3) == 1
push!(r.digits, 1)
n = fld(n, 3)
else
push!(r.digits, -1)
n = fld(n + 1, 3)
end
end
return r
end
const chr2sgn = Dict{Char,Int8}('-' => -1, '0' => 0, '+' => 1)
function Base.convert(::Type{BalancedTernary}, s::AbstractString)
return BalancedTernary(getindex.(chr2sgn, collect(reverse(s))))
end
macro bt_str(s)
convert(BalancedTernary, s)
end
const table = NTuple{2,Int8}[(0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1)]
function _add(a::Vector{Int8}, b::Vector{Int8}, c::Int8=Int8(0))
if isempty(a) || isempty(b)
if c == 0 return isempty(a) ? b : a end
return _add([c], isempty(a) ? b : a)
else
d, c = table[4 + (isempty(a) ? 0 : a[1]) + (isempty(b) ? 0 : b[1]) + c]
r = _add(a[2:end], b[2:end], c)
if !isempty(r) || d != 0
return unshift!(r, d)
else
return r
end
end
end
function Base.:+(a::BalancedTernary, b::BalancedTernary)
v = _add(a.digits, b.digits)
return isempty(v) ? BalancedTernary(0) : BalancedTernary(v)
end
Base.:-(bt::BalancedTernary) = BalancedTernary(-bt.digits)
Base.:-(a::BalancedTernary, b::BalancedTernary) = a + (-b)
function _mul(a::Vector{Int8}, b::Vector{Int8})
if isempty(a) || isempty(b)
return Int8[]
else
if a[1] == -1 x = (-BalancedTernary(b)).digits
elseif a[1] == 0 x = Int8[]
elseif a[1] == 1 x = b end
y = append!(Int8[0], _mul(a[2:end], b))
return _add(x, y)
end
end
function Base.:*(a::BalancedTernary, b::BalancedTernary)
v = _mul(a.digits, b.digits)
return isempty(v) ? BalancedTernary(0) : BalancedTernary(v)
end
a = bt"+-0++0+"
println("a: $(Int(a)), $a")
b = BalancedTernary(-436)
println("b: $(Int(b)), $b")
c = BalancedTernary("+-++-")
println("c: $(Int(c)), $c")
r = a * (b - c)
println("a * (b - c): $(Int(r)), $r")
@assert Int(r) == Int(a) * (Int(b) - Int(c))

View file

@ -1,56 +1,52 @@
/*REXX pgm converts decimal ◄───► balanced ternary; also performs arithmetic.*/
numeric digits 10000 /*be able to handle gihugic numbers. */
Ao = '+-0++0+' ; Abt = Ao /* [↓] 2 literals used by subroutine*/
Bo = '-436' ; Bbt = d2bt(Bo) ; @ = '(decimal)'
Co = '+-++-' ; Cbt = Co ; @@ = 'balanced ternary ='
/*REXX program converts decimal ◄───► balanced ternary; it also performs arithmetic. */
numeric digits 10000 /*be able to handle gihugic numbers. */
Ao = '+-0++0+' ; Abt = Ao /* [↓] 2 literals used by subroutine*/
Bo = '-436' ; Bbt = d2bt(Bo); @ = '(decimal)'
Co = '+-++-' ; Cbt = Co ; @@ = 'balanced ternary ='
call btShow '[a]', Abt
call btShow '[b]', Bbt
call btShow '[c]', Cbt
say; $bt = btMul(Abt,btSub(Bbt,Cbt))
say; $bt = btMul(Abt, btSub(Bbt, Cbt) )
call btShow '[a*(b-c)]', $bt
exit /*stick a fork in it, we're all done. */
/*────────────────────────────────────────────────────────────────────────────*/
d2bt: procedure; parse arg x 1; p=0; $.='-'; $.1='+'; $.0=0; #=
x=x/1
do until x==0; _=(x//(3**(p+1)))%3**p
if _== 2 then _= -1
if _== -2 then _= 1
x=x-_*(3**p); p=p+1; #=$._ || #
end /*until ···*/
return #
/*────────────────────────────────────────────────────────────────────────────*/
bt2d: procedure; parse arg x; r=reverse(x); #=0; $.=-1; $.0=0; _='+'; $._=1
do j=1 for length(x); _=substr(r,j,1); #=#+$._*3**(j-1); end
return #
/*────────────────────────────────────────────────────────────────────────────*/
btAdd: procedure; parse arg x,y; rx=reverse(x); ry=reverse(y); carry=0
@.=0 ; _='-'; @._=-1; _="+"; @._=1
$.='-'; $.0=0; $.1='+'
#=; do j=1 for max(length(x),length(y))
x_=substr(rx,j,1); xn=@.x_
y_=substr(ry,j,1); yn=@.y_
s=xn+yn+carry ; carry= 0
if s== 2 then do; s=-1; carry= 1; end
if s== 3 then do; s= 0; carry= 1; end
if s==-2 then do; s= 1; carry=-1; end
#=$.s || #
end /*j*/
if carry\==0 then #=$.carry||#; return btNorm(#)
/*────────────────────────────────────────────────────────────────────────────*/
btMul: procedure; parse arg x 1 x1 2, y 1 y1 2; if x==0 | y==0 then return 0
S=1; x=btNorm(x); y=btNorm(y) /*handle: 0-xxx values.*/
if x1=='-' then do; x=btNeg(x); S=-S; end /*positate.*/
if y1=='-' then do; y=btNeg(y); S=-S; end /* " */
if length(y)>length(x) then parse value x y with y x /*optimize.*/
P=0
do until y==0 /*keep adding 'til done*/
P=btAdd(P,x) /*multiple the hard way*/
y=btSub(y,'+') /*subtract 1 from Y.*/
end /*until*/
if S==-1 then P=btNeg(P) /*adjust product sign. */
return P /*return the product P.*/
/*────────────────────────────────────────────────────────────────────────────*/
btNeg: return translate(arg(1), '-+', "+-") /*negate the bal_tern #*/
btNorm: _=strip(arg(1),'L',0); if _=='' then _=0; return _ /*normalize a #*/
btSub: return btAdd(arg(1), btNeg(arg(2))) /*subtract two BT args.*/
btShow: say center(arg(1),9) right(arg(2),20) @@ right(bt2d(arg(2)),9) @; return
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
d2bt: procedure; parse arg x 1; p=0; $.='-'; $.1='+'; $.0=0; #=
x=x / 1
do until x==0; _= (x // (3** (p+1) ) ) % 3**p
if _== 2 then _= -1; else if _== -2 then _=1
x=x - _ * (3**p); p=p+1; #=$._ || #
end /*until*/; return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
bt2d: procedure; parse arg x; r=reverse(x); #=0; $.=-1; $.0=0; _='+'; $._=1
do j=1 for length(x); _=substr(r,j,1); #= # + $._ * 3**(j-1); end; return #
/*──────────────────────────────────────────────────────────────────────────────────────*/
btAdd: procedure; parse arg x,y; rx=reverse(x); ry=reverse(y); carry=0
@.=0 ; _='-'; @._= -1; _="+"; @._=1
$.='-'; $.0=0; $.1= '+'
#=; do j=1 for max( length(x), length(y) )
x_=substr(rx, j, 1); xn=@.x_
y_=substr(ry, j, 1); yn=@.y_
s=xn + yn + carry; carry= 0
if s== 2 then do; s=-1; carry= 1; end
if s== 3 then do; s= 0; carry= 1; end
if s==-2 then do; s= 1; carry=-1; end
#=$.s || #
end /*j*/
if carry\==0 then #=$.carry || #; return btNorm(#)
/*──────────────────────────────────────────────────────────────────────────────────────*/
btMul: procedure; parse arg x 1 x1 2, y 1 y1 2; if x==0 | y==0 then return 0
S=1; x=btNorm(x); y=btNorm(y) /*handle: 0-xxx values.*/
if x1=='-' then do; x=btNeg(x); S=-S; end /*positate the number. */
if y1=='-' then do; y=btNeg(y); S=-S; end /* " " " */
if length(y)>length(x) then parse value x y with y x /*optimize " " */
P=0
do until y==0 /*keep adding 'til done*/
P=btAdd(P, x) /*multiple the hard way*/
y=btSub(y, '+') /*subtract 1 from Y.*/
end /*until*/
if S==-1 then P=btNeg(P); return P /*adjust the product sign; return. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
btNeg: return translate(arg(1), '-+', "+-") /*negate bal_ternary #.*/
btNorm: _=strip(arg(1),'L',0); if _=='' then _=0; return _ /*normalize the number.*/
btSub: return btAdd(arg(1), btNeg(arg(2))) /*subtract two BT args.*/
btShow: say center(arg(1),9) right(arg(2),20) @@ right(bt2d(arg(2)),9) @; return