Balanced ternary: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
m (→‎{{header|REXX}}: added/changed whitespace, split some statements.)
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 25:
'''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>
 
=={{header|ALGOL 68}}==
See also:
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]]
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]]
 
=={{header|Ada}}==
Line 291 ⟶ 286:
a * (b - c) = -262023 ----0+--0++0
</pre>
 
=={{header|ALGOL 68}}==
See also:
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]]
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]]
 
=={{header|ATS}}==
Line 765:
c: +-++- 65
a*(b-c): ----0+--0++0 -262023</pre>
 
=={{header|C++}}==
<lang cpp>#include <iostream>
#include <string>
#include <climits>
using namespace std;
 
class BalancedTernary {
protected:
// Store the value as a reversed string of +, 0 and - characters
string value;
 
// Helper function to change a balanced ternary character to an integer
int charToInt(char c) const {
if (c == '0')
return 0;
return 44 - c;
}
 
// Helper function to negate a string of ternary characters
string negate(string s) const {
for (int i = 0; i < s.length(); ++i) {
if (s[i] == '+')
s[i] = '-';
else if (s[i] == '-')
s[i] = '+';
}
return s;
}
 
public:
// Default constructor
BalancedTernary() {
value = "0";
}
 
// Construct from a string
BalancedTernary(string s) {
value = string(s.rbegin(), s.rend());
}
 
// Construct from an integer
BalancedTernary(long long n) {
if (n == 0) {
value = "0";
return;
}
 
bool neg = n < 0;
if (neg)
n = -n;
 
value = "";
while (n != 0) {
int r = n % 3;
if (r == 0)
value += "0";
else if (r == 1)
value += "+";
else {
value += "-";
++n;
}
 
n /= 3;
}
 
if (neg)
value = negate(value);
}
 
// Copy constructor
BalancedTernary(const BalancedTernary &n) {
value = n.value;
}
 
// Addition operators
BalancedTernary operator+(BalancedTernary n) const {
n += *this;
return n;
}
 
BalancedTernary& operator+=(const BalancedTernary &n) {
static char *add = "0+-0+-0";
static char *carry = "--000++";
 
int lastNonZero = 0;
char c = '0';
for (int i = 0; i < value.length() || i < n.value.length(); ++i) {
char a = i < value.length() ? value[i] : '0';
char b = i < n.value.length() ? n.value[i] : '0';
 
int sum = charToInt(a) + charToInt(b) + charToInt(c) + 3;
c = carry[sum];
 
if (i < value.length())
value[i] = add[sum];
else
value += add[sum];
 
if (add[sum] != '0')
lastNonZero = i;
}
 
if (c != '0')
value += c;
else
value = value.substr(0, lastNonZero + 1); // Chop off leading zeroes
 
return *this;
}
 
// Negation operator
BalancedTernary operator-() const {
BalancedTernary result;
result.value = negate(value);
return result;
}
 
// Subtraction operators
BalancedTernary operator-(const BalancedTernary &n) const {
return operator+(-n);
}
 
BalancedTernary& operator-=(const BalancedTernary &n) {
return operator+=(-n);
}
 
// Multiplication operators
BalancedTernary operator*(BalancedTernary n) const {
n *= *this;
return n;
}
 
BalancedTernary& operator*=(const BalancedTernary &n) {
BalancedTernary pos = *this;
BalancedTernary neg = -pos; // Storing an extra copy to avoid negating repeatedly
value = "0";
 
for (int i = 0; i < n.value.length(); ++i) {
if (n.value[i] == '+')
operator+=(pos);
else if (n.value[i] == '-')
operator+=(neg);
pos.value = '0' + pos.value;
neg.value = '0' + neg.value;
}
 
return *this;
}
 
// Stream output operator
friend ostream& operator<<(ostream &out, const BalancedTernary &n) {
out << n.toString();
return out;
}
 
// Convert to string
string toString() const {
return string(value.rbegin(), value.rend());
}
 
// Convert to integer
long long toInt() const {
long long result = 0;
for (long long i = 0, pow = 1; i < value.length(); ++i, pow *= 3)
result += pow * charToInt(value[i]);
return result;
}
 
// Convert to integer if possible
bool tryInt(long long &out) const {
long long result = 0;
bool ok = true;
 
for (long long i = 0, pow = 1; i < value.length() && ok; ++i, pow *= 3) {
if (value[i] == '+') {
ok &= LLONG_MAX - pow >= result; // Clear ok if the result overflows
result += pow;
} else if (value[i] == '-') {
ok &= LLONG_MIN + pow <= result; // Clear ok if the result overflows
result -= pow;
}
}
 
if (ok)
out = result;
return ok;
}
};
 
int main() {
BalancedTernary a("+-0++0+");
BalancedTernary b(-436);
BalancedTernary c("+-++-");
 
cout << "a = " << a << " = " << a.toInt() << endl;
cout << "b = " << b << " = " << b.toInt() << endl;
cout << "c = " << c << " = " << c.toInt() << endl;
 
BalancedTernary d = a * (b - c);
 
cout << "a * (b - c) = " << d << " = " << d.toInt() << endl;
 
BalancedTernary e("+++++++++++++++++++++++++++++++++++++++++");
 
long long n;
if (e.tryInt(n))
cout << "e = " << e << " = " << n << endl;
else
cout << "e = " << e << " is too big to fit in a long long" << endl;
 
return 0;
}
</lang>
 
Output
<pre>
a = +-0++0+ = 523
b = -++-0-- = -436
c = +-++- = 65
a * (b - c) = ----0+--0++0 = -262023
e = +++++++++++++++++++++++++++++++++++++++++ is too big to fit in a long long
</pre>
 
=={{header|C sharp|C#}}==
Line 1,227 ⟶ 1,003:
c: +-++- = 65
a * (b - c): ----0+--0++0 = -262023</pre>
 
=={{header|C++}}==
<lang cpp>#include <iostream>
#include <string>
#include <climits>
using namespace std;
 
class BalancedTernary {
protected:
// Store the value as a reversed string of +, 0 and - characters
string value;
 
// Helper function to change a balanced ternary character to an integer
int charToInt(char c) const {
if (c == '0')
return 0;
return 44 - c;
}
 
// Helper function to negate a string of ternary characters
string negate(string s) const {
for (int i = 0; i < s.length(); ++i) {
if (s[i] == '+')
s[i] = '-';
else if (s[i] == '-')
s[i] = '+';
}
return s;
}
 
public:
// Default constructor
BalancedTernary() {
value = "0";
}
 
// Construct from a string
BalancedTernary(string s) {
value = string(s.rbegin(), s.rend());
}
 
// Construct from an integer
BalancedTernary(long long n) {
if (n == 0) {
value = "0";
return;
}
 
bool neg = n < 0;
if (neg)
n = -n;
 
value = "";
while (n != 0) {
int r = n % 3;
if (r == 0)
value += "0";
else if (r == 1)
value += "+";
else {
value += "-";
++n;
}
 
n /= 3;
}
 
if (neg)
value = negate(value);
}
 
// Copy constructor
BalancedTernary(const BalancedTernary &n) {
value = n.value;
}
 
// Addition operators
BalancedTernary operator+(BalancedTernary n) const {
n += *this;
return n;
}
 
BalancedTernary& operator+=(const BalancedTernary &n) {
static char *add = "0+-0+-0";
static char *carry = "--000++";
 
int lastNonZero = 0;
char c = '0';
for (int i = 0; i < value.length() || i < n.value.length(); ++i) {
char a = i < value.length() ? value[i] : '0';
char b = i < n.value.length() ? n.value[i] : '0';
 
int sum = charToInt(a) + charToInt(b) + charToInt(c) + 3;
c = carry[sum];
 
if (i < value.length())
value[i] = add[sum];
else
value += add[sum];
 
if (add[sum] != '0')
lastNonZero = i;
}
 
if (c != '0')
value += c;
else
value = value.substr(0, lastNonZero + 1); // Chop off leading zeroes
 
return *this;
}
 
// Negation operator
BalancedTernary operator-() const {
BalancedTernary result;
result.value = negate(value);
return result;
}
 
// Subtraction operators
BalancedTernary operator-(const BalancedTernary &n) const {
return operator+(-n);
}
 
BalancedTernary& operator-=(const BalancedTernary &n) {
return operator+=(-n);
}
 
// Multiplication operators
BalancedTernary operator*(BalancedTernary n) const {
n *= *this;
return n;
}
 
BalancedTernary& operator*=(const BalancedTernary &n) {
BalancedTernary pos = *this;
BalancedTernary neg = -pos; // Storing an extra copy to avoid negating repeatedly
value = "0";
 
for (int i = 0; i < n.value.length(); ++i) {
if (n.value[i] == '+')
operator+=(pos);
else if (n.value[i] == '-')
operator+=(neg);
pos.value = '0' + pos.value;
neg.value = '0' + neg.value;
}
 
return *this;
}
 
// Stream output operator
friend ostream& operator<<(ostream &out, const BalancedTernary &n) {
out << n.toString();
return out;
}
 
// Convert to string
string toString() const {
return string(value.rbegin(), value.rend());
}
 
// Convert to integer
long long toInt() const {
long long result = 0;
for (long long i = 0, pow = 1; i < value.length(); ++i, pow *= 3)
result += pow * charToInt(value[i]);
return result;
}
 
// Convert to integer if possible
bool tryInt(long long &out) const {
long long result = 0;
bool ok = true;
 
for (long long i = 0, pow = 1; i < value.length() && ok; ++i, pow *= 3) {
if (value[i] == '+') {
ok &= LLONG_MAX - pow >= result; // Clear ok if the result overflows
result += pow;
} else if (value[i] == '-') {
ok &= LLONG_MIN + pow <= result; // Clear ok if the result overflows
result -= pow;
}
}
 
if (ok)
out = result;
return ok;
}
};
 
int main() {
BalancedTernary a("+-0++0+");
BalancedTernary b(-436);
BalancedTernary c("+-++-");
 
cout << "a = " << a << " = " << a.toInt() << endl;
cout << "b = " << b << " = " << b.toInt() << endl;
cout << "c = " << c << " = " << c.toInt() << endl;
 
BalancedTernary d = a * (b - c);
 
cout << "a * (b - c) = " << d << " = " << d.toInt() << endl;
 
BalancedTernary e("+++++++++++++++++++++++++++++++++++++++++");
 
long long n;
if (e.tryInt(n))
cout << "e = " << e << " = " << n << endl;
else
cout << "e = " << e << " is too big to fit in a long long" << endl;
 
return 0;
}
</lang>
 
Output
<pre>
a = +-0++0+ = 523
b = -++-0-- = -436
c = +-++- = 65
a * (b - c) = ----0+--0++0 = -262023
e = +++++++++++++++++++++++++++++++++++++++++ is too big to fit in a long long
</pre>
 
=={{header|Common Lisp}}==
Line 3,369:
a*(b-c): ----0+--0++0 -262023
</pre>
=={{header|Perl 6}}==
{{Works with|rakudo|2017.01}}
<lang perl6>class BT {
has @.coeff;
 
my %co2bt = '-1' => '-', '0' => '0', '1' => '+';
my %bt2co = %co2bt.invert;
 
multi method new (Str $s) {
self.bless(coeff => %bt2co{$s.flip.comb});
}
multi method new (Int $i where $i >= 0) {
self.bless(coeff => carry $i.base(3).comb.reverse);
}
multi method new (Int $i where $i < 0) {
self.new(-$i).neg;
}
 
method Str () { %co2bt{@!coeff}.join.flip }
method Int () { [+] @!coeff Z* (1,3,9...*) }
 
multi method neg () {
self.new: coeff => carry self.coeff X* -1;
}
}
 
sub carry (*@digits is copy) {
loop (my $i = 0; $i < @digits; $i++) {
while @digits[$i] < -1 { @digits[$i] += 3; @digits[$i+1]--; }
while @digits[$i] > 1 { @digits[$i] -= 3; @digits[$i+1]++; }
}
pop @digits while @digits and not @digits[*-1];
@digits;
}
 
multi prefix:<-> (BT $x) { $x.neg }
 
multi infix:<+> (BT $x, BT $y) {
my ($b,$a) = sort +*.coeff, ($x, $y);
BT.new: coeff => carry ($a.coeff Z+ |$b.coeff, |(0 xx $a.coeff - $b.coeff));
}
 
multi infix:<-> (BT $x, BT $y) { $x + $y.neg }
 
multi infix:<*> (BT $x, BT $y) {
my @x = $x.coeff;
my @y = $y.coeff;
my @z = 0 xx @x+@y-1;
my @safe;
for @x -> $xd {
@z = @z Z+ |(@y X* $xd), |(0 xx @z-@y);
@safe.push: @z.shift;
}
BT.new: coeff => carry @safe, @z;
}
 
my $a = BT.new: "+-0++0+";
my $b = BT.new: -436;
my $c = BT.new: "+-++-";
my $x = $a * ( $b - $c );
 
say 'a == ', $a.Int;
say 'b == ', $b.Int;
say 'c == ', $c.Int;
say "a × (b − c) == ", ~$x, ' == ', $x.Int;</lang>
{{out}}
<pre>a == 523
b == -436
c == 65
a × (b − c) == ----0+--0++0 == -262023</pre>
 
=={{header|Phix}}==
Line 4,078 ⟶ 4,008:
Z = -262023 .
</pre>
 
=={{header|Python}}==
{{trans|Common Lisp}}
Line 4,266 ⟶ 4,197:
a×(b−c) = -262023 or ----0+--0++0
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2017.01}}
<lang perl6>class BT {
has @.coeff;
 
my %co2bt = '-1' => '-', '0' => '0', '1' => '+';
my %bt2co = %co2bt.invert;
 
multi method new (Str $s) {
self.bless(coeff => %bt2co{$s.flip.comb});
}
multi method new (Int $i where $i >= 0) {
self.bless(coeff => carry $i.base(3).comb.reverse);
}
multi method new (Int $i where $i < 0) {
self.new(-$i).neg;
}
 
method Str () { %co2bt{@!coeff}.join.flip }
method Int () { [+] @!coeff Z* (1,3,9...*) }
 
multi method neg () {
self.new: coeff => carry self.coeff X* -1;
}
}
 
sub carry (*@digits is copy) {
loop (my $i = 0; $i < @digits; $i++) {
while @digits[$i] < -1 { @digits[$i] += 3; @digits[$i+1]--; }
while @digits[$i] > 1 { @digits[$i] -= 3; @digits[$i+1]++; }
}
pop @digits while @digits and not @digits[*-1];
@digits;
}
 
multi prefix:<-> (BT $x) { $x.neg }
 
multi infix:<+> (BT $x, BT $y) {
my ($b,$a) = sort +*.coeff, ($x, $y);
BT.new: coeff => carry ($a.coeff Z+ |$b.coeff, |(0 xx $a.coeff - $b.coeff));
}
 
multi infix:<-> (BT $x, BT $y) { $x + $y.neg }
 
multi infix:<*> (BT $x, BT $y) {
my @x = $x.coeff;
my @y = $y.coeff;
my @z = 0 xx @x+@y-1;
my @safe;
for @x -> $xd {
@z = @z Z+ |(@y X* $xd), |(0 xx @z-@y);
@safe.push: @z.shift;
}
BT.new: coeff => carry @safe, @z;
}
 
my $a = BT.new: "+-0++0+";
my $b = BT.new: -436;
my $c = BT.new: "+-++-";
my $x = $a * ( $b - $c );
 
say 'a == ', $a.Int;
say 'b == ', $b.Int;
say 'c == ', $c.Int;
say "a × (b − c) == ", ~$x, ' == ', $x.Int;</lang>
{{out}}
<pre>a == 523
b == -436
c == 65
a × (b − c) == ----0+--0++0 == -262023</pre>
 
=={{header|REXX}}==
Line 4,604 ⟶ 4,607:
+ Ternary.multiply: OK, passed 100 tests.
</pre>
 
=={{header|Tcl}}==
This directly uses the printable representation of the balanced ternary numbers, as Tcl's string operations are reasonably efficient.
10,339

edits