newRPL - build 1255 released! [updated to 1299] - Printable Version +- HP Forums (https://www.hpmuseum.org/forum) +-- Forum: Not HP Calculators (/forum-7.html) +--- Forum: Not quite HP Calculators - but related (/forum-8.html) +--- Thread: newRPL - build 1255 released! [updated to 1299] (/thread-9700.html) RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-15-2019 09:00 PM (05-15-2019 11:47 AM)Gilles Wrote:  Claudio, thanks for your reply. About the IP command, I noticed that the IP command returns an approx or exact number : 1.2 IP returns 1 but 1.2. IP returns 1. and 1. IP returns 1. Perhaps it would be more coherent that the IP command always return an exact number : 1. IP -> 1 ? An approximated number can only be guaranteed correct to the number of digits it carries (usually the current system precision), the dot doesn't have any real practical meaning other than confirming to the user that the number he's seeing on the screen may have been subjected to rounding error at the current precision. IP of an approximated number is still an approximation. Let's say precision is 4 and the "exact" number should've been 0.99999 (5 digits of 9). At the current system precision of 4, the number in question would be represented as 1.000. (4 dgits w/ending dot) If you use IP of that approximated number you'll get 1. (one w/ending dot, not exact). Notice that IP of the exact number would've been 0, so the result of IP too may have been affected by rounding error and is therefore not guaranteed to be exact. (05-15-2019 11:47 AM)Gilles Wrote:  If not, NewRpl lacks an R->I (or a more generic A->E Approx to exact) command Why would you care to force an inexact number to be exact? Besides obsessing about whether a number is exact or not, I can't see any practical use for that. If you can think of a specific use and can convince me to add the command, I'm open to it. I just never found any real case that would need it. RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-15-2019 11:11 PM Hello Claudio, first and foremost, I renew you my compliments for your work on newRPL: it's been a couple of years I haven't followed the progress of your project (life issues...) and having returned to it a couple of weeks ago I'm amazed to see latest advancements. I'be been using regularly at work new RPL (build 1180) for some weeks and this allowed me to spot a few bugs, some of them by pure chance - or misfortune if you prefer! 1) X*1_[m] EVAL (where X is an undefined variable) crashes the calc; 2) XROOT(1,0) sends the calc into an infinite loop. Interestingly (at least for me!), the actual result is not entirely trivial: https://www.quora.com/What-is-the-zeroth-root-of-any-number 3) (TVM) Solving for I%YR, N or PYR when other variables are undefined leaves the stack dirty besides erroring out as expected; 4) →Q doesn't work with parallel list processing 5) Type exactly 6π [ENTER]. Now you have 6 on level 2 and π on level 1: if you now issue →NUM you get a "π error: undefined variable" error 6) If in parallel processing a calculation returns NaN then no output is returned: I'll explain myself with an example: « ∞ SIN » returns NaN but « { ∞ ∞ } SIN » doesn't return { NaN NaN }. Instead, it aborts leaving unevaluated { ∞ ∞ } on the stack. 7) DIGITS should return a string, otherwise potential leading zeros are lost 8) Evaluation of the symbolic expression in the attachment crashes the calc. [attachment=7267] RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-15-2019 11:30 PM (05-15-2019 09:00 PM)Claudio L. Wrote:   (05-15-2019 11:47 AM)Gilles Wrote:  Claudio, thanks for your reply. About the IP command, I noticed that the IP command returns an approx or exact number : 1.2 IP returns 1 but 1.2. IP returns 1. and 1. IP returns 1. Perhaps it would be more coherent that the IP command always return an exact number : 1. IP -> 1 ? An approximated number can only be guaranteed correct to the number of digits it carries (usually the current system precision), the dot doesn't have any real practical meaning other than confirming to the user that the number he's seeing on the screen may have been subjected to rounding error at the current precision. IP of an approximated number is still an approximation. Let's say precision is 4 and the "exact" number should've been 0.99999 (5 digits of 9). At the current system precision of 4, the number in question would be represented as 1.000. (4 dgits w/ending dot) If you use IP of that approximated number you'll get 1. (one w/ending dot, not exact). Notice that IP of the exact number would've been 0, so the result of IP too may have been affected by rounding error and is therefore not guaranteed to be exact. (05-15-2019 11:47 AM)Gilles Wrote:  If not, NewRpl lacks an R->I (or a more generic A->E Approx to exact) command Why would you care to force an inexact number to be exact? Besides obsessing about whether a number is exact or not, I can't see any practical use for that. If you can think of a specific use and can convince me to add the command, I'm open to it. I just never found any real case that would need it. From a numerical stand point, me neither can see a real use case for an approximate to exact conversion, which can be however emulated via the << ->STR RTAIL STR-> >> sequence (of course, the inverse is simply << 0. + >>. Nevertheless, the string manipulation trick highlights an issue: ->STR respects the current numerical format, therefore if I have set a fancy format for my numbers but need a different one for e.g. result presentation/string manipulation I have to GETNFMT, SETNFMT, do my trick and re-SETNFMT. It's cumbersome to write and requires unwanted stack manipulation: Claudio, would it be possible in the future to add a ->NFMT command which accepts a number and a format list and does a one-off string conversion? RE: newRPL - build 1089 released! [update:build 1158] - Gilles - 05-16-2019 09:23 AM (05-15-2019 09:00 PM)Claudio L. Wrote:   (05-15-2019 11:47 AM)Gilles Wrote:  If not, NewRpl lacks an R->I (or a more generic A->E Approx to exact) command Why would you care to force an inexact number to be exact? Besides obsessing about whether a number is exact or not, I can't see any practical use for that. If you can think of a specific use and can convince me to add the command, I'm open to it. I just never found any real case that would need it. 1/ To preserve backwards compatibility with the RPL language. In RPL : 123. R->I returns 123 2/ With some problem you have to find an exact solution. But to find it, you first have to deal with an approx solution (or an interval) and look around to find and verify the exact solution. 3/ To play with digits. I knows the DIGITS command. But in some case, it is interesting to do things like (probably not the best way) : { 1. 2. 3. 4. } << R->I ->STR >> MAP ΣLIST STR-> returns 1234 (NL->I behavior with the ListExt Library) 4/ Perhaps I missed a command, but if you need an 'exact' random integer/ or a random matrix with exact integers. Or generate a random number in Q (ie .'158/99') EDIT : in fact the ->Q command does the job ;D 123. ->Q returns 123 RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-16-2019 10:15 AM Hello Claudio, I've found a couple of regressions. 1) (1,∡0º) √ returns a wrong result. Wrong also if the angle is in radians or grads, but not if it is in DMS. 2) Entering (1 0X) puts a malformed symbolic on the stack (discovered by my clumsiness!) RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-16-2019 01:58 PM Thanks for all the bug reports! These will keep me busy, it seems you found quite a bit of special cases the compiler isn't handling well, I'll go one by one and clean everything up. RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-16-2019 02:33 PM (05-16-2019 01:58 PM)Claudio L. Wrote:  Thanks for all the bug reports! These will keep me busy, it seems you found quite a bit of special cases the compiler isn't handling well, I'll go one by one and clean everything up. I hope you don't mind if I report a last one... A solitary dot is accepted by the parser, allowing construction of expressions such as 'SIN(.)' or '√.' RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-16-2019 05:19 PM (05-16-2019 02:33 PM)JoJo1973 Wrote:   (05-16-2019 01:58 PM)Claudio L. Wrote:  Thanks for all the bug reports! These will keep me busy, it seems you found quite a bit of special cases the compiler isn't handling well, I'll go one by one and clean everything up. I hope you don't mind if I report a last one... A solitary dot is accepted by the parser, allowing construction of expressions such as 'SIN(.)' or '√.' I don't mind at all... that doesn't look good. However, the dot is a valid character in a variable name (like many other symbols), therefore '.' is a valid variable name, though a bit unsightly. The only problem is, if I add the requirement of at least one letter in the name of the variable, it would rule out variables that are greek letters for example (since greek letters are just weird Unicode symbols after all, not too different from the dot). Even banning the dot you could always find some strange unicode symbol that's not forbidden and create a strange variable name like that. I don't know what's the proper solution in this case. RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-16-2019 06:05 PM (05-16-2019 05:19 PM)Claudio L. Wrote:   (05-16-2019 02:33 PM)JoJo1973 Wrote:  I hope you don't mind if I report a last one... A solitary dot is accepted by the parser, allowing construction of expressions such as 'SIN(.)' or '√.' I don't mind at all... that doesn't look good. However, the dot is a valid character in a variable name (like many other symbols), therefore '.' is a valid variable name, though a bit unsightly. The only problem is, if I add the requirement of at least one letter in the name of the variable, it would rule out variables that are greek letters for example (since greek letters are just weird Unicode symbols after all, not too different from the dot). Even banning the dot you could always find some strange unicode symbol that's not forbidden and create a strange variable name like that. I don't know what's the proper solution in this case. IIRC, Unicode tables which you derive data from have flags to classify the code points: you could limit valid characters for identifiers to 0-9, letter-like symbols and a few selected symbols - underscore, dot (except a single dot character) and the likes. Alternatively, you could limit the letter-like characters by blocks: Basic Latin, Greek, Cyrillic and Hebrew blocks have consecutive code points and cover 99.999% of practical uses. I guess there is not much appetite to name a variable in Runic or Balinese! RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-16-2019 11:05 PM (05-16-2019 06:05 PM)JoJo1973 Wrote:  IIRC, Unicode tables which you derive data from have flags to classify the code points: you could limit valid characters for identifiers to 0-9, letter-like symbols and a few selected symbols - underscore, dot (except a single dot character) and the likes. Right now it only has a list of forbidden characters (which are operators and separators in symbolic expressions), but anything else is valid. Since there's thousands of valid characters and only a few forbidden, it made sense at the time. (05-16-2019 06:05 PM)JoJo1973 Wrote:  Alternatively, you could limit the letter-like characters by blocks: Basic Latin, Greek, Cyrillic and Hebrew blocks have consecutive code points and cover 99.999% of practical uses. I guess there is not much appetite to name a variable in Runic or Balinese! newRPL has only the minimum information needed to perform a NFC normalization of a string. Other than that, it does not really mess with Unicode, other than properly decoding/encoding UTF-8 strings. So the information to know if a character is a punctuation symbol or a letter isn't really there (probably wouldn't fit in the entire flash!). Separating by blocks would be OK if there wasn't a lot of punctuations and symbols included within the blocks. Having a lookup table for a few limited blocks with a bit indicating if it's a letter or not would be perhaps doable. I'll have to think about it some more. RE: newRPL - build 1089 released! [update:build 1158] - Gilles - 05-17-2019 11:28 AM Hi Claudio, I noticed 2 problems (Rev 1180) 1/ If you have in a program something like : IF 'a>20 AND a<1000' THEN .... It works fine but when you recall the program you get : IF 'a>20ANDa<1000' THEN ... and you have to add the losts spaces by hand to compil again. 2/ Suppose we have an object 'Lst' wich is { 2 4 6 8 } Lst 3 GET returns 6 but 'Lst' 3 GET returns nothing and change Lst in 6 Same behavior if 'Lst' is a matrice. RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-17-2019 02:06 PM (05-17-2019 11:28 AM)Gilles Wrote:  Hi Claudio, I noticed 2 problems (Rev 1180) 1/ If you have in a program something like : IF 'a>20 AND a<1000' THEN .... It works fine but when you recall the program you get : IF 'a>20ANDa<1000' THEN ... and you have to add the losts spaces by hand to compil again. I didn't think of that: some operators are not symbols, so the decompiler needs to add spaces if they are in a symbolic. (05-17-2019 11:28 AM)Gilles Wrote:  2/ Suppose we have an object 'Lst' wich is { 2 4 6 8 } Lst 3 GET returns 6 but 'Lst' 3 GET returns nothing and change Lst in 6 Same behavior if 'Lst' is a matrice. Bizarre. So, I added all these bugs you guys reported to the bug tracker, I'm going to start using it again since there's too many for me to remember and also to assign priorities (some of these last ones are really critical). If you guys want access to the bug tracker you could report issues directly there, just send me a PM with an email address. Don't worry your email address won't appear anywhere, I'll create virtual throw-away emails for you with an hpgcc3.org domain that forward to your emails, that way your private emails will never be stored in the bugtracker site (which is encrypted, non-public and secure, but you never know when a security hole will become known). I'd like to recruit both of you as official bug hunters of newRPL. RE: newRPL - build 1089 released! [update:build 1158] - Gilles - 05-20-2019 09:26 PM PM sended. I started to adapt a subset of David Mutter's ListExt library and GoferList to newRPL. It's very fast and efficient. On the other hand I noticed that the structure DIR ... END is not supported in newRPL. Claudio, will it be in the future? It would give more readable sources than having to do "STO" for each program. Just to illustrate : Code: ```@============================================================================== @  List Extension + Gofer List adaptation v0.001, Mai 2019, GC @------------------------------------------------------------------------------ DIR @==============================================================================  @ LSeq – List Sequence @ Description : Génére une liste de n entiers @ @    Lev.1        Lev.1 @------------------------------------------------------------------------------ @    n    →    {1,2,3,…,n} @------------------------------------------------------------------------------   LSeq   « → a  « 1 a FOR 'n' n NEXT a →LIST » » @==============================================================================  @ LSeqr – List Sequence Range @ Description : Génére une liste de n entiers entre 2 valeurs @ @    Level 1        Level 2        Level 1 @------------------------------------------------------------------------------ @    a        b    →    {a, a+1, a+2, …, b} @------------------------------------------------------------------------------  LSeqr      « → a b  « a b FOR 'n' n NEXT b a - 1 + →LIST » » @==============================================================================  @ LLast – List Last element @ Description : Renvoie le dernier élément d'une liste @ @    Lev.1            Lev.1 @------------------------------------------------------------------------------ @    {e1, e2, ...en}    →    en @------------------------------------------------------------------------------  LLast  « DUP SIZE GET » @==============================================================================  @ LASeq – List Artihmetic Sequence @ Description : Renvoie une liste de n3 éléments commençant par n1  @ @    Lev.1    Lev.2    Lev.3        Lev.1 @------------------------------------------------------------------------------ @    n1    n2    n3    →    {n1, n1+n2,…, n1+n2*(n3-1)} @------------------------------------------------------------------------------ @ Exemple :     1 2 5 LASeq → { 1 3 5 7 9 } @        0 0.25 11 LASeq →  { 0. .25 .5 .75 1. 1.25 1.5 1.75 2. 2.25 2.5 } @        1 1 0 LASeq -> { } @------------------------------------------------------------------------------  LASeq   « → dép diff nbr     «      CASE       nbr 0 == THEN {} END      nbr 1 == THEN dép 1 →LIST END      dép       2 nbr START DUP diff + NEXT      nbr →LIST     END    »    » @==============================================================================  @ LPop – Reste et premier élément de la liste @ Description : Renvoie le reste et le premier élément d'une liste.  @ Toutes les sous-listes doivent avoir la même dimension. @ @    Lev.1                Lev.1            Lev.2 @------------------------------------------------------------------------------ @    {e1, e2, e3, …, en}    →    {e2,e3, …, en}        e1 @------------------------------------------------------------------------------ @ Exemple :     { 1 2 3 4 5 } LPOP => { 2 3 4 5 } 1 @------------------------------------------------------------------------------  LPop   « DUP TAIL SWAP HEAD » @==============================================================================  @ LZip – « Zip » une liste de listes de même nombre d'éléments comme suit : @ Description : @    Lev.1                    Lev.1 @------------------------------------------------------------------------------ @ {{e11 e12 … e1a} {e21 e22 … e2b}… } → {{e11 e21 … ea1} {e12 e22 … eb2} … } @------------------------------------------------------------------------------ @ Exemple :  @ {{ 1 A } { 2 B } { 3 C }} → {{ 1 2 3 } { A B C}} @ {{ 1 2 3 } { A B C } { x y z }} →  {{ 1 A x} {2 B y } {3 C z}} @------------------------------------------------------------------------------  LZip   « OBJ→ DUP 'nl' LSTO « nl →LIST » DOLIST » @==============================================================================  @ LFilter – Sélectionne les éléments d'une liste @ Description : Filtre une liste en fonction d'un programme @ @    Lev.1            Lev.2        Lev.1             @------------------------------------------------------------------------------ @    {e1 e2 … en}        « Prog »  →     {e? e? … } @------------------------------------------------------------------------------ @ Exemple :     { 1 2 3 4 5 6 7 } « 2 MOD »    → { 1 3 5 7 } @------------------------------------------------------------------------------  LFilter    « → filtre « « IF DUP filtre NOT THEN DROP END » MAP » »  @==============================================================================  @ NL→I – Transforme une liste de chiffres en un nombre @ Description : Number List to integer @ @    Lev.1            Lev.1             @------------------------------------------------------------------------------ @    {n1 n2 … nn}    →      n1n2…nn @------------------------------------------------------------------------------ @ Exemple :     { 1 2 3 4 5 6 7 } → 1234567 @------------------------------------------------------------------------------  NL→I   « « →STR + » STREAM STR→ »  @==============================================================================  @ I→NL – Transforme un nombre en une liste de chiffres @ Description : Number List to interger @ @    Lev.1            Lev.1             @------------------------------------------------------------------------------ @    n1n2…nn         →     {n1 n2 … nn}     @------------------------------------------------------------------------------ @ Exemple :     1234567 → { 1 2 3 4 5 6 7 }  @------------------------------------------------------------------------------   I→NL   «     →STR UTF8→     « IF DUPDUP #3Ah ≤ SWAP #30h ≥ AND THEN →UTF8 STR→ ELSE DROP END » MAP   » @==============================================================================  @ LDdup – Déduplication des doublons d'une liste @ Description : Liste Déduplication.  @ @    Lev.1            Lev.1             @------------------------------------------------------------------------------ @    {e1 e2 … en}    →     {e? e? … }     @------------------------------------------------------------------------------ @ Exemple :     { 9 2 3 9 4 1 2 7 7  3 5 6 7 } → { 9 2 3 4 1 7 5 6 } @------------------------------------------------------------------------------   LDdup    «     REVLIST OBJ→ {}    1 ROT START     IF SWAP DUP2 POS THEN DROP ELSE ADD END    NEXT    »  @==============================================================================  @ LUnion – Union de deux listes @ Description :  @ @    Lev.1        Lev.2            Lev.1             @------------------------------------------------------------------------------ @    {e11 e12 … e1a}    {e21 e22 … e2b}    →     {e? e? … }     @------------------------------------------------------------------------------ @ Exemple :     { 9 2 3 4 } { 1 2 7 9 } → { 9 2 3 4 1 7  } @------------------------------------------------------------------------------   LUnion   « ADD LDdup » @==============================================================================  @ LInter – Intersection de deux listes @ Description :  @ @    Lev.1        Lev.2            Lev.1             @------------------------------------------------------------------------------ @    {e11 e12 … e1a}    {e21 e22 … e2b}    →     {e? e? … }     @------------------------------------------------------------------------------ @ Exemple :     { 9 2 3 4 } { 1 2 7 9 } → { 9 2 } @------------------------------------------------------------------------------   LInter   « → Lst2    « « IF DUP Lst2 SWAP POS NOT THEN DROP END » MAP »   » @==============================================================================  @ LDiff – Différences entre deux listes @ Description :   @ @    Lev.1        Lev.2            Lev.1             @------------------------------------------------------------------------------ @    {e11 e12 … e1a}    {e21 e22 … e2b}    →     {e? e? … }     @------------------------------------------------------------------------------ @ Exemple :     { 9 2 3 4 } { 1 2 7 9 } → { 3 4 1 7 } @------------------------------------------------------------------------------   LDiff   « → Lst2    « « IF DUP Lst2 SWAP POS THEN DROP END » MAP »   » @==============================================================================  END``` RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-20-2019 10:41 PM Hi Gilles, this program will do: Code: ``` «   @@ DUMPDIR: Dump the contents of current directory to string   @@ → S   VARS 1   DO     GETI DUP RCL →STR     { #Ah } →UTF8 +     SWAP →STR " STO" +     { #Ah #Ah } →UTF8 +     + UNROT   UNTIL     DUP 1 ==   END   SWAP SIZE 1 -   START     +   NEXT   RTAIL »``` RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-22-2019 02:00 AM (05-20-2019 09:26 PM)Gilles Wrote:  PM sended. I started to adapt a subset of David Mutter's ListExt library and GoferList to newRPL. It's very fast and efficient. On the other hand I noticed that the structure DIR ... END is not supported in newRPL. Claudio, will it be in the future? It would give more readable sources than having to do "STO" for each program. Yes, directories aren't objects, more like dictionaries so they live outside of the RPL realm. I didn't implement that syntax because I had something better in mind, more like RPL libraries than directories, the idea is a generic container of named objects that could be installed as a system-wide library, extracted to a directory or even to a local var environment without exploding the object. Anyway, it's not yet implemented so for now you have to use lists, but perhaps it's time to discuss the final details of that format. By the way, there's a couple of new commands in newRPL that I added, inspired by David's library that will help in the implementation of some of his commands. RE: newRPL - build 1089 released! [update:build 1158] - The Shadow - 05-22-2019 04:42 AM (05-22-2019 02:00 AM)Claudio L. Wrote:  By the way, there's a couple of new commands in newRPL that I added, inspired by David's library that will help in the implementation of some of his commands. So what are they? List commands are near and dear to my heart. RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-22-2019 08:37 AM (05-22-2019 04:42 AM)The Shadow Wrote:   (05-22-2019 02:00 AM)Claudio L. Wrote:  By the way, there's a couple of new commands in newRPL that I added, inspired by David's library that will help in the implementation of some of his commands. So what are they? List commands are near and dear to my heart. Claudio, talking about lists, I've seen you have implemented support for case lists. If I'm not mistaken, at the moment they behave as normal lists: do they have some special propriety you are planning to add? RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-23-2019 02:44 AM (05-22-2019 08:37 AM)JoJo1973 Wrote:   (05-22-2019 04:42 AM)The Shadow Wrote:  So what are they? List commands are near and dear to my heart. Claudio, talking about lists, I've seen you have implemented support for case lists. If I'm not mistaken, at the moment they behave as normal lists: do they have some special propriety you are planning to add? I just realized the module that has commands for composite objects is completely missing from the wiki (another thing to fix...), no wonder you are asking what they are. It's just a few I found useful, like RHEAD gives you the head of the reverse list (last element). I'll add that module to the wiki so they show up. As far as case lists: they are not the same as regular lists. A case list is assumed to have multiple values of the same variable, so operations between them are not the same as regular lists. For example { A B } { C D } * would normally multiply element by element { A*C B*D }. With case lists, something that could be A or B multiplied by something that could be C or D creates 4 different possible outcomes: {A*C B*C A*D B*D }. This is mainly used internally to evaluate expressions with variables that could have multiple values. Just assign each variable a case list of all possible values and EVAL will return a list of all possible outcomes of the expression. RE: newRPL - build 1089 released! [update:build 1158] - JoJo1973 - 05-23-2019 09:57 AM Very interesting... Evaluating Code: ``` 'c{ -1,1 }*X+c{ -1,1 }*Y'``` results in Code: ``` c{ '-X-Y' '-X+Y' 'X-Y' 'X+Y' }``` RE: newRPL - build 1089 released! [update:build 1158] - Claudio L. - 05-23-2019 02:06 PM (05-23-2019 09:57 AM)JoJo1973 Wrote:  Very interesting... Evaluating Code: ``` 'c{ -1,1 }*X+c{ -1,1 }*Y'``` results in Code: ``` c{ '-X-Y' '-X+Y' 'X-Y' 'X+Y' }``` If you like that... you'll like the ALLROOTS command. Try '√4' ALLROOTS and you'll see that it applies a group of rules that will replace any square root or power with exponent in the 1/n form with a case list using the command XROOT (which only returns the principal root) or the actual principal root magnitude if it's numerically exact, multiplied by a case list with all the complex angles needed to return exact values for all roots. I think the command is still incomplete, it doesn't cover all cases but it's easy to add rules as needed since it's a plain RPL source file (here is an area where I can get help from math-minded people like yourself).