Jump to content

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

Cookies help us deliver our services. By using our services, you agree to our use of cookies.