calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

README.md (7406B)


      1 # `calc_rational`
      2 
      3 `calc_rational` consists of a binary crate `calc` and a library crate
      4 [`calc_lib`](https://docs.rs/calc_rational/latest/calc_lib). `calc` is a CLI calculator for basic
      5 rational number arithmetic using standard operator precedence and associativity. Internally, it is
      6 based on [`Ratio<T>`](https://docs.rs/num/latest/num/rational/struct.Ratio.html)
      7 and [`BigInt`](https://docs.rs/num-bigint/latest/num_bigint/struct.BigInt.html).
      8 
      9 ## Calc in action
     10 
     11 ```bash
     12 [zack@laptop ~]$ calc
     13 2.71828^0^3.14159 + -1!
     14 > 0
     15 s
     16 > 0
     17 @^0
     18 > 1
     19 s
     20 > 1
     21 @/3 * 3
     22 > 1
     23 s
     24 > 1
     25 |@2 - 9|^(1 - 2*3)
     26 > 1/32768
     27 s
     28 > 1/32768
     29 
     30 > 0.000030517578125
     31 round(@, 3)
     32 > 0
     33 round(@, 6)
     34 > 31/1000000
     35 
     36 > 0.000031
     37 2/3
     38 > 2/3
     39 
     40 > 0.666666667
     41 rand()
     42 > 939435294927814822
     43 rand(1+9,10!)
     44 > 2660936
     45 1+4 mod 2 + 1
     46 > 2
     47 -5 mod 2
     48 > 1
     49 -5 mod -2
     50 > 1
     51 5 mod -2
     52 > 1
     53 9^0.5
     54 > 3
     55 (4/9)^(-1/2)
     56 > 3/2
     57 q
     58 [zack@laptop ~]$
     59 ```
     60 
     61 ## Expressions
     62 
     63 The following are the list of expressions in descending order of precedence:
     64   1. number literals, `@`, `()`, `||`, `round()`, `rand()`
     65   2. `!`
     66   3. `^`
     67   4. `-` (unary negation operator)
     68   5. `*`, `/`, `mod`
     69   6. `+`, `-`
     70 
     71 All binary operators are left-associative sans `^` which is right-associative.
     72 
     73 Any expression is allowed to be enclosed in `()`. Note that parentheses are purely for grouping expressions;
     74 in particular, you cannot use them to represent multiplication (e.g., `4(2)` is grammatically incorrect and
     75 will result in an error message).
     76 
     77 Any expression is allowed to be enclosed in `||`. This unary operator represents absolute value.
     78 
     79 `!` is the factorial operator. Due to its high precedence, something like *-i!^j!* for *i, j ∈ ℕ* is
     80 the same thing as *-((i!)^(j!))*. If the expression preceding it does not evaluate to a non-negative integer,
     81 then an error will be displayed. Spaces and tabs are *not* ignored; so `1 !` is grammatically incorrect and
     82 will result in an error message.
     83 
     84 `^` is the exponentiation operator. The expression left of the operator can evaluate to any rational number;
     85 however the expression right of the operator must evaluate to an integer or ±1/2 unless the expression on
     86 the left evaluates to `0` or `1`. In the event of the former, the expression right of the operator must evaluate
     87 to a non-negative rational number. In the event of the latter, the expression right of the operator can evaluate to
     88 any rational number. Note that `0^0` is defined to be 1. When the operand right of `^` evaluates to ±1/2, then
     89 the left operand must be the square of a rational number.
     90 
     91 The unary operator `-` represents negation.
     92 
     93 The operators `*` and `/` represent multiplication and division respectively. Expressions right of `/`
     94 must evaluate to any non-zero rational number; otherwise an error will be displayed.
     95 
     96 The binary operator `mod` represents modulo such that *n mod m = r = n - m\*q* for *n,q ∈ ℤ, m ∈ ℤ\\{0}, and r ∈ ℕ*
     97 where *r* is the minimum non-negative solution.
     98 
     99 The binary operators `+` and `-` represent addition and subtraction respectively.
    100 
    101 With the aforementioned exception of `!`, all spaces and tabs before and after operators are ignored.
    102 
    103 ## Round expression
    104 
    105 `round(expression, digit)` rounds `expression` to `digit`-number of fractional digits. An error will
    106 be displayed if called incorrectly.
    107 
    108 ## Rand expression
    109 
    110 `rand(expression, expression)` generates a random 64-bit integer inclusively between the passed expressions.
    111 An error will be displayed if called incorrectly. `rand()` generates a random 64-bit integer.
    112 
    113 ## Numbers
    114 
    115 A number literal is a non-empty sequence of digits or a non-empty sequence of digits immediately followed by `.`
    116 which is immediately followed by a non-empty sequence of digits (e.g., `134.901`). This means that number
    117 literals represent precisely all rational numbers that are equivalent to a ratio of a non-negative integer to
    118 a positive integer whose sole prime factors are 2 or 5. To represent all other rational numbers, the unary
    119 operator `-` and binary operator `/` must be used.
    120 
    121 ## Empty expression
    122 
    123 The empty expression (i.e., expression that at most only consists of spaces and tabs) will return
    124 the result from the previous non-(empty/store) expression in *decimal* form using the minimum number of digits.
    125 In the event an infinite number of digits is required, it will be rounded to 9 fractional digits using normal rounding
    126 rules first.
    127 
    128 ## Store expression
    129 
    130 To store the result of the previous non-(empty/store) expression, one simply passes `s`. In addition to storing the
    131 result which will subsequently be available via `@`, it displays the result. At most 8 results can be stored at once;
    132 at which point, results that are stored overwrite the oldest result.
    133 
    134 ## Recall expression
    135 
    136 `@` is used to recall previously stored results. It can be followed by any *digit* from `1` to `8`.
    137 If such a digit does not immediately follow it, then it will be interpreted as if there were a `1`.
    138 `@i` returns the *i*-th most-previous stored result where *i ∈ {1, 2, 3, 4, 5, 6, 7, 8}*.
    139 Note that spaces and tabs are *not* ignored so `@ 2` is grammatically incorrect and will result in an error message.
    140 As emphasized, it does not work on expressions; so both `@@` and `@(1)` are grammatically incorrect.
    141 
    142 ## Character encoding
    143 
    144 All inputs must only contain the ASCII encoding of the following Unicode scalar values: `0`-`9`, `.`, `+`, `-`,
    145 `*`, `/`, `^`, `!`, `mod`, `|`, `(`, `)`, `round`, `rand`, `,`, `@`, `s`, &lt;space&gt;, &lt;tab&gt;,
    146 &lt;line feed&gt;, &lt;carriage return&gt;, and `q`. Any other byte sequences are grammatically incorrect and will
    147 lead to an error message.
    148 
    149 ## Errors
    150 
    151 Errors due to a language violation (e.g., dividing by `0`) manifest into an error message. `panic!`s
    152 and [`io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)s caused by writing to the global
    153 standard output stream lead to program abortion. On OpenBSD-stable when compiled with the `priv_sep` feature,
    154 it will error if [`pledge(2)`](https://man.openbsd.org/amd64/pledge.2) errors with the promise of `"stdio"`.
    155 
    156 ## Exiting
    157 
    158 `q` with any number of spaces and tabs before and after or sending `EOF` will cause the program to terminate.
    159 
    160 ## License
    161 
    162 Licensed under either of
    163 
    164 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0).
    165 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT).
    166 
    167 at your option.
    168 
    169 ## Contribution
    170 
    171 Unless you explicitly state otherwise, any contribution intentionally submitted inclusion in the work by you, as
    172 defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
    173 
    174 ### Status
    175 
    176 This package will be actively maintained until it is deemed “feature complete”.
    177 There are really only two properties that will always be true. First,
    178 the grammar that generates a “reasonable” superset of the language will
    179 be an unambiguous context-free grammar with expression precedence and binary operator
    180 associativity embedded within. Last, the language will only deal with the field of
    181 rational numbers.
    182 
    183 The crate is only tested on `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but it should work
    184 on most platforms.
    185 
    186 #### Formal language specification
    187 
    188 For a more precise specification of the “calc language”, one can read the
    189 [calc language specification](https://git.philomathiclife.com/calc_rational/lang.pdf).