Balanced ternary: Difference between revisions
Content added Content deleted
(Added AppleScript.) |
|||
Line 291: | Line 291: | ||
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]] |
* [[Generalised floating point addition#ALGOL 68|Generalised floating point addition]] |
||
* [[Generalised floating point multiplication#ALGOL 68|Generalised floating point multiplication]] |
* [[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}}== |
=={{header|ATS}}== |