RosettaCodeData/Task/Balanced-ternary/D/balanced-ternary.d

145 lines
4.4 KiB
D
Raw Permalink Normal View History

2014-01-17 05:32:22 +00:00
import std.stdio, std.bigint, std.range, std.algorithm;
2013-04-10 16:57:12 -07:00
struct BalancedTernary {
// Represented as a list of 0, 1 or -1s,
// with least significant digit first.
2014-01-17 05:32:22 +00:00
enum Dig : byte { N=-1, Z=0, P=+1 } // Digit.
const Dig[] digits;
2013-04-10 16:57:12 -07:00
2014-01-17 05:32:22 +00:00
// This could also be a BalancedTernary template argument.
static immutable string dig2str = "-0+";
2013-04-10 16:57:12 -07:00
2014-01-17 05:32:22 +00:00
immutable static Dig[dchar] str2dig; // = ['+': Dig.P, ...];
nothrow static this() {
2013-04-10 16:57:12 -07:00
str2dig = ['+': Dig.P, '-': Dig.N, '0': Dig.Z];
}
2014-01-17 05:32:22 +00:00
immutable pure nothrow static Dig[2][] table =
2013-04-10 16:57:12 -07:00
[[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]];
2014-01-17 05:32:22 +00:00
this(in string inp) const pure {
this.digits = inp.retro.map!(c => str2dig[c]).array;
2013-04-10 16:57:12 -07:00
}
2015-02-20 00:35:01 -05:00
this(in long inp) const pure nothrow {
2013-06-05 21:47:54 +00:00
this.digits = _bint2ternary(inp.BigInt);
2013-04-10 16:57:12 -07:00
}
2015-02-20 00:35:01 -05:00
this(in BigInt inp) const pure nothrow {
2013-04-10 16:57:12 -07:00
this.digits = _bint2ternary(inp);
}
2014-01-17 05:32:22 +00:00
this(in BalancedTernary inp) const pure nothrow {
2013-06-05 21:47:54 +00:00
// No need to dup, they are virtually immutable.
2013-04-10 16:57:12 -07:00
this.digits = inp.digits;
}
2015-02-20 00:35:01 -05:00
private this(in Dig[] inp) pure nothrow {
2013-04-10 16:57:12 -07:00
this.digits = inp;
}
2015-02-20 00:35:01 -05:00
static Dig[] _bint2ternary(in BigInt n) pure nothrow {
static py_div(T1, T2)(in T1 a, in T2 b) pure nothrow {
2013-06-05 21:47:54 +00:00
if (a < 0) {
return (b < 0) ?
-a / -b :
-(-a / b) - (-a % b != 0 ? 1 : 0);
} else {
return (b < 0) ?
-(a / -b) - (a % -b != 0 ? 1 : 0) :
a / b;
}
2013-04-10 16:57:12 -07:00
}
if (n == 0) return [];
2014-01-17 05:32:22 +00:00
// This final switch in D v.2.064 is fake, not enforced.
final switch (((n % 3) + 3) % 3) { // (n % 3) is the remainder.
2013-04-10 16:57:12 -07:00
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));
}
}
2015-02-20 00:35:01 -05:00
@property BigInt toBint() const pure nothrow {
2013-06-05 21:47:54 +00:00
return reduce!((y, x) => x + 3 * y)(0.BigInt, digits.retro);
2013-04-10 16:57:12 -07:00
}
2014-01-17 05:32:22 +00:00
string toString() const pure nothrow {
2013-04-10 16:57:12 -07:00
if (digits.empty) return "0";
2013-06-05 21:47:54 +00:00
return digits.retro.map!(d => dig2str[d + 1]).array;
2013-04-10 16:57:12 -07:00
}
2014-01-17 05:32:22 +00:00
static const(Dig)[] neg_(in Dig[] digs) pure nothrow {
return digs.map!(a => -a).array;
2013-04-10 16:57:12 -07:00
}
2014-01-17 05:32:22 +00:00
BalancedTernary opUnary(string op:"-")() const pure nothrow {
2013-04-10 16:57:12 -07:00
return BalancedTernary(neg_(this.digits));
}
2014-01-17 05:32:22 +00:00
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;
2013-04-10 16:57:12 -07:00
if (a.empty || b.empty) {
if (c == Dig.Z)
return a_or_b;
else
return BalancedTernary.add_([c], a_or_b);
} else {
// (const d, c) = table[...];
const dc = table[3 + (a.length ? a[0] : 0) +
(b.length ? b[0] : 0) + c];
2014-01-17 05:32:22 +00:00
const res = add_(a[1 .. $], b[1 .. $], dc[1]);
2013-06-05 21:47:54 +00:00
// Trim leading zeros.
2013-04-10 16:57:12 -07:00
if (res.length || dc[0] != Dig.Z)
return [dc[0]] ~ res;
else
return res;
}
}
2014-01-17 05:32:22 +00:00
BalancedTernary opBinary(string op:"+")(in BalancedTernary b)
const pure nothrow {
2013-04-10 16:57:12 -07:00
return BalancedTernary(add_(this.digits, b.digits));
}
2014-01-17 05:32:22 +00:00
BalancedTernary opBinary(string op:"-")(in BalancedTernary b)
const pure nothrow {
2013-04-10 16:57:12 -07:00
return this + (-b);
}
2014-01-17 05:32:22 +00:00
static const(Dig)[] mul_(in Dig[] a, in Dig[] b) pure nothrow {
2013-04-10 16:57:12 -07:00
if (a.empty || b.empty) {
return [];
} else {
2014-01-17 05:32:22 +00:00
const y = Dig.Z ~ mul_(a[1 .. $], b);
2013-04-10 16:57:12 -07:00
final switch (a[0]) {
case Dig.N: return add_(neg_(b), y);
case Dig.Z: return add_([], y);
case Dig.P: return add_(b, y);
}
}
}
2014-01-17 05:32:22 +00:00
BalancedTernary opBinary(string op:"*")(in BalancedTernary b)
const pure nothrow {
2013-04-10 16:57:12 -07:00
return BalancedTernary(mul_(this.digits, b.digits));
}
}
void main() {
2014-01-17 05:32:22 +00:00
immutable a = BalancedTernary("+-0++0+");
writeln("a: ", a.toBint, ' ', a);
2013-04-10 16:57:12 -07:00
2014-01-17 05:32:22 +00:00
immutable b = BalancedTernary(-436);
writeln("b: ", b.toBint, ' ', b);
2013-04-10 16:57:12 -07:00
2014-01-17 05:32:22 +00:00
immutable c = BalancedTernary("+-++-");
writeln("c: ", c.toBint, ' ', c);
2013-04-10 16:57:12 -07:00
2015-02-20 00:35:01 -05:00
const /*immutable*/ r = a * (b - c);
2014-01-17 05:32:22 +00:00
writeln("a * (b - c): ", r.toBint, ' ', r);
2013-04-10 16:57:12 -07:00
}