Balanced ternary: Difference between revisions

Added AppleScript.
(Added AppleScript.)
Line 291:
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]]
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]]
 
=={{header|AppleScript}}==
 
To demonstrate the possibility, the ''integerFromBT'' and ''negateBT'' handlers here work by being tricksy with the characters' Unicode numbers. It's a more efficient way to deal with the characters. But I'm not sure how this'll be taken ''vis-à-vis'' not converting to native integers first, so the remaining handlers use a strictly if-then string comparison approach. Applescript's quite happy to convert automatically between integers, reals, numeric strings, and single-item lists containing numbers, so ''BTFromInteger'' accepts any of these forms, but the numbers represented must be whole-number values and must be small enough not to error AppleScript's ''as integer'' coercion. This coercion is error free for numbers in the range -(2 ^ 31) to 2 ^ 31 - 1, although actual integer class objects can only represent numbers in the range -(2 ^ 29) to 2 ^ 29 - 1. ''IntegerFromBT'' doesn't currently impose any integer-class size limit on its output.
 
<lang applescript>-- Build a balanced ternary, as text, from an integer value or acceptable AppleScript substitute.
on BTFromInteger(n)
try
if (n mod 1 is not 0) then error (n as text) & " isn't an integer value"
set n to n as integer
on error errMsg
display alert "BTFromInteger handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
if (n is 0) then return "0"
-- Positive numbers' digits will be indexed from the beginning of a list containing them, negatives' from the end.
-- AppleScript indices are 1-based, so get the appropriate 1 or -1 add-in.
set one to 1
if (n < 0) then set one to -1
set digits to {"0", "+", "-", "0"}
-- Build the text digit by digit.
set bt to ""
repeat until (n = 0)
set nMod3 to n mod 3
set bt to (item (nMod3 + one) of digits) & bt
set n to n div 3 + nMod3 div 2 -- + nMod3 div 2 adds in a carry when nMod3 is either 2 or -2.
end repeat
return bt
end BTFromInteger
 
-- Calculate a balanced ternary's integer value from its characters' Unicode numbers.
on integerFromBT(bt)
checkInput(bt, "integerFromBT")
set n to 0
repeat with thisID in (get bt's id)
set n to n * 3
-- Unicode 48 is "0", 43 is "+", 45 is "-".
if (thisID < 48) then set n to n + (44 - thisID)
end repeat
return n
end integerFromBT
 
-- Add two balanced ternaries together.
on addBTs(bt1, bt2)
checkInput({bt1, bt2}, "addBTs")
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, longerLength, shorterLength} to {bt2, bt1, shorterLength, longerLength}
-- Add the shorter number's digits into a list of the longer number's digits, adding in carries too where appropriate.
set resultList to bt1's characters
repeat with i from -1 to -shorterLength by -1
set {carry, item i of resultList} to sumDigits(item i of resultList, character i of bt2)
repeat with j from (i - 1) to -longerLength by -1
if (carry is "0") then exit repeat
set {carry, item j of resultList} to sumDigits(carry, item j of resultList)
end repeat
if (carry is not "0") then set beginning of bt1 to carry
end repeat
-- Zap any leading zeros resulting from the cancelling out of the longer number's MSD(s).
set j to -(count resultList)
repeat while ((item j of resultList is "0") and (j < -1))
set item j of resultList to ""
set j to j + 1
end repeat
return join(resultList, "")
end addBTs
 
-- Multiply one balanced ternary by another.
on multiplyBTs(bt1, bt2)
checkInput({bt1, bt2}, "multiplyBTs")
-- Longer and shorter aren't critical here, but it's more efficient to loop through the lesser number of digits.
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, shorterLength} to {bt2, bt1, longerLength}
set multiplicationResult to "0"
repeat with i from -1 to -shorterLength by -1
set d2 to character i of bt2
if (d2 is not "0") then
set subresult to ""
-- With each non-"0" subresult, begin with the appropriate number of trailing zeros.
repeat (-1 - i) times
set subresult to "0" & subresult
end repeat
-- Prepend the longer ternary as is.
set subresult to bt1 & subresult
-- Negate the result if the current multiplier from the shorter ternary is "-".
if (d2 is "-") then set subresult to negateBT(subresult)
-- Add the subresult to the total so far.
set multiplicationResult to addBTs(multiplicationResult, subresult)
end if
end repeat
return multiplicationResult
end multiplyBTs
 
-- Negate a balanced ternary by substituting the characters obtained through subtracting its sign characters' Unicode numbers from 88.
on negateBT(bt)
checkInput(bt, "negateBT")
set characterIDs to bt's id
repeat with thisID in characterIDs
if (thisID < 48) then set thisID's contents to 88 - thisID
end repeat
return string id characterIDs
end negateBT
 
(* Private handlers. *)
 
on checkInput(params as list, handlerName)
try
repeat with thisParam in params
if (thisParam's class is text) then
if (join(split(thisParam, {"-", "+", "0"}), "") > "") then error "\"" & thisParam & "\" isn't a balanced ternary number."
else
error "The parameter isn't text."
end if
end repeat
on error errMsg
display alert handlerName & " handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
end checkInput
 
-- "Add" two balanced ternaries and return both the carry and the result for the column.
on sumDigits(d1, d2)
if (d1 is "0") then
return {"0", d2}
else if (d2 is "0") then
return {"0", d1}
else if (d1 = d2) then
if (d1 = "+") then
return {"+", "-"}
else
return {"-", "+"}
end if
else
return {"0", "0"}
end if
end sumDigits
 
on join(lst, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set txt to lst as text
set AppleScript's text item delimiters to astid
return txt
end join
 
on split(txt, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set lst to txt's text items
set AppleScript's text item delimiters to astid
return lst
end split
 
-- Test code:
set a to "+-0++0+"
set b to BTFromInteger(-436) --> "-++-0--"
set c to "+-++-"
 
set line1 to "a = " & integerFromBT(a)
set line2 to "b = " & integerFromBT(b)
set line3 to "c = " & integerFromBT(c)
tell multiplyBTs(a, addBTs(b, negateBT(c))) to ¬
set line4 to "a * (b - c) = " & it & " or " & my integerFromBT(it)
 
return line1 & linefeed & line2 & linefeed & line3 & linefeed & line4</lang>
 
{{output}}
<lang applescript>"a = 523
b = -436
c = 65
a * (b - c) = ----0+--0++0 or -262023"</lang>
 
=={{header|ATS}}==
557

edits