Balanced ternary: Difference between revisions
Content added Content deleted
(Added AppleScript.) |
|||
Line 3,559: | Line 3,559: | ||
''Note: the "-", "0", "+" denotes by digits, respectively, the "7", "8", "9".'' |
''Note: the "-", "0", "+" denotes by digits, respectively, the "7", "8", "9".'' |
||
=={{header|Nim}}== |
|||
<lang Nim>import strformat |
|||
import tables |
|||
type |
|||
# Trit definition. |
|||
Trit = range[-1'i8..1'i8] |
|||
# Balanced ternary number as a sequence of trits stored in little endian way. |
|||
BTernary = seq[Trit] |
|||
const |
|||
# Textual representation of trits. |
|||
Trits: array[Trit, char] = ['-', '0', '+'] |
|||
# Symbolic names used for trits. |
|||
TN = Trit(-1) |
|||
TZ = Trit(0) |
|||
TP = Trit(1) |
|||
# Table to convert the result of classic addition to balanced ternary numbers. |
|||
AddTable = {-2: @[TP, TN], -1: @[TN], 0: @[TZ], 1: @[TP], 2: @[TN, TP]}.toTable() |
|||
# Mapping from modulo to trits (used for conversion from int to balanced ternary). |
|||
ModTrits: array[-2..2, Trit] = [TP, TN, TZ, TP, TN] |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func normalize(bt: var BTernary) = |
|||
## Remove the extra zero trits at head of a BTernary number. |
|||
var i = bt.high |
|||
while i >= 0 and bt[i] == 0: |
|||
dec i |
|||
bt.setlen(if i < 0: 1 else: i + 1) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `+`*(a, b: BTernary): BTernary = |
|||
## Add two BTernary numbers. |
|||
# Prepare operands. |
|||
var (a, b) = (a, b) |
|||
if a.len < b.len: |
|||
a.setLen(b.len) |
|||
else: |
|||
b.setLen(a.len) |
|||
# Perform addition trit per trit. |
|||
var carry = TZ |
|||
for i in 0..<a.len: |
|||
var s = AddTable[a[i] + b[i]] |
|||
if carry != TZ: |
|||
s = s + @[carry] |
|||
carry = if s.len > 1: s[1] else: TZ |
|||
result.add(s[0]) |
|||
# Add the carry to the result if it is not null. |
|||
if carry != TZ: |
|||
result.add(carry) |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `+=`*(a: var BTernary; b: BTernary) {.inline.} = |
|||
## Increment a BTernary number. |
|||
a = a + b |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `-`(a: BTernary): BTernary = |
|||
## Negate a BTernary number. |
|||
result.setLen(a.len) |
|||
for i, t in a: |
|||
result[i] = -t |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `-`*(a, b: BTernary): BTernary {.inline.} = |
|||
## Subtract a BTernary number to another. |
|||
a + -b |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `-=`*(a: var BTernary; b: BTernary) {.inline.} = |
|||
## Decrement a BTernary number. |
|||
a = a + -b |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `*`*(a, b: BTernary): BTernary = |
|||
## Multiply tow BTernary numbers. |
|||
var start: BTernary |
|||
let na = -a |
|||
# Loop on each trit of "b" and add directly a whole row. |
|||
for t in b: |
|||
case t |
|||
of TP: result += start & a |
|||
of TZ: discard |
|||
of TN: result += start & na |
|||
start.add(TZ) # Shift next row. |
|||
result.normalize() |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func toTrit*(c: char): Trit = |
|||
## Convert a char to a trit. |
|||
case c |
|||
of '-': -1 |
|||
of '0': 0 |
|||
of '+': 1 |
|||
else: |
|||
raise newException(ValueError, fmt"Invalid trit: '{c}'") |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func `$`*(bt: BTernary): string = |
|||
## Return the string representation of a BTernary number. |
|||
result.setLen(bt.len) |
|||
for i, t in bt: |
|||
result[^(i + 1)] = Trits[t] |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func toBTernary*(s: string): BTernary = |
|||
## Build a BTernary number from its string representation. |
|||
result.setLen(s.len) |
|||
for i, c in s: |
|||
result[^(i + 1)] = c.toTrit() |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func toInt*(bt: BTernary): int = |
|||
## Convert a BTernary number to an integer. |
|||
## An overflow error is raised if the result cannot fit in an integer. |
|||
var m = 1 |
|||
for t in bt: |
|||
result += m * t |
|||
m *= 3 |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func toBTernary(val: int): BTernary = |
|||
## Convert an integer to a BTernary number. |
|||
var val = val |
|||
while true: |
|||
let trit = ModTrits[val mod 3] |
|||
result.add(trit) |
|||
val = (val - trit) div 3 |
|||
if val == 0: |
|||
break |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
when isMainModule: |
|||
let a = "+-0++0+".toBTernary |
|||
let b = -436.toBTernary |
|||
let c = "+-++-".toBTernary |
|||
echo "Balanced ternary numbers:" |
|||
echo fmt"a = {a}" |
|||
echo fmt"b = {b}" |
|||
echo fmt"c = {c}" |
|||
echo "" |
|||
echo "Their decimal representation:" |
|||
echo fmt"a = {a.toInt: 4d}" |
|||
echo fmt"b = {b.toInt: 4d}" |
|||
echo fmt"c = {c.toInt: 4d}" |
|||
echo "" |
|||
let x = a * (b - c) |
|||
echo "a × (b - c):" |
|||
echo fmt"– in ternary: {x}" |
|||
echo fmt"– in decimal: {x.toInt}"</lang> |
|||
{{out}} |
|||
<pre>Balanced ternary numbers: |
|||
a = +-0++0+ |
|||
b = -++-0-- |
|||
c = +-++- |
|||
Their decimal representation: |
|||
a = 523 |
|||
b = -436 |
|||
c = 65 |
|||
a × (b - c): |
|||
– in ternary: ----0+--0++0 |
|||
– in decimal: -262023</pre> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |