Time for an 2014 update…

This commit is contained in:
Ingy döt Net 2014-01-17 05:32:22 +00:00
parent 372c577f83
commit 09687c4926
2520 changed files with 34227 additions and 7318 deletions

View file

@ -1,47 +1,47 @@
import std.stdio, std.bigint, std.range, std.algorithm, std.array,
std.conv, std.exception;
import std.stdio, std.bigint, std.range, std.algorithm;
struct BalancedTernary {
enum Dig : byte { N=-1, Z=0, P=+1 } // Digits.
Dig[] digits;
// Represented as a list of 0, 1 or -1s,
// with least significant digit first.
enum Dig : byte { N=-1, Z=0, P=+1 } // Digit.
const Dig[] digits;
static string dig2str = "-0+";
// This could also be a BalancedTernary template argument.
static immutable string dig2str = "-0+";
const static Dig[dchar] str2dig; // = ['+': Dig.P, ...];
static this() {
immutable static Dig[dchar] str2dig; // = ['+': Dig.P, ...];
nothrow static this() {
str2dig = ['+': Dig.P, '-': Dig.N, '0': Dig.Z];
}
immutable static Dig[2][] table =
immutable pure nothrow static Dig[2][] table =
[[Dig.Z, Dig.N], [Dig.P, Dig.N], [Dig.N, Dig.Z],
[Dig.Z, Dig.Z], [Dig.P, Dig.Z], [Dig.N, Dig.P],
[Dig.Z, Dig.P]];
this(string inp) {
this.digits = inp.retro().map!(c => cast()str2dig[c]).array;
this(in string inp) const pure {
this.digits = inp.retro.map!(c => str2dig[c]).array;
}
this(long inp) {
this(in long inp) const pure /*nothrow*/ {
this.digits = _bint2ternary(inp.BigInt);
}
this(BigInt inp) {
this(in BigInt inp) const pure /*nothrow*/ {
this.digits = _bint2ternary(inp);
}
this(BalancedTernary inp) {
this(in BalancedTernary inp) const pure nothrow {
// No need to dup, they are virtually immutable.
this.digits = inp.digits;
}
private this(Dig[] inp) {
private this(in Dig[] inp) /*inout*/ pure nothrow {
this.digits = inp;
}
static Dig[] _bint2ternary(/*in*/ BigInt n) {
static py_div(T1, T2)(T1 a, T2 b) {
static Dig[] _bint2ternary(in BigInt n) pure /*nothrow*/ {
static py_div(T1, T2)(in T1 a, in T2 b) pure /*nothrow*/ {
if (a < 0) {
return (b < 0) ?
-a / -b :
@ -54,33 +54,34 @@ struct BalancedTernary {
}
if (n == 0) return [];
switch (((n % 3) + 3) % 3) { // (n % 3) is the remainder.
// This final switch in D v.2.064 is fake, not enforced.
final switch (((n % 3) + 3) % 3) { // (n % 3) is the remainder.
case 0: return Dig.Z ~ _bint2ternary(py_div(n, 3));
case 1: return Dig.P ~ _bint2ternary(py_div(n, 3));
case 2: return Dig.N ~ _bint2ternary(py_div(n + 1, 3));
default: assert(0, "Can't happen");
}
}
@property BigInt toBint() const {
@property BigInt toBint() const pure /*nothrow*/ {
return reduce!((y, x) => x + 3 * y)(0.BigInt, digits.retro);
}
string toString() const {
string toString() const pure nothrow {
if (digits.empty) return "0";
return digits.retro.map!(d => dig2str[d + 1]).array;
}
static Dig[] neg_(Dig[] digs) {
return digs.map!q{ -a }.array;
static const(Dig)[] neg_(in Dig[] digs) pure nothrow {
return digs.map!(a => -a).array;
}
BalancedTernary opUnary(string op:"-")() {
BalancedTernary opUnary(string op:"-")() const pure nothrow {
return BalancedTernary(neg_(this.digits));
}
static Dig[] add_(Dig[] a, Dig[] b, Dig c=Dig.Z) {
auto a_or_b = a.length ? a : b;
static const(Dig)[] add_(in Dig[] a, in Dig[] b, in Dig c=Dig.Z)
pure nothrow {
const a_or_b = a.length ? a : b;
if (a.empty || b.empty) {
if (c == Dig.Z)
return a_or_b;
@ -90,7 +91,7 @@ struct BalancedTernary {
// (const d, c) = table[...];
const dc = table[3 + (a.length ? a[0] : 0) +
(b.length ? b[0] : 0) + c];
auto res = add_(a[1 .. $], b[1 .. $], dc[1]);
const res = add_(a[1 .. $], b[1 .. $], dc[1]);
// Trim leading zeros.
if (res.length || dc[0] != Dig.Z)
return [dc[0]] ~ res;
@ -99,19 +100,21 @@ struct BalancedTernary {
}
}
BalancedTernary opBinary(string op:"+")(BalancedTernary b) {
BalancedTernary opBinary(string op:"+")(in BalancedTernary b)
const pure nothrow {
return BalancedTernary(add_(this.digits, b.digits));
}
BalancedTernary opBinary(string op:"-")(BalancedTernary b) {
BalancedTernary opBinary(string op:"-")(in BalancedTernary b)
const pure nothrow {
return this + (-b);
}
static Dig[] mul_(in Dig[] a, /*in*/ Dig[] b) {
static const(Dig)[] mul_(in Dig[] a, in Dig[] b) pure nothrow {
if (a.empty || b.empty) {
return [];
} else {
Dig[] y = Dig.Z ~ mul_(a[1 .. $], b);
const y = Dig.Z ~ mul_(a[1 .. $], b);
final switch (a[0]) {
case Dig.N: return add_(neg_(b), y);
case Dig.Z: return add_([], y);
@ -120,21 +123,22 @@ struct BalancedTernary {
}
}
BalancedTernary opBinary(string op:"*")(BalancedTernary b) {
BalancedTernary opBinary(string op:"*")(in BalancedTernary b)
const pure nothrow {
return BalancedTernary(mul_(this.digits, b.digits));
}
}
void main() {
auto a = BalancedTernary("+-0++0+");
writeln("a: ", a.toBint, " ", a);
immutable a = BalancedTernary("+-0++0+");
writeln("a: ", a.toBint, ' ', a);
auto b = BalancedTernary(-436);
writeln("b: ", b.toBint, " ", b);
immutable b = BalancedTernary(-436);
writeln("b: ", b.toBint, ' ', b);
auto c = BalancedTernary("+-++-");
writeln("c: ", c.toBint, " ", c);
immutable c = BalancedTernary("+-++-");
writeln("c: ", c.toBint, ' ', c);
auto r = a * (b - c);
writeln("a * (b - c): ", r.toBint, " ", r);
immutable r = a * (b - c);
writeln("a * (b - c): ", r.toBint, ' ', r);
}

View file

@ -0,0 +1,160 @@
enum T {
m('-', -1), z('0', 0), p('+', 1)
final String symbol
final int value
private T(String symbol, int value) {
this.symbol = symbol
this.value = value
}
static T get(Object key) {
switch (key) {
case [m.value, m.symbol] : return m
case [z.value, z.symbol] : return z
case [p.value, p.symbol] : return p
default: return null
}
}
T negative() {
T.get(-this.value)
}
String toString() { this.symbol }
}
class BalancedTernaryInteger {
static final MINUS = new BalancedTernaryInteger(T.m)
static final ZERO = new BalancedTernaryInteger(T.z)
static final PLUS = new BalancedTernaryInteger(T.p)
private static final LEADING_ZEROES = /^0+/
final String value
BalancedTernaryInteger(String bt) {
assert bt && bt.toSet().every { T.get(it) }
value = bt ==~ LEADING_ZEROES ? T.z : bt.replaceAll(LEADING_ZEROES, '');
}
BalancedTernaryInteger(BigInteger i) {
this(i == 0 ? T.z.symbol : valueFromInt(i));
}
BalancedTernaryInteger(T...tArray) {
this(tArray.sum{ it.symbol });
}
BalancedTernaryInteger(List<T> tList) {
this(tList.sum{ it.symbol });
}
private static String valueFromInt(BigInteger i) {
assert i != null
if (i < 0) return negate(valueFromInt(-i))
if (i == 0) return ''
int bRem = (((i % 3) - 2) ?: -3) + 2
valueFromInt((i - bRem).intdiv(3)) + T.get(bRem)
}
private static String negate(String bt) {
bt.collect{ T.get(it) }.inject('') { str, t ->
str + (-t)
}
}
private static final Map INITIAL_SUM_PARTS = [carry:T.z, sum:[]]
private static final prepValueLen = { int len, String s ->
s.padLeft(len + 1, T.z.symbol).collect{ T.get(it) }
}
private static final partCarrySum = { partialSum, carry, trit ->
[carry: carry, sum: [trit] + partialSum]
}
private static final partSum = { parts, trits ->
def carrySum = partCarrySum.curry(parts.sum)
switch ((trits + parts.carry).sort()) {
case [[T.m, T.m, T.m]]: return carrySum(T.m, T.z) //-3
case [[T.m, T.m, T.z]]: return carrySum(T.m, T.p) //-2
case [[T.m, T.z, T.z], [T.m, T.m, T.p]]: return carrySum(T.z, T.m) //-1
case [[T.z, T.z, T.z], [T.m, T.z, T.p]]: return carrySum(T.z, T.z) //+0
case [[T.z, T.z, T.p], [T.m, T.p, T.p]]: return carrySum(T.z, T.p) //+1
case [[T.z, T.p, T.p]]: return carrySum(T.p, T.m) //+2
case [[T.p, T.p, T.p]]: default: return carrySum(T.p, T.z) //+3
}
}
BalancedTernaryInteger plus(BalancedTernaryInteger that) {
assert that != null
if (this == ZERO) return that
if (that == ZERO) return this
def prep = prepValueLen.curry([value.size(), that.value.size()].max())
List values = [prep(value), prep(that.value)].transpose()
new BalancedTernaryInteger(values[-1..(-values.size())].inject(INITIAL_SUM_PARTS, partSum).sum)
}
BalancedTernaryInteger negative() {
!this ? this : new BalancedTernaryInteger(negate(value))
}
BalancedTernaryInteger minus(BalancedTernaryInteger that) {
assert that != null
this + -that
}
private static final INITIAL_PRODUCT_PARTS = [sum:ZERO, pad:'']
private static final sigTritCount = { it.value.replaceAll(T.z.symbol,'').size() }
private BalancedTernaryInteger paddedValue(String pad) {
new BalancedTernaryInteger(value + pad)
}
private BalancedTernaryInteger partialProduct(T multiplier, String pad){
switch (multiplier) {
case T.z: return ZERO
case T.m: return -paddedValue(pad)
case T.p: default: return paddedValue(pad)
}
}
BalancedTernaryInteger multiply(BalancedTernaryInteger that) {
assert that != null
if (that == ZERO) return ZERO
if (that == PLUS) return this
if (that == MINUS) return -this
if (this.value.size() == 1 || sigTritCount(this) < sigTritCount(that)) {
return that.multiply(this)
}
that.value.collect{ T.get(it) }[-1..(-value.size())].inject(INITIAL_PRODUCT_PARTS) { parts, multiplier ->
[sum: parts.sum + partialProduct(multiplier, parts.pad), pad: parts.pad + T.z]
}.sum
}
BigInteger asBigInteger() {
value.collect{ T.get(it) }.inject(0) { i, trit -> i * 3 + trit.value }
}
def asType(Class c) {
switch (c) {
case Integer: return asBigInteger() as Integer
case Long: return asBigInteger() as Long
case [BigInteger, Number]: return asBigInteger()
case Boolean: return this != ZERO
case String: return toString()
default: return super.asType(c)
}
}
boolean equals(Object that) {
switch (that) {
case BalancedTernaryInteger: return this.value == that?.value
default: return super.equals(that)
}
}
int hashCode() { this.value.hashCode() }
String toString() { value }
}

View file

@ -0,0 +1,16 @@
BalancedTernaryInteger a = new BalancedTernaryInteger('+-0++0+')
BalancedTernaryInteger b = new BalancedTernaryInteger(-436)
BalancedTernaryInteger c = new BalancedTernaryInteger(T.p, T.m, T.p, T.p, T.m)
BalancedTernaryInteger bmc = new BalancedTernaryInteger(-436 - (c as Integer))
BalancedTernaryInteger atbmc = new BalancedTernaryInteger((a as Integer) * (-436 - (c as Integer)))
printf ("%9s = %12s %8d\n", 'a', "${a}", a as Number)
printf ("%9s = %12s %8d\n", 'b', "${b}", b as Number)
printf ("%9s = %12s %8d\n", 'c', "${c}", c as Number)
assert (b-c) == bmc
printf ("%9s = %12s %8d\n", 'b-c', "${b-c}", (b-c) as Number)
assert (a * (b-c)) == atbmc
printf ("%9s = %12s %8d\n", 'a * (b-c)', "${a * (b-c)}", (a * (b-c)) as Number)
println "\nDemonstrate failure:"
assert (a * (b-c)) == a

View file

@ -0,0 +1,137 @@
global tt$
tt$="-0+" '-1 0 1; +2 -> 1 2 3, instr
'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.
a$="+-0++0+"
a=deci(a$)
print "a",a, a$
b=-436
b$=ternary$(b)
print "b",b, b$
c$="+-++-"
c=deci(c$)
print "c",c, c$
'calculate in ternary
res$=multTernary$(a$, subTernary$(b$, c$))
print "a * (b - c)", res$
print "In decimal:",deci(res$)
print "Check:"
print "a * (b - c)", a * (b - c)
end
function deci(s$)
pow = 1
for i = len(s$) to 1 step -1
c$ = mid$(s$,i,1)
'select case c$
' case "+":sign= 1
' case "-":sign=-1
' case "0":sign= 0
'end select
sign = instr(tt$,c$)-2
deci = deci+pow*sign
pow = pow*3
next
end function
function ternary$(n)
while abs(n)>3^k/2
k=k+1
wend
k=k-1
pow = 3^k
for i = k to 0 step -1
sign = (n>0) - (n<0)
sign = sign * (abs(n)>pow/2)
ternary$ = ternary$+mid$(tt$,sign+2,1)
n = n - sign*pow
pow = pow/3
next
if ternary$ = "" then ternary$ ="0"
end function
function multTernary$(a$, b$)
c$ = ""
t$ = ""
shift$ = ""
for i = len(a$) to 1 step -1
select case mid$(a$,i,1)
case "+": t$ = b$
case "0": t$ = "0"
case "-": t$ = negate$(b$)
end select
c$ = addTernary$(c$, t$+shift$)
shift$ = shift$ +"0"
'print d, t$, c$
next
multTernary$ = c$
end function
function subTernary$(a$, b$)
subTernary$ = addTernary$(a$, negate$(b$))
end function
function negate$(s$)
negate$=""
for i = 1 to len(s$)
'print mid$(s$,i,1), instr(tt$, mid$(s$,i,1)), 4-instr(tt$, mid$(s$,i,1))
negate$=negate$+mid$(tt$, 4-instr(tt$, mid$(s$,i,1)), 1)
next
end function
function addTernary$(a$, b$)
'add a$ + b$, for now only positive
l = max(len(a$), len(b$))
a$=pad$(a$,l)
b$=pad$(b$,l)
c$ = "" 'result
carry = 0
for i = l to 1 step -1
a = instr(tt$,mid$(a$,i,1))-2
b = instr(tt$,mid$(b$,i,1))-2 '-1 0 1
c = a+b+carry
select case
case abs(c)<2
carry = 0
case c>0
carry =1: c=c-3
case c<0
carry =-1: c=c+3
end select
'print a, b, c
c$ = mid$(tt$,c+2,1)+c$
next
if carry<>0 then c$ = mid$(tt$,carry+2,1) +c$
'print c$
'have to trim leading 0's
i=0
while mid$(c$,i+1,1)="0"
i=i+1
wend
c$=mid$(c$,i+1)
if c$="" then c$="0"
addTernary$ = c$
end function
function pad$(a$,n) 'pad from right with 0 to length n
pad$ = a$
while len(pad$)<n
pad$ = "0"+pad$
wend
end function

View file

@ -0,0 +1,74 @@
use strict;
use warnings;
my @d = qw( 0 + - );
my @v = qw( 0 1 -1 );
sub to_bt {
my $n = shift;
my $b = '';
while( $n ) {
my $r = $n%3;
$b .= $d[$r];
$n -= $v[$r];
$n /= 3;
}
return scalar reverse $b;
}
sub from_bt {
my $n = 0;
for( split //, shift ) { # Horner
$n *= 3;
$n += "${_}1" if $_;
}
return $n;
}
my %addtable = (
'-0' => [ '-', '' ],
'+0' => [ '+', '' ],
'+-' => [ '0', '' ],
'00' => [ '0', '' ],
'--' => [ '+', '-' ],
'++' => [ '-', '+' ],
);
sub add {
my ($b1, $b2) = @_;
return ($b1 or $b2 ) unless ($b1 and $b2);
my $d = $addtable{ join '', sort substr( $b1, -1, 1, '' ), substr( $b2, -1, 1, '' ) };
return add( add($b1, $d->[1]), $b2 ).$d->[0];
}
sub unary_minus {
my $b = shift;
$b =~ tr/-+/+-/;
return $b;
}
sub subtract {
my ($b1, $b2) = @_;
return add( $b1, unary_minus $b2 );
}
sub mult {
my ($b1, $b2) = @_;
my $r = '0';
for( reverse split //, $b2 ){
$r = add $r, $b1 if $_ eq '+';
$r = subtract $r, $b1 if $_ eq '-';
$b1 .= '0';
}
$r =~ s/^0+//;
return $r;
}
my $a = "+-0++0+";
my $b = to_bt( -436 );
my $c = "+-++-";
my $d = mult( $a, subtract( $b, $c ) );
printf " a: %14s %10d\n", $a, from_bt( $a );
printf " b: %14s %10d\n", $b, from_bt( $b );
printf " c: %14s %10d\n", $c, from_bt( $c );
printf "a*(b-c): %14s %10d\n", $d, from_bt( $d );

View file

@ -0,0 +1,104 @@
object TernaryBit {
val P = TernaryBit(+1)
val M = TernaryBit(-1)
val Z = TernaryBit( 0)
implicit def asChar(t: TernaryBit): Char = t.charValue
implicit def valueOf(c: Char): TernaryBit = {
c match {
case '0' => 0
case '+' => 1
case '-' => -1
case nc => throw new IllegalArgumentException("Illegal ternary symbol " + nc)
}
}
implicit def asInt(t: TernaryBit): Int = t.intValue
implicit def valueOf(i: Int): TernaryBit = TernaryBit(i)
}
case class TernaryBit(val intValue: Int) {
def inverse: TernaryBit = TernaryBit(-intValue)
def charValue = intValue match {
case 0 => '0'
case 1 => '+'
case -1 => '-'
}
}
class Ternary(val bits: List[TernaryBit]) {
def + (b: Ternary) = {
val sumBits: List[Int] = bits.map(_.intValue).zipAll(b.bits.map(_.intValue), 0, 0).map(p => p._1 + p._2)
// normalize
val iv: Tuple2[List[Int], Int] = (List(), 0)
val (revBits, carry) = sumBits.foldLeft(iv)((accu: Tuple2[List[Int], Int], e: Int) => {
val s = e + accu._2
(((s + 1 + 3 * 100) % 3 - 1) :: accu._1 , (s + 1 + 3 * 100) / 3 - 100)
})
new Ternary(( TernaryBit(carry) :: revBits.map(TernaryBit(_))).reverse )
}
def - (b: Ternary) = {this + (-b)}
def <<<(a: Int): Ternary = { List.fill(a)(TernaryBit.Z) ++ bits}
def >>>(a: Int): Ternary = { bits.drop(a) }
def unary_- = { bits.map(_.inverse) }
def ** (b: TernaryBit): Ternary = {
b match {
case TernaryBit.P => this
case TernaryBit.M => - this
case TernaryBit.Z => 0
}
}
def * (mul: Ternary): Ternary = {
// might be done more efficiently - perform normalize only once
mul.bits.reverse.foldLeft(new Ternary(Nil))((a: Ternary, b: TernaryBit) => (a <<< 1) + (this ** b))
}
def intValue = bits.foldRight(0)((c, a) => a*3 + c.intValue)
override def toString = new String(bits.reverse.map(_.charValue).toArray)
}
object Ternary {
implicit def asString(t: Ternary): String = t.toString()
implicit def valueOf(s: String): Ternary = new Ternary(s.toList.reverse.map(TernaryBit.valueOf(_)))
implicit def asBits(t: Ternary): List[TernaryBit] = t.bits
implicit def valueOf(l: List[TernaryBit]): Ternary = new Ternary(l)
implicit def asInt(t: Ternary): BigInt = t.intValue
// XXX not tail recursive
implicit def valueOf(i: BigInt): Ternary = {
if (i < 0) -valueOf(-i)
else if (i == 0) new Ternary(List())
else if (i % 3 == 0) TernaryBit.Z :: valueOf(i / 3)
else if (i % 3 == 1) TernaryBit.P :: valueOf(i / 3)
else /*(i % 3 == 2)*/ TernaryBit.M :: valueOf((i + 1) / 3)
}
implicit def intToTernary(i: Int): Ternary = valueOf(i)
}
</scala>
Then these classes can be used in the following way:
<lang scala>
object Main {
def main(args: Array[String]): Unit = {
val a: Ternary = "+-0++0+"
val b: Ternary = -436
val c: Ternary = "+-++-"
println(a.toString + " " + a.intValue)
println(b.toString + " " + b.intValue)
println(c.toString + " " + c.intValue)
val res = a * (b - c)
println(res.toString + " " + res.intValue)
}
}

View file

@ -0,0 +1,15 @@
object TernarySpecification extends Properties("Ternary") {
property("sum") = forAll { (a: Int, b: Int) =>
val at: Ternary = a
val bt: Ternary = b
(at+bt).intValue == (at.intValue + bt.intValue)
}
property("multiply") = forAll { (a: Int, b: Int) =>
val at: Ternary = a
val bt: Ternary = b
(at*bt).intValue == (at.intValue * bt.intValue)
}
}